diff --git a/.vscode/settings.json b/.vscode/settings.json index c4a528b..9c95895 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,5 +11,6 @@ "color": "default" } ], - "VsCodeTaskButtons.showCounter": false + "VsCodeTaskButtons.showCounter": false, + "rust-analyzer.checkOnSave": true } diff --git a/Justfile b/Justfile new file mode 100644 index 0000000..be05212 --- /dev/null +++ b/Justfile @@ -0,0 +1,5 @@ +test: + RUST_BACKTRACE=1 godot --path godot res://tests/test_runner.tscn -- --quiet-run + +bench: + RUST_BACKTRACE=1 godot --path godot res://tests/test_runner.tscn -- --bench \ No newline at end of file diff --git a/README.md b/README.md index 693421e..bac81c6 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ # godottest messing around with godot and rust + +## run tests + +```sh +RUST_BACKTRACE=1 godot --path godot res://tests/test_runner.tscn -- --quiet-run +``` diff --git a/godot/Rust.gdextension b/godot/Rust.gdextension index c640e38..6a12633 100644 --- a/godot/Rust.gdextension +++ b/godot/Rust.gdextension @@ -1,6 +1,7 @@ [configuration] entry_symbol = "gdext_rust_init" compatibility_minimum = 4.1 +reloadable = true [libraries] "android.debug" = "res://../rust/target/debug/godottest_rs.so" @@ -65,6 +66,6 @@ compatibility_minimum = 4.1 "windows.editor.x86_64" = "res://../rust/target/x86_64-pc-windows-msvc/debug/godottest_rs.dll" [icons] -AsyncRuntime = "res://addons/rust/NodeRustFerris.svg" -Player = "res://addons/rust/NodeRustFerris.svg" Mappy = "res://addons/rust/NodeRustFerris.svg" +Player = "res://addons/rust/NodeRustFerris.svg" +AsyncRuntime = "res://addons/rust/NodeRustFerris.svg" diff --git a/godot/Rust.gdextension.uid b/godot/Rust.gdextension.uid index 92cc7f2..7b11879 100644 --- a/godot/Rust.gdextension.uid +++ b/godot/Rust.gdextension.uid @@ -1 +1 @@ -uid://dx7md3kauujl +uid://yljs7ohq1dqw diff --git a/godot/addons/panku_console/LICENSE b/godot/addons/panku_console/LICENSE new file mode 100644 index 0000000..d66c0a7 --- /dev/null +++ b/godot/addons/panku_console/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2023 Feo (k2kra) Wu + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/godot/addons/panku_console/README.md b/godot/addons/panku_console/README.md new file mode 100644 index 0000000..b986276 --- /dev/null +++ b/godot/addons/panku_console/README.md @@ -0,0 +1 @@ +This repository is a mirror that tracks the latest version of [PankuConsole](https://github.com/Ark2000/PankuConsole), so you can add it as a submodule in you addons folder. diff --git a/godot/addons/panku_console/common/buffered_rich_text.gd b/godot/addons/panku_console/common/buffered_rich_text.gd new file mode 100644 index 0000000..db67648 --- /dev/null +++ b/godot/addons/panku_console/common/buffered_rich_text.gd @@ -0,0 +1,35 @@ +extends VBoxContainer + +# it is like, an infinite scroll game. + +# specifically, the first buffer will be cleared and sent to the last +# when the last buffer is full. + +# with buffers, we can constanly output lots of fancy stuff while keeping a smooth experience. + +const BUFFER_MAX_PARAGRAPHS = 64 +const BUFFERS = 4 + +var cur_label_idx:int = 0 + +func add_text(text:String): + var cur_label:RichTextLabel = get_child(cur_label_idx) + cur_label.text += text + if cur_label.get_paragraph_count() > BUFFER_MAX_PARAGRAPHS: + cur_label_idx += 1 + if cur_label_idx == BUFFERS: + cur_label_idx = BUFFERS - 1 + var first_label:RichTextLabel = get_child(0) + first_label.text = "" + move_child(first_label, BUFFERS - 1) + +func _ready(): + set("theme_override_constants/separation", 0) + for child in get_children(): + child.queue_free() + for i in range(BUFFERS): + var new_buffer:RichTextLabel = RichTextLabel.new() + new_buffer.fit_content = true + new_buffer.bbcode_enabled = true + new_buffer.selection_enabled = true + add_child(new_buffer) diff --git a/godot/addons/panku_console/common/buffered_rich_text.gd.uid b/godot/addons/panku_console/common/buffered_rich_text.gd.uid new file mode 100644 index 0000000..b03aadc --- /dev/null +++ b/godot/addons/panku_console/common/buffered_rich_text.gd.uid @@ -0,0 +1 @@ +uid://hxsdaekjx5k0 diff --git a/godot/addons/panku_console/common/config.gd b/godot/addons/panku_console/common/config.gd new file mode 100644 index 0000000..ca85283 --- /dev/null +++ b/godot/addons/panku_console/common/config.gd @@ -0,0 +1,126 @@ +class_name PankuConfig + +const CONFIG_SECTION = "panku" +const OPTIONS = { + # See https://github.com/Ark2000/PankuConsole/issues/170 + DISABLE_ON_RELEASE = 'disable_on_release', + # See https://github.com/Ark2000/PankuConsole/issues/173 + CUSTOM_DEFAULT_CONFIG = 'custom_default_config', +} + +const INITIAL_DEFAULT_CONFIG_FILE_PATH = "res://addons/panku_console/default_panku_config.cfg" +const USER_CONFIG_FILE_PATH = "user://panku_config.cfg" + + +# Full option name in project settings. +static func panku_option(option: String) -> String: + return CONFIG_SECTION + "/" + option + + +# A helper function to add custom project settings +# See https://dfaction.net/handling-custom-project-settings-using-gdscript/ +static func add_custom_project_setting( + name: String, + default_value, + type: int, + hint: int = PROPERTY_HINT_NONE, hint_string: String = "" + ) -> void: + if ProjectSettings.has_setting(name): return + + var setting_info: Dictionary = { + "name": name, + "type": type, + "hint": hint, + "hint_string": hint_string + } + + ProjectSettings.set_setting(name, default_value) + ProjectSettings.add_property_info(setting_info) + ProjectSettings.set_initial_value(name, default_value) + ProjectSettings.set_as_basic(name, true) + + +static func init_all_project_settings() -> void: + # Seems we can't add descriptions to custom settings now. + + # Disable Panku Console in release builds + add_custom_project_setting( + panku_option(OPTIONS.DISABLE_ON_RELEASE), + false, + TYPE_BOOL + ) + + # Path to the custom + # `res://` path default config file, useful if you are going to keep panku console in release builds. + add_custom_project_setting( + panku_option(OPTIONS.CUSTOM_DEFAULT_CONFIG), + INITIAL_DEFAULT_CONFIG_FILE_PATH, + TYPE_STRING, + PROPERTY_HINT_FILE, + "*.cfg" + ) + + # save_project_settings() + + +static func clear_all_project_settings() -> void: + for option in OPTIONS.values(): + var opt: String = panku_option(option) + if ProjectSettings.has_setting(opt): + ProjectSettings.clear(opt) + + save_project_settings() + + +static func save_project_settings() -> void: + var error: int = ProjectSettings.save() + if error != OK: + push_error("Encountered error %d when saving project settings." % error) + + +# Get custom config file path from project settings +static func get_custom_default_config_path() -> String: + return ProjectSettings.get_setting(panku_option(OPTIONS.CUSTOM_DEFAULT_CONFIG), INITIAL_DEFAULT_CONFIG_FILE_PATH) + +# Check if custom config file from project settings exist +static func is_custom_default_config_exists() -> bool: + return FileAccess.file_exists(get_custom_default_config_path()) + + +# load config from file, always return a dictionary +static func _get_config(file_path:String) -> Dictionary: + if FileAccess.file_exists(file_path): + var file = FileAccess.open(file_path, FileAccess.READ) + var content := file.get_as_text() + var config:Dictionary = str_to_var(content) + if config: return config + return {} + + +# save user config to file +static func set_config(config:Dictionary): + var file = FileAccess.open(USER_CONFIG_FILE_PATH, FileAccess.WRITE) + var content = var_to_str(config) + file.store_string(content) + + +# get config, if user config exists, return user config, otherwise return default config configured by plugin user +static func get_config() -> Dictionary: + var user_config:Dictionary = _get_config(USER_CONFIG_FILE_PATH) + if not user_config.is_empty(): + return user_config + # if no user config, return default config, which is read-only + if is_custom_default_config_exists(): + return _get_config(get_custom_default_config_path()) + + return _get_config(INITIAL_DEFAULT_CONFIG_FILE_PATH) + + +static func get_value(key:String, default:Variant) -> Variant: + return get_config().get(key, default) + + +static func set_value(key:String, val:Variant) -> void: + var config = _get_config(USER_CONFIG_FILE_PATH) + config[key] = val + set_config(config) diff --git a/godot/addons/panku_console/common/config.gd.uid b/godot/addons/panku_console/common/config.gd.uid new file mode 100644 index 0000000..9038732 --- /dev/null +++ b/godot/addons/panku_console/common/config.gd.uid @@ -0,0 +1 @@ +uid://bd0ob776pkvry diff --git a/godot/addons/panku_console/common/gdexprenv.gd b/godot/addons/panku_console/common/gdexprenv.gd new file mode 100644 index 0000000..61d03cd --- /dev/null +++ b/godot/addons/panku_console/common/gdexprenv.gd @@ -0,0 +1,276 @@ +class_name PankuGDExprEnv + +const type_names = { + TYPE_NIL: "null", + TYPE_BOOL: "bool", + TYPE_INT: "int", + TYPE_FLOAT: "float", + TYPE_STRING: "String", + TYPE_VECTOR2: "Vector2", + TYPE_VECTOR2I: "Vector2i", + TYPE_RECT2: "Rect2", + TYPE_RECT2I: "Rect2i", + TYPE_VECTOR3: "Vector3", + TYPE_VECTOR3I: "Vector3i", + TYPE_TRANSFORM2D: "Transform2D", + TYPE_VECTOR4: "Vector4", + TYPE_VECTOR4I: "Vector4i", + TYPE_PLANE: "Plane", + TYPE_QUATERNION: "Quaternion", + TYPE_AABB: "AABB", + TYPE_BASIS: "Basis", + TYPE_TRANSFORM3D: "Transform3D", + TYPE_PROJECTION: "Projection", + TYPE_COLOR: "Color", + TYPE_STRING_NAME: "StringName", + TYPE_NODE_PATH: "NodePath", + TYPE_RID: "RID", + TYPE_OBJECT: "Object", + TYPE_CALLABLE: "Callable", + TYPE_SIGNAL: "Signal", + TYPE_DICTIONARY: "Dictionary", + TYPE_ARRAY: "Array", + TYPE_PACKED_BYTE_ARRAY: "PackedByteArray", + TYPE_PACKED_INT32_ARRAY: "PackedInt32Array", + TYPE_PACKED_INT64_ARRAY: "PackedInt64Array", + TYPE_PACKED_FLOAT32_ARRAY: "PackedFloat32Array", + TYPE_PACKED_FLOAT64_ARRAY: "PackedFloat64Array", + TYPE_PACKED_STRING_ARRAY: "PackedStringArray", + TYPE_PACKED_VECTOR2_ARRAY: "PackedVector2Array", + TYPE_PACKED_VECTOR3_ARRAY: "PackedVector3Array", + TYPE_PACKED_COLOR_ARRAY: "PackedColorArray", +} + +var _envs = {} +var _envs_info = {} +var _expression = Expression.new() +var _base_instance:Object + +func set_base_instance(base_instance:Object): + _base_instance = base_instance + #add info of base instance + var env_info = extract_info_from_script(_base_instance.get_script()) + for k in env_info: _envs_info[k] = env_info[k] + +func get_base_instance(): + return _base_instance + +## Register an environment that run expressions. +## [br][code]env_name[/code]: the name of the environment +## [br][code]env[/code]: The base instance that runs the expressions. For exmaple your player node. +func register_env(env_name:String, env:Object): + _envs[env_name] = env +# output("[color=green][Info][/color] [b]%s[/b] env loaded!"%env_name) + if env is Node: + env.tree_exiting.connect( + func(): remove_env(env_name) + ) + if env.get_script(): + var env_info = extract_info_from_script(env.get_script()) + for k in env_info: + var keyword = "%s.%s" % [env_name, k] + _envs_info[keyword] = env_info[k] + +## Return the environment object or [code]null[/code] by its name. +func get_env(env_name:String) -> Node: + return _envs.get(env_name) + +## Remove the environment named [code]env_name[/code] +func remove_env(env_name:String): + if _envs.has(env_name): + _envs.erase(env_name) + for k in _envs_info.keys(): + if k.begins_with(env_name + "."): + _envs_info.erase(k) + +#Execute an expression in a preset environment. +func execute(exp:String) -> Dictionary: + return execute_exp(exp, _expression, _base_instance, _envs) + +# TODO: not used +func get_available_export_objs() -> Array: + var result = [] + for obj_name in _envs: + var obj = _envs[obj_name] + if !obj.get_script(): + continue + var export_properties = get_export_properties_from_script(obj.get_script()) + if export_properties.is_empty(): + continue + result.push_back(obj_name) + return result + +func get_help_info(k:String) -> String: + return _envs_info[k]["help"] + +#TODO: refactor all those mess +func parse_exp(exp:String, allow_empty:=false): + var result:Array + var empty_flag = allow_empty and exp.is_empty() + + if empty_flag: + result = _envs_info.keys() + else: + result = search_and_sort_and_highlight(exp, _envs_info.keys()) + + var hints_bbcode = [] + var hints_value = [] + + for r in result: + var keyword:String + var bbcode_main:String + + if empty_flag: + keyword = r + bbcode_main = r + else: + keyword = r["keyword"] + bbcode_main = r["bbcode"] + + var bbcode_postfix = _envs_info[keyword]["bbcode_postfix"] + var keyword_type = _envs_info[keyword]["type"] + hints_value.push_back(keyword) + hints_bbcode.push_back(bbcode_main + bbcode_postfix) + return { + "hints_bbcode": hints_bbcode, + "hints_value": hints_value + } + +static func search_and_sort_and_highlight(s:String, li:Array): + s = s.lstrip(" ").rstrip(" ") + var matched = [] + if s == "": return matched + for k in li: + var start = k.find(s) + if start >= 0: + var similarity = 1.0 * s.length() / k.length() + matched.append({ + "keyword": k, + "similarity": similarity, + "start": start, + "bbcode": "" + }) + + matched.sort_custom( + func(k1, k2): + if k1["start"] != k2["start"]: + return k1["start"] > k2["start"] + else: + return k1["similarity"] < k2["similarity"] + ) + + var line_format = "%s[color=green][b]%s[/b][/color]%s" + + for m in matched: + var p = ["", "", ""] + if m["start"] < 0: + p[0] = m["keyword"] + else: + p[0] = m["keyword"].substr(0, m["start"]) + p[1] = s + p[2] = m["keyword"].substr(m["start"] + s.length(), -1) + + m["bbcode"] = line_format % p + + return matched + +static func extract_info_from_script(script:Script): + var result = {} + + var methods = [] + var properties = [] + var constants = [] + var constants_bbcode_postfix = {} + + for m in script.get_script_method_list(): + if m["name"] != "" and m["name"].is_valid_identifier() and !m["name"].begins_with("_"): + var args = [] + for a in m["args"]: + args.push_back("[color=cyan]%s[/color][color=gray]:[/color][color=orange]%s[/color]"%[a["name"], type_names[a["type"]]]) + result[m["name"]] = { + "type": "method", + "bbcode_postfix": "(%s)"%("[color=gray], [/color]".join(PackedStringArray(args))) + } + for p in script.get_script_property_list(): + if p["name"] != "" and !p["name"].begins_with("_") and p["name"].is_valid_identifier(): + result[p["name"]] = { + "type": "property", + "bbcode_postfix":"[color=gray]:[/color][color=orange]%s[/color]"%type_names[p["type"]] + } + + var constant_map = script.get_script_constant_map() + var help_info = {} + for c in constant_map: + if !c.begins_with("_"): + result[c] = { + "type": "constant", + "bbcode_postfix":"[color=gray]:[/color][color=orange]%s[/color]"%type_names[typeof(constant_map[c])] + } + elif c.begins_with("_HELP_") and c.length() > 6 and typeof(constant_map[c]) == TYPE_STRING: + var key = c.lstrip("_HELP_") + help_info[key] = constant_map[c] + + for k in result: + if help_info.has(k): + result[k]["help"] = help_info[k] + else: + result[k]["help"] = "No help information provided." + + #keyword -> {type, bbcode_postfix, help} + return result + +static func execute_exp(exp_str:String, expression:Expression, base_instance:Object, env:Dictionary): + var failed := false + var result = null + + var error = expression.parse(exp_str, env.keys()) + if error != OK: + failed = true + result = expression.get_error_text() + else: + result = expression.execute(env.values(), base_instance, true) + if expression.has_execute_failed(): + failed = true + result = expression.get_error_text() + + return { + "failed": failed, + "result": result + } + +static func get_export_properties_from_script(script:Script): + var result = [] + var data = script.get_script_property_list() + for d in data: + if !(d.usage == PROPERTY_USAGE_SCRIPT_VARIABLE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE): + continue + result.append(d) + return result + +static func generate_help_text_from_script(script:Script): + var result = ["[color=cyan][b]User script defined identifiers[/b][/color]: "] + var env_info = extract_info_from_script(script) + var keys = env_info.keys() + keys.sort() + for k in keys: + result.push_back("%s - [i]%s[/i]"%[k + env_info[k]["bbcode_postfix"], env_info[k]["help"]]) + return "\n".join(PackedStringArray(result)) + +#returns a string containing all public script properties of an object +#please BE AWARE when using this function on an object with custom getters. +static func get_object_outline(obj:Object) -> String: + var result := PackedStringArray() + if obj == null: return "null" + var script = obj.get_script() + if script == null: + return "this object has no script attached." + var properties = script.get_script_property_list() + for p in properties: + if p.usage & PROPERTY_USAGE_SCRIPT_VARIABLE == 0: + continue + if p.name.begins_with("_"): + continue + result.append("%s: %s" % [p.name, str(obj.get(p.name))]) + if result.is_empty(): + return "this object has no public script variables." + return "\n".join(result) diff --git a/godot/addons/panku_console/common/gdexprenv.gd.uid b/godot/addons/panku_console/common/gdexprenv.gd.uid new file mode 100644 index 0000000..650c321 --- /dev/null +++ b/godot/addons/panku_console/common/gdexprenv.gd.uid @@ -0,0 +1 @@ +uid://xnce2n76k5p6 diff --git a/godot/addons/panku_console/common/lynx_window2/border.gd b/godot/addons/panku_console/common/lynx_window2/border.gd new file mode 100644 index 0000000..53b25d6 --- /dev/null +++ b/godot/addons/panku_console/common/lynx_window2/border.gd @@ -0,0 +1,9 @@ +extends Panel + +func hey_i_am_here(): + modulate.a = 0.0 + var t = create_tween() + t.set_speed_scale(1.0 / Engine.time_scale) + for i in range(2): + t.tween_property(self, "modulate:a", 0.3, 0.1) + t.tween_property(self, "modulate:a", 0.0, 0.1) diff --git a/godot/addons/panku_console/common/lynx_window2/border.gd.uid b/godot/addons/panku_console/common/lynx_window2/border.gd.uid new file mode 100644 index 0000000..b353266 --- /dev/null +++ b/godot/addons/panku_console/common/lynx_window2/border.gd.uid @@ -0,0 +1 @@ +uid://b2oil1la5ccpf diff --git a/godot/addons/panku_console/common/lynx_window2/lynx_window_2.gd b/godot/addons/panku_console/common/lynx_window2/lynx_window_2.gd new file mode 100644 index 0000000..1933b0c --- /dev/null +++ b/godot/addons/panku_console/common/lynx_window2/lynx_window_2.gd @@ -0,0 +1,298 @@ +class_name PankuLynxWindow extends ColorRect + +#Do not connect the button node directly, use these signals to detect click event. +signal title_btn_clicked +signal window_closed + +const lynx_window_shader_material:ShaderMaterial = preload("./lynx_window_shader_material.tres") +const OS_WINDOW_MARKER = "PankuOSWindow" + +@export var _window_title_container:HBoxContainer +@export var _title_btn:PankuButton +@export var _close_btn:PankuButton +@export var _options_btn:PankuButton +@export var _resize_btn:Button +@export var _shadow_focus:Panel +@export var _shadow:NinePatchRect +@export var _container:Panel +@export var _pop_btn:PankuButton + +@export var no_resize := false +@export var no_resize_x := false +@export var no_resize_y := false +@export var no_move := false +@export var no_snap := false + +@export var no_title := false: + set(v): + no_title = v + _window_title_container.visible = !v + +@export var queue_free_on_close := true +@export var flicker := true + +var transform_interp_speed := 40.0 +var bounds_interp_speed := 50.0 +var anim_interp_speed := 10.0 + +var _is_dragging := false +var _drag_start_position:Vector2 +var _drag_start_position_global:Vector2 +var _is_resizing := false +var _resize_start_position:Vector2 +var _os_window:Window +var _content:Control +var _size_before_folded:Vector2 +var _folded:bool = false +var _size_animation:bool = false +var _target_size:Vector2 + +func add_options_button(callback:Callable): + _options_btn.show() + _options_btn.pressed.connect(callback) + +func get_layout_position(layout:Control.LayoutPreset) -> Vector2: + var window_rect = get_rect() + var screen_rect = get_viewport_rect() + var new_position = Vector2.ZERO + var end_position = screen_rect.size - window_rect.size + var center_position = end_position / 2 + if layout == PRESET_TOP_LEFT: + pass + elif layout == PRESET_CENTER_TOP: + new_position.x = center_position.x + elif layout == PRESET_TOP_RIGHT: + new_position.x = end_position.x + elif layout == PRESET_CENTER_LEFT: + new_position.y = center_position.y + elif layout == PRESET_CENTER: + new_position = center_position + elif layout == PRESET_CENTER_RIGHT: + new_position.x = end_position.x + new_position.y = center_position.y + elif layout == PRESET_BOTTOM_LEFT: + new_position.y = end_position.y + elif layout == PRESET_CENTER_BOTTOM: + new_position.x = center_position.x + new_position.y = end_position.y + elif layout == PRESET_BOTTOM_RIGHT: + new_position = end_position + return new_position + +func get_content(): + return _content + +func set_content(node:Control): + _content = node + if _os_window and _os_window.visible: + if _os_window.get_child_count() > 0: + push_error("Error: error in set_content") + return + _os_window.add_child(node) + return + if _container.get_child_count() > 0: + push_error("Error: error in set_content.") + return + _container.add_child(node) + +func highlight(v:bool): + _shadow_focus.visible = v + +func _init_os_window(): + _os_window = Window.new() + _os_window.set_meta(OS_WINDOW_MARKER, true) + var color_rect = ColorRect.new() + color_rect.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) + _os_window.add_child(color_rect) + get_tree().root.add_child(_os_window) + #destructor + tree_exiting.connect( + func(): + _os_window.queue_free() + ) + #switch back to embed window when os window close requested + _os_window.close_requested.connect( + func(): + _os_window.remove_child(_content) + _os_window.hide() + set_content(_content) + show() + ) + if get_parent().has_method("get_os_window_bg_color"): + color_rect.color = get_parent().get_os_window_bg_color() + +func switch_to_os_window(): + if _content == null: + push_error("Error: No content. ") + return + if _os_window == null: + _init_os_window() + _container.remove_child(_content) + _os_window.add_child(_content) + _os_window.size = size + _os_window.title = _title_btn.text + _os_window.position = Vector2(DisplayServer.window_get_position(0)) + position + _content.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) + _os_window.show() + hide() + +func show_window(): + if _os_window and _os_window.visible: + return + show() + move_to_front() + modulate.a = 0.0 + create_tween().tween_property(self, "modulate:a", 1.0, 0.2) + +func hide_window(): + if _os_window and _os_window.visible: + _os_window.close_requested.emit() + hide() + +func toggle_window_visibility(): + if _os_window.visible or visible: + hide_window() + else: + show_window() + +func set_window_visibility(b:bool): + if b: show_window() + else: hide_window() + +func get_window_visibility() -> bool: + return visible or _os_window.visible + +func set_window_title_text(text:String): + if _os_window and _os_window.visible: + _os_window.title = text + else: + _title_btn.text = " " + text + +func get_normal_window_size(): + if _folded: return _size_before_folded + return size + +func get_title_bar_height(): + return _window_title_container.size.y + +func _ready(): + custom_minimum_size = _window_title_container.get_minimum_size() + + _options_btn.visible = false + + _title_btn.button_down.connect( + func(): + _is_dragging = true + _drag_start_position = get_local_mouse_position() + _drag_start_position_global = get_global_mouse_position() + ) + _title_btn.button_up.connect( + func(): + _is_dragging = false + ) + _resize_btn.button_down.connect( + func(): + _is_resizing = true + _resize_start_position = _resize_btn.get_local_mouse_position() + ) + _resize_btn.button_up.connect( + func(): + _is_resizing = false + ) + _close_btn.pressed.connect( + func(): + window_closed.emit() + if queue_free_on_close: + queue_free() + else: + hide() + ) + + _title_btn.button.gui_input.connect( + func(e): + if e is InputEventMouseButton and !e.pressed: + if e.button_index != MOUSE_BUTTON_NONE: + if (get_global_mouse_position() - _drag_start_position_global).length_squared() < 4: + title_btn_clicked.emit() + ) + visibility_changed.connect( + func(): + if is_visible_in_tree() and flicker: + $Border.hey_i_am_here() + ) + + if flicker: + $Border.hey_i_am_here() + + _pop_btn.pressed.connect(switch_to_os_window) + + if _container.get_child_count() > 0: + _content = _container.get_child(0) + + if get_parent().has_method("get_enable_os_popup_btns"): + _pop_btn.visible = get_parent().get_enable_os_popup_btns() + + # feature: foldable window + title_btn_clicked.connect( + func(): + if _folded: + _target_size = _size_before_folded + else: + if !_size_animation: + _size_before_folded = size + _target_size = _window_title_container.size + _size_animation = true + _folded = !_folded + _resize_btn.visible = !_folded + ) + +func _input(e): + #release focus when you click outside of the window + if is_visible: + if e is InputEventMouseButton and e.pressed: + if !get_global_rect().has_point(get_global_mouse_position()): + var f = get_viewport().gui_get_focus_owner() + if f and is_ancestor_of(f): + f.release_focus() + if e is InputEventKey and e.keycode == KEY_ESCAPE and e.pressed and get_global_rect().has_point(get_global_mouse_position()): + window_closed.emit() + if queue_free_on_close: + queue_free() + else: + hide() + +func _process(delta: float) -> void: + if !no_move and _is_dragging: + var tp := position + get_local_mouse_position() - _drag_start_position + position = PankuUtils.interp(position, tp, transform_interp_speed, delta) + elif !no_resize and _is_resizing: + var ts := size + _resize_btn.get_local_mouse_position() - _resize_start_position + ts.x = min(ts.x, get_viewport_rect().size.x) + ts.y = min(ts.y, get_viewport_rect().size.y) + if !no_resize_x: + size.x = PankuUtils.interp(size.x, ts.x, transform_interp_speed, delta) + if !no_resize_y: + size.y = PankuUtils.interp(size.y, ts.y, transform_interp_speed, delta) + elif !no_snap: + var window_rect := get_rect() + var screen_rect := get_viewport_rect() + var target_position := window_rect.position + var target_size := window_rect.size.clamp(Vector2.ZERO, screen_rect.size) + if window_rect.position.y < 0: + target_position.y = 0 + if window_rect.end.y > screen_rect.end.y: + target_position.y = screen_rect.end.y - window_rect.size.y + if window_rect.end.y > screen_rect.end.y + window_rect.size.y / 2: + target_position.y = screen_rect.end.y - get_title_bar_height() + if window_rect.position.x < 0: + target_position.x = 0 + if window_rect.end.x > screen_rect.end.x: + target_position.x = screen_rect.end.x - window_rect.size.x + var current_position = window_rect.position + current_position = PankuUtils.interp(current_position, target_position, bounds_interp_speed, delta) + size = PankuUtils.interp(size, target_size, bounds_interp_speed, delta) + position = current_position + if _size_animation: + if _target_size.is_equal_approx(size): + _size_animation = false + size = PankuUtils.interp(size, _target_size, anim_interp_speed, delta) diff --git a/godot/addons/panku_console/common/lynx_window2/lynx_window_2.gd.uid b/godot/addons/panku_console/common/lynx_window2/lynx_window_2.gd.uid new file mode 100644 index 0000000..cdf383a --- /dev/null +++ b/godot/addons/panku_console/common/lynx_window2/lynx_window_2.gd.uid @@ -0,0 +1 @@ +uid://buw6hpyf4b2an diff --git a/godot/addons/panku_console/common/lynx_window2/lynx_window_2.tscn b/godot/addons/panku_console/common/lynx_window2/lynx_window_2.tscn new file mode 100644 index 0000000..56a65ac --- /dev/null +++ b/godot/addons/panku_console/common/lynx_window2/lynx_window_2.tscn @@ -0,0 +1,204 @@ +[gd_scene load_steps=19 format=3 uid="uid://s88loppa6gja"] + +[ext_resource type="Material" uid="uid://dyipeqsa8lcpc" path="res://addons/panku_console/common/lynx_window2/lynx_window_shader_material.tres" id="1_tvp6i"] +[ext_resource type="Script" path="res://addons/panku_console/common/lynx_window2/lynx_window_2.gd" id="2_1ul5o"] +[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="2_3fhqk"] +[ext_resource type="Texture2D" uid="uid://dosm26riekruh" path="res://addons/panku_console/res/icons2/menu.svg" id="4_4dlyn"] +[ext_resource type="PackedScene" uid="uid://drn5t13m088fb" path="res://addons/panku_console/common/panku_button.tscn" id="4_dnesi"] +[ext_resource type="Texture2D" uid="uid://gav3m4qtvgje" path="res://addons/panku_console/res/icons2/pop-out-svgrepo-com.svg" id="4_im81u"] +[ext_resource type="Texture2D" uid="uid://8g5afcuanbl6" path="res://addons/panku_console/res/icons2/close.svg" id="5_l4qpm"] +[ext_resource type="Texture2D" uid="uid://dvr12fl5prm78" path="res://addons/panku_console/res/effect/square_shadow.png" id="6_mfp1h"] +[ext_resource type="Texture2D" uid="uid://ciu5jiw4xmkq0" path="res://addons/panku_console/res/icons2/resize-svgrepo-com.svg" id="7_duwqn"] +[ext_resource type="Script" path="res://addons/panku_console/common/lynx_window2/border.gd" id="8_gj3ji"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_hv45g"] +draw_center = false +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color(1, 1, 1, 0.25098) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_6i67d"] +content_margin_left = 8.0 +content_margin_top = 8.0 +content_margin_right = 8.0 +content_margin_bottom = 8.0 +draw_center = false +border_width_left = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color(1, 1, 1, 0.25098) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_lct0k"] +draw_center = false +shadow_color = Color(0, 0, 0, 0.0627451) +shadow_size = 16 + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_p3y6j"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_r0x7y"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_p7tml"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_5muk4"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_uldta"] +draw_center = false +border_width_left = 4 +border_width_top = 4 +border_width_right = 4 +border_width_bottom = 4 +border_color = Color(1, 1, 1, 1) + +[node name="LynxWindow2" type="ColorRect" node_paths=PackedStringArray("_window_title_container", "_title_btn", "_close_btn", "_options_btn", "_resize_btn", "_shadow_focus", "_shadow", "_container", "_pop_btn")] +material = ExtResource("1_tvp6i") +offset_right = 413.0 +offset_bottom = 305.0 +theme = ExtResource("2_3fhqk") +script = ExtResource("2_1ul5o") +_window_title_container = NodePath("MainBody/VBoxContainer/Up") +_title_btn = NodePath("MainBody/VBoxContainer/Up/TitleButton") +_close_btn = NodePath("MainBody/VBoxContainer/Up/CloseButton") +_options_btn = NodePath("MainBody/VBoxContainer/Up/MenuButton") +_resize_btn = NodePath("Button") +_shadow_focus = NodePath("Shadow2") +_shadow = NodePath("Shadow") +_container = NodePath("MainBody/VBoxContainer/Down") +_pop_btn = NodePath("MainBody/VBoxContainer/Up/PopupButton") + +[node name="MainBody" type="Control" parent="."] +clip_contents = true +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="MainBody"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/separation = 0 + +[node name="Up" type="HBoxContainer" parent="MainBody/VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 0 + +[node name="TitleButton" parent="MainBody/VBoxContainer/Up" instance=ExtResource("4_dnesi")] +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_styles/panel = SubResource("StyleBoxFlat_hv45g") + +[node name="TextureRect" parent="MainBody/VBoxContainer/Up/TitleButton/HBoxContainer" index="0"] +texture = null + +[node name="Label" parent="MainBody/VBoxContainer/Up/TitleButton/HBoxContainer" index="1"] +text = "Window Title" + +[node name="PopupButton" parent="MainBody/VBoxContainer/Up" instance=ExtResource("4_dnesi")] +layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_hv45g") + +[node name="TextureRect" parent="MainBody/VBoxContainer/Up/PopupButton/HBoxContainer" index="0"] +texture = ExtResource("4_im81u") + +[node name="Label" parent="MainBody/VBoxContainer/Up/PopupButton/HBoxContainer" index="1"] +visible = false + +[node name="MenuButton" parent="MainBody/VBoxContainer/Up" instance=ExtResource("4_dnesi")] +layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_hv45g") + +[node name="TextureRect" parent="MainBody/VBoxContainer/Up/MenuButton/HBoxContainer" index="0"] +texture = ExtResource("4_4dlyn") + +[node name="Label" parent="MainBody/VBoxContainer/Up/MenuButton/HBoxContainer" index="1"] +visible = false + +[node name="CloseButton" parent="MainBody/VBoxContainer/Up" instance=ExtResource("4_dnesi")] +layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_hv45g") + +[node name="TextureRect" parent="MainBody/VBoxContainer/Up/CloseButton/HBoxContainer" index="0"] +texture = ExtResource("5_l4qpm") + +[node name="Label" parent="MainBody/VBoxContainer/Up/CloseButton/HBoxContainer" index="1"] +visible = false + +[node name="Down" type="Panel" parent="MainBody/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +theme_override_styles/panel = SubResource("StyleBoxFlat_6i67d") + +[node name="Shadow" type="NinePatchRect" parent="."] +modulate = Color(1, 1, 1, 0.501961) +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = -64.0 +offset_top = -79.0 +offset_right = 63.0 +offset_bottom = 47.0 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("6_mfp1h") +draw_center = false +region_rect = Rect2(0, 0, 512, 512) +patch_margin_left = 64 +patch_margin_top = 80 +patch_margin_right = 64 +patch_margin_bottom = 48 + +[node name="Shadow2" type="Panel" parent="."] +visible = false +layout_mode = 2 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_lct0k") + +[node name="Button" type="Button" parent="."] +self_modulate = Color(1, 1, 1, 0.501961) +layout_mode = 1 +anchors_preset = 3 +anchor_left = 1.0 +anchor_top = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = -12.0 +offset_top = -12.0 +grow_horizontal = 0 +grow_vertical = 0 +mouse_default_cursor_shape = 12 +theme_override_styles/focus = SubResource("StyleBoxEmpty_p3y6j") +theme_override_styles/hover = SubResource("StyleBoxEmpty_r0x7y") +theme_override_styles/pressed = SubResource("StyleBoxEmpty_p7tml") +theme_override_styles/normal = SubResource("StyleBoxEmpty_5muk4") +icon = ExtResource("7_duwqn") +flat = true +expand_icon = true + +[node name="Border" type="Panel" parent="."] +modulate = Color(1, 1, 1, 0) +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_uldta") +script = ExtResource("8_gj3ji") + +[editable path="MainBody/VBoxContainer/Up/TitleButton"] +[editable path="MainBody/VBoxContainer/Up/PopupButton"] +[editable path="MainBody/VBoxContainer/Up/MenuButton"] +[editable path="MainBody/VBoxContainer/Up/CloseButton"] diff --git a/godot/addons/panku_console/common/lynx_window2/lynx_window_shader_material.tres b/godot/addons/panku_console/common/lynx_window2/lynx_window_shader_material.tres new file mode 100644 index 0000000..1ed1018 --- /dev/null +++ b/godot/addons/panku_console/common/lynx_window2/lynx_window_shader_material.tres @@ -0,0 +1,8 @@ +[gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://dyipeqsa8lcpc"] + +[ext_resource type="Shader" path="res://addons/panku_console/res/shader/simple_fast_blur.gdshader" id="1_3h55m"] + +[resource] +shader = ExtResource("1_3h55m") +shader_parameter/lod = 4.0 +shader_parameter/modulate = Color(0, 0, 0, 0.12549) diff --git a/godot/addons/panku_console/common/lynx_window2/lynx_windows_manager_2.gd b/godot/addons/panku_console/common/lynx_window2/lynx_windows_manager_2.gd new file mode 100644 index 0000000..3298c43 --- /dev/null +++ b/godot/addons/panku_console/common/lynx_window2/lynx_windows_manager_2.gd @@ -0,0 +1,80 @@ +#A simple control node managing its child windows +class_name PankuLynxWindowsManager extends Control + +const CFG_ENABLE_OS_WINDOW = "enable_os_window" +const CFG_OS_WINDOW_BGCOLOR = "os_window_bg_color" + +@onready var console:PankuConsole = get_node(PankuConsole.SingletonPath) + +var os_popup_btn_enabled:bool +var os_window_bg_color:Color + +func _ready(): + load_data() + +func _input(e): + if e is InputEventMouseButton and e.pressed: + var flag = true + #traverse child windows in reverse order, use double shadow to highlight current active window. + for i in range(get_child_count() - 1, -1, -1): + var w:Control = get_child(i) + if w.visible and w.get_global_rect().has_point(get_global_mouse_position()): + var forefront = get_child(get_child_count() - 1) + if forefront.has_method("highlight"): forefront.highlight(false) + w.move_to_front() + forefront = get_child(get_child_count() - 1) + if forefront.has_method("highlight"): forefront.highlight(true) + flag = false + break + if flag and get_child_count() > 0: + var forefront = get_child(get_child_count() - 1) + if forefront.has_method("highlight"): forefront.highlight(false) + +func create_window(content:Control) -> PankuLynxWindow: + var new_window:PankuLynxWindow = preload("lynx_window_2.tscn").instantiate() + content.anchors_preset = Control.PRESET_FULL_RECT + new_window.set_content(content) + add_child(new_window) + new_window.show_window() + return new_window + +func enable_os_popup_btns(b:bool): + #note that this may affect your project + get_viewport().gui_embed_subwindows = !b + os_popup_btn_enabled = b + for w in get_children(): + #maybe there's a better way to get node type + if !w.has_method("switch_to_os_window"): + continue + w._pop_btn.visible = b + +func get_enable_os_popup_btns() -> bool: + return os_popup_btn_enabled + +func set_os_window_bg_color(c:Color): + os_window_bg_color = c + for w in get_children(): + #maybe there's a better way to get node type + if !w.has_method("switch_to_os_window"): + continue + if w._os_window != null: + w._os_window.get_child(0).color = c + +func get_os_window_bg_color() -> Color: + return os_window_bg_color + +func save_data(): + var cfg = PankuConfig.get_config() + cfg[CFG_ENABLE_OS_WINDOW] = os_popup_btn_enabled + cfg[CFG_OS_WINDOW_BGCOLOR] = os_window_bg_color + PankuConfig.set_config(cfg) + +func load_data(): + var cfg = PankuConfig.get_config() + enable_os_popup_btns(cfg.get(CFG_ENABLE_OS_WINDOW, false)) + set_os_window_bg_color(cfg.get(CFG_OS_WINDOW_BGCOLOR, Color("#2b2e32"))) + +func _notification(what): + #quit event + if what == NOTIFICATION_WM_CLOSE_REQUEST: + save_data() diff --git a/godot/addons/panku_console/common/lynx_window2/lynx_windows_manager_2.gd.uid b/godot/addons/panku_console/common/lynx_window2/lynx_windows_manager_2.gd.uid new file mode 100644 index 0000000..9830b20 --- /dev/null +++ b/godot/addons/panku_console/common/lynx_window2/lynx_windows_manager_2.gd.uid @@ -0,0 +1 @@ +uid://xjhlmbdx8fjf diff --git a/godot/addons/panku_console/common/module_manager.gd b/godot/addons/panku_console/common/module_manager.gd new file mode 100644 index 0000000..fbfe42e --- /dev/null +++ b/godot/addons/panku_console/common/module_manager.gd @@ -0,0 +1,54 @@ +class_name PankuModuleManager + +var _modules:Array[PankuModule] +var _modules_table:Dictionary +var _core:PankuConsole + +func init_manager(_core:PankuConsole, _modules:Array[PankuModule]): + self._modules = _modules + self._core = _core + load_modules() + +func load_modules(): + + # The extra tree structure is purely used for avoiding using RefCounted which may cause uncessary leaked instance warnings. + var manager_node:Node = Node.new() + manager_node.name = "_Modules_" + _core.add_child(manager_node) + + for _m in _modules: + var module:PankuModule = _m + _modules_table[module.get_module_name()] = module + + module.name = module.get_module_name() + manager_node.add_child(module) + + for _m in _modules: + var module:PankuModule = _m + module.core = _core + module._init_module() + #print("[info] %s module loaded!" % module.get_module_name()) + +func update_modules(delta:float): + for _m in _modules: + var module:PankuModule = _m + module.update_module(delta) + +func get_module(module_name:String): + return _modules_table[module_name] + +func has_module(module_name:String): + return _modules_table.has(module_name) + +func get_module_option_objects(): + var objects = [] + for _m in _modules: + var module:PankuModule = _m + if module._opt != null: + objects.append(module._opt) + return objects + +func quit_modules(): + for _m in _modules: + var module:PankuModule = _m + module.quit_module() diff --git a/godot/addons/panku_console/common/module_manager.gd.uid b/godot/addons/panku_console/common/module_manager.gd.uid new file mode 100644 index 0000000..bf46ffc --- /dev/null +++ b/godot/addons/panku_console/common/module_manager.gd.uid @@ -0,0 +1 @@ +uid://rkefpsd8kk4q diff --git a/godot/addons/panku_console/common/module_options.gd b/godot/addons/panku_console/common/module_options.gd new file mode 100644 index 0000000..1910cfd --- /dev/null +++ b/godot/addons/panku_console/common/module_options.gd @@ -0,0 +1,11 @@ +class_name ModuleOptions extends Resource + +var _module:PankuModule + +var _loaded := false + +#FIXME: Tricky part of saving data, needs to be reworked +func update_setting(key: String, value: Variant): + self.set(key, value) + if _loaded and _module: + _module.save_module_data(key, value) diff --git a/godot/addons/panku_console/common/module_options.gd.uid b/godot/addons/panku_console/common/module_options.gd.uid new file mode 100644 index 0000000..cf3b91a --- /dev/null +++ b/godot/addons/panku_console/common/module_options.gd.uid @@ -0,0 +1 @@ +uid://dhh5181ty0ng6 diff --git a/godot/addons/panku_console/common/panku_button.gd b/godot/addons/panku_console/common/panku_button.gd new file mode 100644 index 0000000..7414df6 --- /dev/null +++ b/godot/addons/panku_console/common/panku_button.gd @@ -0,0 +1,39 @@ +class_name PankuButton extends Control + +signal pressed +signal button_down +signal button_up + +@export +var button:Button + +@export +var trect:TextureRect + +@export +var label:Label + +var icon: + set(v): + trect.texture = v + get: + return trect.texture + +var text: + set(v): + label.text = v + get: + return label.text + +func _ready(): + + button.pressed.connect( + func(): + pressed.emit() + ) + button.button_down.connect( + func(): button_down.emit() + ) + button.button_up.connect( + func(): button_up.emit() + ) diff --git a/godot/addons/panku_console/common/panku_button.gd.uid b/godot/addons/panku_console/common/panku_button.gd.uid new file mode 100644 index 0000000..e04f6e0 --- /dev/null +++ b/godot/addons/panku_console/common/panku_button.gd.uid @@ -0,0 +1 @@ +uid://bdhu7gchsjvpf diff --git a/godot/addons/panku_console/common/panku_button.tscn b/godot/addons/panku_console/common/panku_button.tscn new file mode 100644 index 0000000..e404fdc --- /dev/null +++ b/godot/addons/panku_console/common/panku_button.tscn @@ -0,0 +1,42 @@ +[gd_scene load_steps=5 format=3 uid="uid://drn5t13m088fb"] + +[ext_resource type="Script" path="res://addons/panku_console/common/panku_button.gd" id="1_7kf5f"] +[ext_resource type="Texture2D" uid="uid://dchvk7qgfe37m" path="res://addons/panku_console/res/icons2/fold-svgrepo-com.svg" id="2_su653"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_v3kpx"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_cwnaw"] +content_margin_top = 4.0 +content_margin_bottom = 4.0 + +[node name="PankuButton" type="PanelContainer" node_paths=PackedStringArray("button", "trect", "label")] +editor_description = "Godot's Button can't handle scaling icons properly as descripted in https://github.com/godotengine/godot-proposals/issues/660, so I have to make a new one." +self_modulate = Color(1, 1, 1, 0) +offset_right = 112.0 +offset_bottom = 31.0 +mouse_filter = 2 +theme_override_styles/panel = SubResource("StyleBoxEmpty_v3kpx") +script = ExtResource("1_7kf5f") +button = NodePath("Button") +trect = NodePath("HBoxContainer/TextureRect") +label = NodePath("HBoxContainer/Label") + +[node name="Button" type="Button" parent="."] +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 +mouse_filter = 2 +theme_override_constants/separation = 0 + +[node name="TextureRect" type="TextureRect" parent="HBoxContainer"] +layout_mode = 2 +mouse_filter = 2 +texture = ExtResource("2_su653") +expand_mode = 2 + +[node name="Label" type="Label" parent="HBoxContainer"] +layout_mode = 2 +size_flags_vertical = 1 +theme_override_styles/normal = SubResource("StyleBoxEmpty_cwnaw") +vertical_alignment = 1 diff --git a/godot/addons/panku_console/common/panku_module.gd b/godot/addons/panku_console/common/panku_module.gd new file mode 100644 index 0000000..d30ee7c --- /dev/null +++ b/godot/addons/panku_console/common/panku_module.gd @@ -0,0 +1,101 @@ +class_name PankuModule extends Node +# extends Node: A hacky way to avoid cyclic RefCounted verbose warnings which is uncessary to worry about. + +var core:PankuConsole + +var _env:RefCounted = null +var _opt:ModuleOptions = null + +# dir name of the module +func get_module_name() -> String: + return get_script().resource_path.get_base_dir().get_file() + +# called when the module is loaded +func init_module(): + pass + +# called when the module is unloaded (quit program) +func quit_module(): + if _opt: + _opt._loaded = false + +# called at the start of each physics frame +func update_module(delta:float): + pass + +func save_module_data(key:String, value:Variant): + var cfg:Dictionary = PankuConfig.get_config() + var module_name:String = get_module_name() + if !cfg.has(module_name): + cfg[module_name] = {} + cfg[module_name][key] = value + PankuConfig.set_config(cfg) + +func load_module_data(key:String, default_value:Variant = null) -> Variant: + var cfg:Dictionary = PankuConfig.get_config() + var module_name:String = get_module_name() + var module_data = cfg.get(module_name, {}) + return module_data.get(key, default_value) + +func has_module_data(key:String) -> bool: + var cfg:Dictionary = PankuConfig.get_config() + var module_name:String = get_module_name() + var module_data = cfg.get(module_name, {}) + return module_data.has(key) + +func load_window_data(window:PankuLynxWindow): + window.position = load_module_data("window_position", window.get_layout_position([ + Control.PRESET_TOP_LEFT, + Control.PRESET_CENTER_TOP, + Control.PRESET_TOP_RIGHT, + Control.PRESET_CENTER_LEFT, + Control.PRESET_CENTER, + Control.PRESET_CENTER_RIGHT, + Control.PRESET_BOTTOM_LEFT, + Control.PRESET_CENTER_BOTTOM, + Control.PRESET_BOTTOM_RIGHT, + ][randi()%9])) + window.size = load_module_data("window_size", window.get_normal_window_size()) + window.set_window_visibility(load_module_data("window_visibility", false)) + +func save_window_data(window:PankuLynxWindow): + _save_window_geometry(window) + save_module_data("window_visibility", window.visible) + + +func _save_window_geometry(window:PankuLynxWindow): + save_module_data("window_position", window.position) + save_module_data("window_size", window.get_normal_window_size()) + + +# Add hook to window to auto save its geometry on close. +func add_auto_save_hook(window: PankuLynxWindow) -> void: + # Here some global settings check can be implemented, + # if we decide to make "save on close" feature optional + window.window_closed.connect(_save_window_geometry.bind(window)) + + +func get_module_env() -> RefCounted: + return _env + +func get_module_opt() -> ModuleOptions: + return _opt + +func _init_module(): + var module_script_dir:String = get_script().resource_path.get_base_dir() + var env_script_path = module_script_dir + "/env.gd" + var opt_script_path = module_script_dir + "/opt.gd" + + if ResourceLoader.exists(env_script_path, "GDScript"): + _env = load(env_script_path).new() + _env._module = self + core.gd_exprenv.register_env(get_module_name(), _env) + + if ResourceLoader.exists(opt_script_path, "GDScript"): + #print(opt_script_path) + _opt = load(opt_script_path).new() as ModuleOptions + _opt._module = self + + init_module() + if _opt: + _opt._loaded = true diff --git a/godot/addons/panku_console/common/panku_module.gd.uid b/godot/addons/panku_console/common/panku_module.gd.uid new file mode 100644 index 0000000..8c0f8c6 --- /dev/null +++ b/godot/addons/panku_console/common/panku_module.gd.uid @@ -0,0 +1 @@ +uid://ce7g5hrgs5lql diff --git a/godot/addons/panku_console/common/repl_base_instance.gd b/godot/addons/panku_console/common/repl_base_instance.gd new file mode 100644 index 0000000..44d7ceb --- /dev/null +++ b/godot/addons/panku_console/common/repl_base_instance.gd @@ -0,0 +1,23 @@ +var _core:PankuConsole + +const _HELP_help := "List all environment variables." +var help:String: + get: + var result = ["Registered objects:\n"] + var colors = ["#7c3f58", "#eb6b6f", "#f9a875", "#fff6d3"] + var i = 0 + for k in _core.gd_exprenv._envs: + var c = colors[i%4] + i = i + 1 + result.push_back("[b][color=%s]%s[/color][/b] "%[c, k]) + result.push_back("\n") + result.push_back("You can type [b]helpe(object)[/b] to get more information.") + return "".join(PackedStringArray(result)) + +const _HELP_helpe := "Provide detailed information about one specific environment variable." +func helpe(obj:Object) -> String: + if !obj: + return "Invalid!" + if !obj.get_script(): + return "It has no attached script!" + return PankuGDExprEnv.generate_help_text_from_script(obj.get_script()) diff --git a/godot/addons/panku_console/common/repl_base_instance.gd.uid b/godot/addons/panku_console/common/repl_base_instance.gd.uid new file mode 100644 index 0000000..5622b43 --- /dev/null +++ b/godot/addons/panku_console/common/repl_base_instance.gd.uid @@ -0,0 +1 @@ +uid://b8fo6s8tlpkh4 diff --git a/godot/addons/panku_console/common/smooth_scroll/smooth_scroll.gd b/godot/addons/panku_console/common/smooth_scroll/smooth_scroll.gd new file mode 100644 index 0000000..40d071f --- /dev/null +++ b/godot/addons/panku_console/common/smooth_scroll/smooth_scroll.gd @@ -0,0 +1,57 @@ +extends PanelContainer + +@export var clip_container:Control + +@export var scrollbar:VScrollBar + +@export var follow_content:bool = true + +@onready var content:Control = clip_container.get_child(0) + +var scroll_progress:float = 0.0 +var prev_content_size_y:float = 0.0 + +func init_progressbar() -> void: + scrollbar.min_value = 0.0 + scrollbar.allow_greater = true + scrollbar.allow_lesser = true + scrollbar.value = 0.0 + +func _gui_input(event: InputEvent) -> void: + if event is InputEventMouseButton and event.is_pressed(): + var step:float = clip_container.size.y / 8.0 + if event.button_index == MOUSE_BUTTON_WHEEL_UP: + scrollbar.value -= step + if event.button_index == MOUSE_BUTTON_WHEEL_DOWN: + scrollbar.value += step + +func _process(delta: float) -> void: + # add a tiny optimization here + if not is_visible_in_tree(): return + + # See https://github.com/Ark2000/PankuConsole/issues/183, looks quirky + # content.size = Vector2(clip_container.size.x, 0) + # content.position = Vector2.ZERO + content.size.x = clip_container.size.x + content.size.y = 0 + content.position.y = 0 + content.position.x = 0 + + scrollbar.max_value = content.size.y + var scrollbar_value_max = max(0, scrollbar.max_value - clip_container.size.y) + scrollbar.value = PankuUtils.interp(scrollbar.value, clampf(scrollbar.value, 0.0, scrollbar_value_max), 10, delta) + scrollbar.page = clip_container.size.y + scrollbar.visible = content.size.y > clip_container.size.y + + scroll_progress = PankuUtils.interp(scroll_progress, scrollbar.value, 10, delta) + content.position.y = - scroll_progress + + if !follow_content: return + if prev_content_size_y != content.size.y: + var should_follow:bool = (scrollbar.value + scrollbar.page) / prev_content_size_y > 0.99 + prev_content_size_y = content.size.y + if should_follow: + scrollbar.value = scrollbar.max_value - scrollbar.page + +func _ready() -> void: + init_progressbar() diff --git a/godot/addons/panku_console/common/smooth_scroll/smooth_scroll.gd.uid b/godot/addons/panku_console/common/smooth_scroll/smooth_scroll.gd.uid new file mode 100644 index 0000000..5836452 --- /dev/null +++ b/godot/addons/panku_console/common/smooth_scroll/smooth_scroll.gd.uid @@ -0,0 +1 @@ +uid://dtang12b2rua7 diff --git a/godot/addons/panku_console/common/smooth_scroll/smooth_scroll.tscn b/godot/addons/panku_console/common/smooth_scroll/smooth_scroll.tscn new file mode 100644 index 0000000..013b157 --- /dev/null +++ b/godot/addons/panku_console/common/smooth_scroll/smooth_scroll.tscn @@ -0,0 +1,30 @@ +[gd_scene load_steps=3 format=3 uid="uid://dyq4rjkkjs55d"] + +[ext_resource type="Script" path="res://addons/panku_console/common/smooth_scroll/smooth_scroll.gd" id="1_ma8ku"] +[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="1_pa7xs"] + +[node name="SmoothScrollContainer" type="PanelContainer" node_paths=PackedStringArray("clip_container", "scrollbar")] +self_modulate = Color(1, 1, 1, 0) +clip_contents = true +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme = ExtResource("1_pa7xs") +script = ExtResource("1_ma8ku") +clip_container = NodePath("HBoxContainer/Control") +scrollbar = NodePath("HBoxContainer/VScrollBar") + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="Control" type="Control" parent="HBoxContainer"] +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="VScrollBar" type="VScrollBar" parent="HBoxContainer"] +layout_mode = 2 +page = 20.0 +value = 80.0 diff --git a/godot/addons/panku_console/common/utils.gd b/godot/addons/panku_console/common/utils.gd new file mode 100644 index 0000000..7f3777e --- /dev/null +++ b/godot/addons/panku_console/common/utils.gd @@ -0,0 +1,43 @@ +#@tool +#extends EditorScript +class_name PankuUtils + +# It will be included if you download the plugin from mirror repo(https://github.com/Ark2000/panku_console) +const COMMIT_SHA_FILE_PATH = "res://addons/panku_console/COMMIT_SHA" + +static func get_plugin_version() -> String: + var error_result = "Unknown version" + #load version string from plugin.cfg + var cfg = ConfigFile.new() + if cfg.load("res://addons/panku_console/plugin.cfg") != OK: + return error_result + return cfg.get_value("plugin", "version", error_result) + +static func get_commit_sha() -> String: + if FileAccess.file_exists(COMMIT_SHA_FILE_PATH): + return FileAccess.get_file_as_string(COMMIT_SHA_FILE_PATH) + return "" + +static func get_commit_sha_short() -> String: + return get_commit_sha().substr(0, 7) + +static func get_commit_url() -> String: + var sha := get_commit_sha() + if sha != "": + return "https://github.com/Ark2000/PankuConsole/commit/" + sha + return "" + +# Framerate-independent interpolation. +static func interp(from, to, lambda: float, delta: float): + if from is Vector2: + if abs(from.x - to.x) < 1.0: from.x = to.x + if abs(from.y - to.y) < 1.0: from.y = to.y + if from is float: + if abs(from - to) < 0.01: from = to + return lerp(from, to, 1.0 - exp(-lambda * delta)) + +#func _run(): +# print("plugin_version: ", get_plugin_version()) +# print("commit_sha: ", get_commit_sha()) +# print("commit_sha_short: ", get_commit_sha_short()) +# print("commit_url: ", get_commit_url()) diff --git a/godot/addons/panku_console/common/utils.gd.uid b/godot/addons/panku_console/common/utils.gd.uid new file mode 100644 index 0000000..9c48668 --- /dev/null +++ b/godot/addons/panku_console/common/utils.gd.uid @@ -0,0 +1 @@ +uid://yw3dk5jaii26 diff --git a/godot/addons/panku_console/console.gd b/godot/addons/panku_console/console.gd new file mode 100644 index 0000000..8900e36 --- /dev/null +++ b/godot/addons/panku_console/console.gd @@ -0,0 +1,86 @@ +class_name PankuConsole extends CanvasLayer +# `console.gd` is a global singleton that provides all modules with a common interface +# you can also use some of its members to interact with the console + +signal interactive_shell_visibility_changed(visible:bool) +signal new_expression_entered(expression:String, result) +signal new_notification_created(bbcode:String, id:int) +signal toggle_console_action_just_pressed() + +const SingletonName = "Panku" +const SingletonPath = "/root/" + SingletonName +const ToggleConsoleAction = "toggle_console" + +# create_data_controller(objs:Array[Object]) -> PankuLynxWindow +var create_data_controller_window:Callable = func(objs:Array): return null + +var windows_manager:PankuLynxWindowsManager +var module_manager:PankuModuleManager = PankuModuleManager.new() +var gd_exprenv:PankuGDExprEnv = PankuGDExprEnv.new() +var _shell_visibility := false + +# notification whose id>=0 will be fixed to the bottom of the notification list +# useful for loop print +# you can use `get_instance_id()` as notification's unique id +func notify(any, id=-1) -> void: + var text = str(any) + new_notification_created.emit(text, id) + +func get_shell_visibility() -> bool: + return _shell_visibility + +func _input(event: InputEvent): + if event.is_action_pressed(ToggleConsoleAction): + toggle_console_action_just_pressed.emit() + +func _ready(): + assert(get_tree().current_scene != self, "Do not run console.tscn as a scene!") + + # Yep, seems like double check project settings in the main singleton + # is the only "correct" way to work with custom project setting + # https://github.com/godotengine/godot/issues/56598#issuecomment-1904100640 + PankuConfig.init_all_project_settings() + + if not PankuConfig.is_custom_default_config_exists(): + push_warning("[Panku Console] Default config file not found. Using code-level default config.") + + windows_manager = $LynxWindowsManager + var base_instance = preload("./common/repl_base_instance.gd").new() + base_instance._core = self + gd_exprenv.set_base_instance(base_instance) + + # add default input action if not defined by user + if not InputMap.has_action(ToggleConsoleAction): + InputMap.add_action(ToggleConsoleAction) + var default_toggle_console_event = InputEventKey.new() + default_toggle_console_event.physical_keycode = KEY_QUOTELEFT + InputMap.action_add_event(ToggleConsoleAction, default_toggle_console_event) + + # since panku console servers numerous purposes + # we use a module system to manage all different features + # modules are invisible to each other by design to avoid coupling + # you can add or remove any modules here as you wish + var modules:Array[PankuModule] = [ + PankuModuleNativeLogger.new(), + PankuModuleScreenNotifier.new(), + PankuModuleSystemReport.new(), + PankuModuleHistoryManager.new(), + PankuModuleEngineTools.new(), + PankuModuleKeyboardShortcuts.new(), + PankuModuleCheckLatestRelease.new(), + PankuModuleInteractiveShell.new(), + PankuModuleGeneralSettings.new(), + PankuModuleDataController.new(), + PankuModuleScreenCrtEffect.new(), + PankuModuleExpressionMonitor.new(), + PankuModuleTextureViewer.new(), + PankuModuleVariableTracker.new(), + PankuModuleAbout.new(), + PankuModuleSnakeGame.new(), + ] + module_manager.init_manager(self, modules) + +func _notification(what): + # quit event + if what == NOTIFICATION_WM_CLOSE_REQUEST: + module_manager.quit_modules() diff --git a/godot/addons/panku_console/console.gd.uid b/godot/addons/panku_console/console.gd.uid new file mode 100644 index 0000000..5a70886 --- /dev/null +++ b/godot/addons/panku_console/console.gd.uid @@ -0,0 +1 @@ +uid://otltxiojr8qu diff --git a/godot/addons/panku_console/console.tscn b/godot/addons/panku_console/console.tscn new file mode 100644 index 0000000..2506b02 --- /dev/null +++ b/godot/addons/panku_console/console.tscn @@ -0,0 +1,22 @@ +[gd_scene load_steps=4 format=3 uid="uid://cyftuo4syatlv"] + +[ext_resource type="Script" path="res://addons/panku_console/console.gd" id="1_dohs1"] +[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="2_wxhx6"] +[ext_resource type="Script" path="res://addons/panku_console/common/lynx_window2/lynx_windows_manager_2.gd" id="10_f7qaq"] + +[node name="Console" type="CanvasLayer"] +process_mode = 3 +layer = 128 +script = ExtResource("1_dohs1") + +[node name="LynxWindowsManager" type="Control" parent="."] +z_index = 1 +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +theme = ExtResource("2_wxhx6") +script = ExtResource("10_f7qaq") diff --git a/godot/addons/panku_console/default_panku_config.cfg b/godot/addons/panku_console/default_panku_config.cfg new file mode 100644 index 0000000..e5deb54 --- /dev/null +++ b/godot/addons/panku_console/default_panku_config.cfg @@ -0,0 +1,80 @@ +{ +"enable_os_window": false, +"engine_tools": { +"time_scale": 1.0 +}, +"exp_history": [], +"expression_monitor": { +"monitor_data": [{ +"expressions": ["engine_tools.get_performance_info()"], +"group_name": "default group" +}], +"window_position": Vector2(0, 49), +"window_size": Vector2(85, 74), +"window_visibility": false +}, +"general_settings": { +"enable_os_window": false, +"lynx_window_base_color": Color(0, 0.0470588, 0.0941176, 0.501961), +"lynx_window_blur_effect": true, +"lynx_window_enable_os_window": false, +"lynx_window_os_window_bg_color": Color(0, 0, 0, 0.658824), +"os_window_bg_color": Color(0, 0, 0, 0.992157), +"window_blur_effect": true, +"window_position": Vector2(429.546, 94.1911), +"window_size": Vector2(512.568, 478.128), +"window_visibility": true +}, +"history_manager": { +"window_position": Vector2(317.728, 138.82), +"window_size": Vector2(411.987, 339.537), +"window_visibility": false +}, +"interactive_shell": { +"gui_mode": 0, +"histories": [], +"init_expr": "", +"output_font_size": 14.0, +"pause_if_input": false, +"pause_if_popup": false, +"show_side_menu": true, +"unified_visibility": false, +"unified_window_visibility": false, +"window_position": Vector2(427.419, 75.3913), +"window_size": Vector2(510.736, 410.437), +"window_visibility": true +}, +"keyboard_shortcuts": { +"key_mapper": [], +"window_position": Vector2(0, 49), +"window_size": Vector2(85, 74), +"window_visibility": false +}, +"native_logger": { +"font_size": 17.0, +"logger_tags": ["[error]", "[warning]", "[info]"], +"screen_overlay": 0, +"screen_overlay_alpha": 0.44, +"screen_overlay_font_shadow": true, +"screen_overlay_font_size": 20.0, +"show_timestamp": true, +"window_position": Vector2(284.123, 124.547), +"window_size": Vector2(483.998, 379.028), +"window_visibility": false +}, +"os_window_bg_color": Color(0, 0, 0, 0.992157), +"os_window_bgcolor": Color(0, 0, 0, 0.658824), +"snake": { +"leader_board": [{ +"score": 40, +"timestamp": "2024-01-29T16:00:00" +}, { +"score": 20, +"timestamp": "2024-01-29T16:01:14" +}] +}, +"variable_tracker": { +"tracking_delay": 0.5, +"use_last_as_current": true +} +} diff --git a/godot/addons/panku_console/logo.svg b/godot/addons/panku_console/logo.svg new file mode 100644 index 0000000..41f564c --- /dev/null +++ b/godot/addons/panku_console/logo.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/godot/addons/panku_console/logo.svg.import b/godot/addons/panku_console/logo.svg.import new file mode 100644 index 0000000..79c2e5f --- /dev/null +++ b/godot/addons/panku_console/logo.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://rkxm4c3bbf34" +path="res://.godot/imported/logo.svg-5c6f042742ccac523c072414b9eb3caf.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/logo.svg" +dest_files=["res://.godot/imported/logo.svg-5c6f042742ccac523c072414b9eb3caf.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/modules/about/about.gd b/godot/addons/panku_console/modules/about/about.gd new file mode 100644 index 0000000..79b01f9 --- /dev/null +++ b/godot/addons/panku_console/modules/about/about.gd @@ -0,0 +1,26 @@ +extends Control + +var _module:PankuModule + +@export var intro:Label +@export var project_page_button:Button +@export var check_update_button:Button + +# Called when the node enters the scene tree for the first time. +func _ready(): + var version:String = PankuUtils.get_plugin_version() + var sha:String = PankuUtils.get_commit_sha_short() + if sha == "": sha = "Unknown" + + intro.text = intro.text.replace("", version) + intro.text = intro.text.replace("", sha) + + project_page_button.pressed.connect( + func(): + OS.shell_open("https://github.com/Ark2000/PankuConsole") + ) + + check_update_button.pressed.connect( + func(): + _module.core.gd_exprenv.execute("check_latest_release.check()") + ) diff --git a/godot/addons/panku_console/modules/about/about.gd.uid b/godot/addons/panku_console/modules/about/about.gd.uid new file mode 100644 index 0000000..fb3e65a --- /dev/null +++ b/godot/addons/panku_console/modules/about/about.gd.uid @@ -0,0 +1 @@ +uid://pkgdt4duvguc diff --git a/godot/addons/panku_console/modules/about/about.tscn b/godot/addons/panku_console/modules/about/about.tscn new file mode 100644 index 0000000..ecd50f3 --- /dev/null +++ b/godot/addons/panku_console/modules/about/about.tscn @@ -0,0 +1,215 @@ +[gd_scene load_steps=10 format=3 uid="uid://cgwg3foes57mq"] + +[ext_resource type="Script" path="res://addons/panku_console/modules/about/about.gd" id="1_kpix3"] +[ext_resource type="PackedScene" uid="uid://dyq4rjkkjs55d" path="res://addons/panku_console/common/smooth_scroll/smooth_scroll.tscn" id="2_sev6e"] +[ext_resource type="Texture2D" uid="uid://rkxm4c3bbf34" path="res://addons/panku_console/logo.svg" id="3_eycho"] +[ext_resource type="PackedScene" uid="uid://cxmplwhfv5l88" path="res://addons/panku_console/modules/about/url_button.tscn" id="4_cqu2c"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_knn3o"] +content_margin_left = 8.0 +content_margin_top = 8.0 +content_margin_right = 8.0 +content_margin_bottom = 8.0 +bg_color = Color(0, 0, 0, 0.270588) + +[sub_resource type="FontVariation" id="FontVariation_v70xy"] +variation_embolden = 0.5 + +[sub_resource type="FontVariation" id="FontVariation_wgi7f"] +variation_embolden = 0.5 + +[sub_resource type="SystemFont" id="SystemFont_6on77"] +font_names = PackedStringArray("Monospace") + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_cqcex"] +content_margin_left = 4.0 +content_margin_top = 4.0 +content_margin_right = 4.0 +content_margin_bottom = 4.0 +bg_color = Color(0, 0, 0, 0.25098) +corner_radius_top_left = 4 +corner_radius_top_right = 4 +corner_radius_bottom_right = 4 +corner_radius_bottom_left = 4 + +[node name="about" type="Control" node_paths=PackedStringArray("intro", "project_page_button", "check_update_button")] +clip_contents = true +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_kpix3") +intro = NodePath("VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/PanelContainer/HBoxContainer/Label") +project_page_button = NodePath("VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/ProjectPageButton") +check_update_button = NodePath("VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/CheckUpdateButton") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 1 +anchors_preset = -1 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 8.0 +offset_top = 8.0 +offset_right = -8.0 +offset_bottom = -8.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="SmoothScrollContainer" parent="VBoxContainer" instance=ExtResource("2_sev6e")] +layout_mode = 2 +size_flags_vertical = 3 +follow_content = false + +[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control" index="0"] +layout_mode = 1 +anchors_preset = 10 +anchor_right = 1.0 +offset_bottom = 995.0 +grow_horizontal = 2 + +[node name="PanelContainer" type="PanelContainer" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer"] +layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_knn3o") + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/PanelContainer"] +layout_mode = 2 +alignment = 1 + +[node name="TextureRect" type="TextureRect" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/PanelContainer/HBoxContainer"] +layout_mode = 2 +texture = ExtResource("3_eycho") +expand_mode = 2 + +[node name="Label" type="Label" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/PanelContainer/HBoxContainer"] +layout_mode = 2 +text = "Panku Console [] +© 2022-present Panku Console contributors. +© 2022 Ark2000. +" + +[node name="Label" type="Label" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer"] +layout_mode = 2 +text = "Panku Console is a feature-packed real-time debugging toolkit for Godot Engine." +clip_text = true + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer"] +layout_mode = 2 + +[node name="ProjectPageButton" type="Button" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_fonts/font = SubResource("FontVariation_v70xy") +text = "Project Page" + +[node name="CheckUpdateButton" type="Button" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_fonts/font = SubResource("FontVariation_v70xy") +text = "Check Update" + +[node name="HSeparator" type="HSeparator" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer"] +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer"] +layout_mode = 2 +theme_override_fonts/font = SubResource("FontVariation_wgi7f") +text = "Project Manager" + +[node name="Button" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer" instance=ExtResource("4_cqu2c")] +layout_mode = 2 +text = "Feo Wu (Ark2000)" +url = "https://github.com/Ark2000" + +[node name="Label2" type="Label" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer"] +layout_mode = 2 +theme_override_fonts/font = SubResource("FontVariation_wgi7f") +text = "Contributors" + +[node name="Button2" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer" instance=ExtResource("4_cqu2c")] +layout_mode = 2 +text = "Feo Wu (Ark2000)" +url = "https://github.com/Ark2000" + +[node name="Button3" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer" instance=ExtResource("4_cqu2c")] +layout_mode = 2 +text = "Rafael Correa (scriptsengineer)" +url = "https://github.com/scriptsengineer" + +[node name="Button4" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer" instance=ExtResource("4_cqu2c")] +layout_mode = 2 +text = "worron" +url = "https://github.com/worron" + +[node name="Button5" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer" instance=ExtResource("4_cqu2c")] +layout_mode = 2 +text = "mieldepoche" +url = "https://github.com/mieldepoche" + +[node name="Button6" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer" instance=ExtResource("4_cqu2c")] +layout_mode = 2 +text = "Eggbertx" +url = "https://github.com/Eggbertx" + +[node name="Button7" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer" instance=ExtResource("4_cqu2c")] +layout_mode = 2 +text = "univeous" +url = "https://github.com/univeous" + +[node name="Button8" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer" instance=ExtResource("4_cqu2c")] +layout_mode = 2 +text = "CheapMeow" +url = "https://github.com/CheapMeow" + +[node name="Button9" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer" instance=ExtResource("4_cqu2c")] +layout_mode = 2 +text = "winston-yallow (Winston)" +url = "https://github.com/winston-yallow" + +[node name="Label3" type="Label" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer"] +layout_mode = 2 +theme_override_fonts/font = SubResource("FontVariation_wgi7f") +text = "Icons" + +[node name="Button10" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer" instance=ExtResource("4_cqu2c")] +layout_mode = 2 +text = "SVG Repo" +url = "https://www.svgrepo.com/page/licensing/" + +[node name="Label4" type="Label" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer"] +layout_mode = 2 +theme_override_fonts/font = SubResource("FontVariation_wgi7f") +text = "License" + +[node name="Label5" type="Label" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer"] +layout_mode = 2 +theme_override_fonts/font = SubResource("SystemFont_6on77") +theme_override_styles/normal = SubResource("StyleBoxFlat_cqcex") +text = "The MIT License (MIT) + +Copyright (c) 2022-present Panku Console contributors. +Copyright (c) 2022 Ark2000 + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the \"Software\"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." +clip_text = true + +[editable path="VBoxContainer/SmoothScrollContainer"] diff --git a/godot/addons/panku_console/modules/about/env.gd b/godot/addons/panku_console/modules/about/env.gd new file mode 100644 index 0000000..e3e1d11 --- /dev/null +++ b/godot/addons/panku_console/modules/about/env.gd @@ -0,0 +1,5 @@ +var _module:PankuModule + +const _HELP_open = "Open about window" +func open() -> void: + _module.open_window() diff --git a/godot/addons/panku_console/modules/about/env.gd.uid b/godot/addons/panku_console/modules/about/env.gd.uid new file mode 100644 index 0000000..9a153ac --- /dev/null +++ b/godot/addons/panku_console/modules/about/env.gd.uid @@ -0,0 +1 @@ +uid://cbd0wepa77b0c diff --git a/godot/addons/panku_console/modules/about/module.gd b/godot/addons/panku_console/modules/about/module.gd new file mode 100644 index 0000000..9b4c915 --- /dev/null +++ b/godot/addons/panku_console/modules/about/module.gd @@ -0,0 +1,15 @@ +class_name PankuModuleAbout extends PankuModule + +var window:PankuLynxWindow +const ui = preload("./about.tscn") + +func open_window(): + if window: return + var ui_instance = ui.instantiate() + ui_instance._module = self + window = core.windows_manager.create_window(ui_instance) + window.set_window_title_text("About") + window.show_window() + window.window_closed.connect( + func(): window = null + ) diff --git a/godot/addons/panku_console/modules/about/module.gd.uid b/godot/addons/panku_console/modules/about/module.gd.uid new file mode 100644 index 0000000..2754617 --- /dev/null +++ b/godot/addons/panku_console/modules/about/module.gd.uid @@ -0,0 +1 @@ +uid://bhcijrphn6uto diff --git a/godot/addons/panku_console/modules/about/url_button.gd b/godot/addons/panku_console/modules/about/url_button.gd new file mode 100644 index 0000000..97a4e1a --- /dev/null +++ b/godot/addons/panku_console/modules/about/url_button.gd @@ -0,0 +1,9 @@ +extends Button + +@export var url:String + +func _ready(): + pressed.connect( + func(): + OS.shell_open(url) + ) diff --git a/godot/addons/panku_console/modules/about/url_button.gd.uid b/godot/addons/panku_console/modules/about/url_button.gd.uid new file mode 100644 index 0000000..da3bb33 --- /dev/null +++ b/godot/addons/panku_console/modules/about/url_button.gd.uid @@ -0,0 +1 @@ +uid://btw5pitk8auv6 diff --git a/godot/addons/panku_console/modules/about/url_button.tscn b/godot/addons/panku_console/modules/about/url_button.tscn new file mode 100644 index 0000000..72236a3 --- /dev/null +++ b/godot/addons/panku_console/modules/about/url_button.tscn @@ -0,0 +1,17 @@ +[gd_scene load_steps=3 format=3 uid="uid://cxmplwhfv5l88"] + +[ext_resource type="Script" path="res://addons/panku_console/modules/about/url_button.gd" id="1_01blg"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ivnlg"] +content_margin_left = 8.0 +bg_color = Color(0, 0, 0, 0.243137) +corner_radius_top_left = 4 +corner_radius_top_right = 4 +corner_radius_bottom_right = 4 +corner_radius_bottom_left = 4 + +[node name="Button" type="Button"] +theme_override_styles/normal = SubResource("StyleBoxFlat_ivnlg") +text = "Button Text" +alignment = 0 +script = ExtResource("1_01blg") diff --git a/godot/addons/panku_console/modules/check_latest_release/env.gd b/godot/addons/panku_console/modules/check_latest_release/env.gd new file mode 100644 index 0000000..74e0a00 --- /dev/null +++ b/godot/addons/panku_console/modules/check_latest_release/env.gd @@ -0,0 +1,5 @@ +var _module:PankuModule + +const _HELP_check = "Fetch latest release information from Github" +func check(): + _module.check() diff --git a/godot/addons/panku_console/modules/check_latest_release/env.gd.uid b/godot/addons/panku_console/modules/check_latest_release/env.gd.uid new file mode 100644 index 0000000..eeb2680 --- /dev/null +++ b/godot/addons/panku_console/modules/check_latest_release/env.gd.uid @@ -0,0 +1 @@ +uid://dad7nd3c3hjqv diff --git a/godot/addons/panku_console/modules/check_latest_release/module.gd b/godot/addons/panku_console/modules/check_latest_release/module.gd new file mode 100644 index 0000000..e720ff7 --- /dev/null +++ b/godot/addons/panku_console/modules/check_latest_release/module.gd @@ -0,0 +1,32 @@ +class_name PankuModuleCheckLatestRelease extends PankuModule + +signal check_lasted_release_requested() +signal check_lasted_release_responded(msg:Dictionary) + +func send_request() -> Node: + var node = preload("./network.gd").new() + core.add_child(node) + node.check_latest_release() + node.response_received.connect( + func(_v): node.queue_free() + ) + return node + +func check_update(): + send_request().response_received.connect( + func(msg:Dictionary): + check_lasted_release_responded.emit(msg) + ) + +func check(): + send_request().response_received.connect( + func(msg:Dictionary): + if !msg["success"]: + core.notify("[color=red][Error][/color] Failed! " + msg["msg"]) + else: + core.notify("[color=green][info][/color] Latest: [%s] [url=%s]%s[/url]" % [msg["published_at"], msg["html_url"], msg["name"]]) + ) + +func init_module(): + # implement core functions + check_lasted_release_requested.connect(check_update) diff --git a/godot/addons/panku_console/modules/check_latest_release/module.gd.uid b/godot/addons/panku_console/modules/check_latest_release/module.gd.uid new file mode 100644 index 0000000..e4a6b37 --- /dev/null +++ b/godot/addons/panku_console/modules/check_latest_release/module.gd.uid @@ -0,0 +1 @@ +uid://ba42o6b87vvna diff --git a/godot/addons/panku_console/modules/check_latest_release/network.gd b/godot/addons/panku_console/modules/check_latest_release/network.gd new file mode 100644 index 0000000..963718e --- /dev/null +++ b/godot/addons/panku_console/modules/check_latest_release/network.gd @@ -0,0 +1,59 @@ +extends HTTPRequest + +signal response_received(msg:Dictionary) + +const LATEST_RELEASE_URL = "https://api.github.com/repos/Ark2000/PankuConsole/releases/latest" + +const REQUEST_RESULT = { + RESULT_SUCCESS: "SUCCESS", + RESULT_CHUNKED_BODY_SIZE_MISMATCH: "CHUNKED_BODY_SIZE_MISMATCH", + RESULT_CANT_CONNECT: "CANT_CONNECT", + RESULT_CANT_RESOLVE: "CANT_RESOLVE", + RESULT_CONNECTION_ERROR: "CONNECTION_ERROR", + RESULT_TLS_HANDSHAKE_ERROR: "TLS_HANDSHAKE_ERROR", + RESULT_NO_RESPONSE: "NO_RESPONSE", + RESULT_BODY_SIZE_LIMIT_EXCEEDED: "BODY_SIZE_LIMIT_EXCEEDED", + RESULT_BODY_DECOMPRESS_FAILED: "BODY_DECOMPRESS_FAILED", + RESULT_REQUEST_FAILED: "REQUEST_FAILED", + RESULT_DOWNLOAD_FILE_CANT_OPEN: "DOWNLOAD_FILE_CANT_OPEN", + RESULT_DOWNLOAD_FILE_WRITE_ERROR: "DOWNLOAD_FILE_WRITE_ERROR", + RESULT_REDIRECT_LIMIT_REACHED: "REDIRECT_LIMIT_REACHED", + RESULT_TIMEOUT: "TIMEOUT" +} + +static func dget(dict:Dictionary, key, default_value=""): + return default_value if !dict.has(key) else dict[key] + +var is_busy := false + +func _ready(): + request_completed.connect(_on_request_completed) + +func check_latest_release(): + if is_busy: return + is_busy = true + var error = request(LATEST_RELEASE_URL) + if error != OK: + is_busy = false + response_received.emit({ + "success": false, + "msg": "An error occurred in the HTTP request." + }) + +func _on_request_completed(result:int, response_code:int, headers:PackedStringArray, body:PackedByteArray): + is_busy = false + if result != RESULT_SUCCESS: + response_received.emit({ + "success": false, + "msg": REQUEST_RESULT[result] + }) + return + var json = JSON.new() + json.parse(body.get_string_from_utf8()) + var response:Dictionary = json.get_data() + response_received.emit({ + "success": true, + "published_at": dget(response, "published_at", "???"), + "name": dget(response, "name", "???"), + "html_url": dget(response, "html_url", "???") + }) diff --git a/godot/addons/panku_console/modules/check_latest_release/network.gd.uid b/godot/addons/panku_console/modules/check_latest_release/network.gd.uid new file mode 100644 index 0000000..7e2a57a --- /dev/null +++ b/godot/addons/panku_console/modules/check_latest_release/network.gd.uid @@ -0,0 +1 @@ +uid://dojjr6xbfugxm diff --git a/godot/addons/panku_console/modules/check_latest_release/opt.gd b/godot/addons/panku_console/modules/check_latest_release/opt.gd new file mode 100644 index 0000000..9bd8384 --- /dev/null +++ b/godot/addons/panku_console/modules/check_latest_release/opt.gd @@ -0,0 +1,8 @@ +extends ModuleOptions + +@export_group("check_latest_release") + +@export var export_button_check_update := "Check Update" + +func check_update(): + _module.check() diff --git a/godot/addons/panku_console/modules/check_latest_release/opt.gd.uid b/godot/addons/panku_console/modules/check_latest_release/opt.gd.uid new file mode 100644 index 0000000..f7b0d94 --- /dev/null +++ b/godot/addons/panku_console/modules/check_latest_release/opt.gd.uid @@ -0,0 +1 @@ +uid://dwah7jcf3nn6i diff --git a/godot/addons/panku_console/modules/engine_tools/env.gd b/godot/addons/panku_console/modules/engine_tools/env.gd new file mode 100644 index 0000000..33bfdd8 --- /dev/null +++ b/godot/addons/panku_console/modules/engine_tools/env.gd @@ -0,0 +1,30 @@ +var _module:PankuModule + +const _HELP_toggle_fullscreen = "Toggle [fullscreen / windowed] mode" +func toggle_fullscreen() -> void: + _module.toggle_fullscreen() + +const _HELP_set_time_scale = "Equals to [color=green]Engine.time_scale[/color]" +func set_time_scale(val:float) -> void: + _module.set_time_scale(val) + +const _HELP_get_performance_info = "Show performance info" +func get_performance_info(count_nodes := false) -> String: + return _module.get_performance_info(count_nodes) + +const _HELP_take_screenshot = "Take a screenshot of current window" +func take_screenshot() -> void: + _module.take_screenshot() + +const _HELP_quit = "Quit application" +func quit() -> void: + _module.quit() + +const _HELP_toggle_2d_collision_shape_visibility = "Toggle visibility of 2D collision shapes, useful for debugging" +func toggle_2d_collision_shape_visibility() -> void: + _module.toggle_2d_collision_shape_visibility() + +const _HELP_reload_current_scene = "Reload current scene" +func reload_current_scene() -> void: + _module.reload_current_scene() + diff --git a/godot/addons/panku_console/modules/engine_tools/env.gd.uid b/godot/addons/panku_console/modules/engine_tools/env.gd.uid new file mode 100644 index 0000000..69eda18 --- /dev/null +++ b/godot/addons/panku_console/modules/engine_tools/env.gd.uid @@ -0,0 +1 @@ +uid://b02ldrmvchylr diff --git a/godot/addons/panku_console/modules/engine_tools/module.gd b/godot/addons/panku_console/modules/engine_tools/module.gd new file mode 100644 index 0000000..512f650 --- /dev/null +++ b/godot/addons/panku_console/modules/engine_tools/module.gd @@ -0,0 +1,72 @@ +class_name PankuModuleEngineTools extends PankuModule + +func init_module(): + get_module_opt().count_nodes = load_module_data("count_nodes", false) + super.init_module() + +func toggle_fullscreen() -> void: + if DisplayServer.window_get_mode() != DisplayServer.WINDOW_MODE_WINDOWED: + DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED) + else: + DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN) + core.notify("Fullscreen: " + str(DisplayServer.window_get_mode() == DisplayServer.WINDOW_MODE_FULLSCREEN)) + +func set_time_scale(val:float) -> void: + Engine.time_scale = val + +class ClsCountNodesInTree: + func calc_children_count(core: PankuConsole, node_path: String) -> int: + var nd: Node = core.get_tree().current_scene.get_node(node_path) + return count_all_children(nd) + func count_all_children(nd: Node) -> int: + var count: int = nd.get_children().size() + for child: Node in nd.get_children(): + count += count_all_children(child) + return count + +func get_performance_info(count_nodes:bool) -> String: + var result = "FPS: %d | Mem: %.2fMB | Objs: %d" % [ + Engine.get_frames_per_second(), + OS.get_static_memory_usage()/1048576.0, + Performance.get_monitor(Performance.OBJECT_COUNT) + ] + if count_nodes: + var cls_count: ClsCountNodesInTree = ClsCountNodesInTree.new() + var root_count: int = cls_count.calc_children_count(core, "/root") + var panku_count: int = cls_count.calc_children_count(core, "/root/Panku") + result += " | Nodes: %d" % [root_count - panku_count] + return result + +func take_screenshot() -> void: + var image = core.get_viewport().get_texture().get_image() + var time = str(int(Time.get_unix_time_from_system() * 1000.0)) + var file_name = "screenshot_%s.png" % time + var path = "user://".path_join(file_name) + var real_path = OS.get_user_data_dir().path_join(file_name) + image.save_png(path) + core.notify("[b]Screenshot[/b] saved at [color=green][url=%s]%s[/url][/color]" % [real_path, real_path]) + +func quit() -> void: + core.get_tree().root.propagate_notification(core.NOTIFICATION_WM_CLOSE_REQUEST) + core.get_tree().quit() + +# Currently godot can't toggle visibility of 2D collision shapes at runtime, this is a workaround. +# See https://github.com/godotengine/godot-proposals/issues/2072 +func toggle_2d_collision_shape_visibility() -> void: + var tree := core.get_tree() + tree.debug_collisions_hint = not tree.debug_collisions_hint + + # Traverse tree to call queue_redraw on instances of + # CollisionShape2D and CollisionPolygon2D. + var node_stack: Array[Node] = [tree.get_root()] + while not node_stack.is_empty(): + var node: Node = node_stack.pop_back() + if is_instance_valid(node): + if node is CollisionShape2D or node is CollisionPolygon2D: + node.queue_redraw() + node_stack.append_array(node.get_children()) + core.notify("2D Debug Draw: " + str(tree.debug_collisions_hint)) + +func reload_current_scene() -> void: + core.get_tree().reload_current_scene() + core.notify("Scene reloaded") diff --git a/godot/addons/panku_console/modules/engine_tools/module.gd.uid b/godot/addons/panku_console/modules/engine_tools/module.gd.uid new file mode 100644 index 0000000..2814df4 --- /dev/null +++ b/godot/addons/panku_console/modules/engine_tools/module.gd.uid @@ -0,0 +1 @@ +uid://dan217hmehfix diff --git a/godot/addons/panku_console/modules/engine_tools/opt.gd b/godot/addons/panku_console/modules/engine_tools/opt.gd new file mode 100644 index 0000000..63d1a77 --- /dev/null +++ b/godot/addons/panku_console/modules/engine_tools/opt.gd @@ -0,0 +1,40 @@ +extends ModuleOptions + +@export_group("engine_tools") + +@export var export_button_toggle_fullscreen := "Toggle Fullscreen" + +func toggle_fullscreen(): + _module.toggle_fullscreen() + +@export var export_button_take_screenshot := "Take Screenshot" + +func take_screenshot(): + _module.take_screenshot() + +@export var export_button_quit := "Quit" + +func quit(): + _module.quit() + +@export var export_button_toggle_2d_debug_draw := "Toggle 2D Debug Draw" + +func toggle_2d_debug_draw(): + _module.toggle_2d_collision_shape_visibility() + +@export var export_button_reload_current_scene := "Reload Current Scene" + +func reload_current_scene(): + _module.reload_current_scene() + +@export_range(0.1, 10.0, 0.01) var time_scale := 1.0: + set(v): + time_scale = v + _module.set_time_scale(time_scale) + +@export var export_comment_count_nodes = "Show node count in performance info (can issue extra performance hit)." +@export var count_nodes := false + +@export var readonly_performance_info:String: + get: + return _module.get_performance_info(count_nodes) diff --git a/godot/addons/panku_console/modules/engine_tools/opt.gd.uid b/godot/addons/panku_console/modules/engine_tools/opt.gd.uid new file mode 100644 index 0000000..f033914 --- /dev/null +++ b/godot/addons/panku_console/modules/engine_tools/opt.gd.uid @@ -0,0 +1 @@ +uid://v2u6b17gkyxf diff --git a/godot/addons/panku_console/modules/expression_monitor/env.gd b/godot/addons/panku_console/modules/expression_monitor/env.gd new file mode 100644 index 0000000..0ac9d50 --- /dev/null +++ b/godot/addons/panku_console/modules/expression_monitor/env.gd @@ -0,0 +1,4 @@ +var _module:PankuModule + +func open_window(): + _module.open_window() diff --git a/godot/addons/panku_console/modules/expression_monitor/env.gd.uid b/godot/addons/panku_console/modules/expression_monitor/env.gd.uid new file mode 100644 index 0000000..9eb8888 --- /dev/null +++ b/godot/addons/panku_console/modules/expression_monitor/env.gd.uid @@ -0,0 +1 @@ +uid://cwk00j0krbxbk diff --git a/godot/addons/panku_console/modules/expression_monitor/expression_item.gd b/godot/addons/panku_console/modules/expression_monitor/expression_item.gd new file mode 100644 index 0000000..7be43d1 --- /dev/null +++ b/godot/addons/panku_console/modules/expression_monitor/expression_item.gd @@ -0,0 +1,33 @@ +extends Control + +signal expr_changed(new_expr:String) +signal removing + +@export var x_btn:Button +@export var ledit:LineEdit +@export var label:Label + +func set_result(text:String): + label.text = text + label.get_parent().visible = (text != "") + +func set_expr(text:String): + ledit.text = text + +func get_expr() -> String: + return ledit.text + +func _ready(): + x_btn.pressed.connect( + func(): + removing.emit() + queue_free() + ) + ledit.focus_exited.connect( + func(): + expr_changed.emit(ledit.text) + ) + ledit.text_submitted.connect( + func(new_text:String): + expr_changed.emit(new_text) + ) diff --git a/godot/addons/panku_console/modules/expression_monitor/expression_item.gd.uid b/godot/addons/panku_console/modules/expression_monitor/expression_item.gd.uid new file mode 100644 index 0000000..714d5e9 --- /dev/null +++ b/godot/addons/panku_console/modules/expression_monitor/expression_item.gd.uid @@ -0,0 +1 @@ +uid://cncy7a8mdovjf diff --git a/godot/addons/panku_console/modules/expression_monitor/expression_item.tscn b/godot/addons/panku_console/modules/expression_monitor/expression_item.tscn new file mode 100644 index 0000000..21d307c --- /dev/null +++ b/godot/addons/panku_console/modules/expression_monitor/expression_item.tscn @@ -0,0 +1,46 @@ +[gd_scene load_steps=4 format=3 uid="uid://om8bp40jo1e"] + +[ext_resource type="Script" path="res://addons/panku_console/modules/expression_monitor/expression_item.gd" id="1_dnu23"] +[ext_resource type="Texture2D" uid="uid://8g5afcuanbl6" path="res://addons/panku_console/res/icons2/close.svg" id="2_bc3ds"] +[ext_resource type="PackedScene" uid="uid://drn5t13m088fb" path="res://addons/panku_console/common/panku_button.tscn" id="3_n03xa"] + +[node name="VBoxContainer" type="VBoxContainer" node_paths=PackedStringArray("x_btn", "ledit", "label")] +anchors_preset = 10 +anchor_right = 1.0 +offset_bottom = 31.0 +grow_horizontal = 2 +size_flags_horizontal = 3 +script = ExtResource("1_dnu23") +x_btn = NodePath("expression_item/PankuButton/Button") +ledit = NodePath("expression_item/LineEdit") +label = NodePath("HBoxContainer/Label") + +[node name="expression_item" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="PankuButton" parent="expression_item" instance=ExtResource("3_n03xa")] +layout_mode = 2 + +[node name="TextureRect" parent="expression_item/PankuButton/HBoxContainer" index="0"] +texture = ExtResource("2_bc3ds") + +[node name="LineEdit" type="LineEdit" parent="expression_item"] +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "Input expression here..." + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +visible = false +layout_mode = 2 + +[node name="ColorRect" type="ColorRect" parent="HBoxContainer"] +custom_minimum_size = Vector2(8, 0) +layout_mode = 2 +color = Color(0.239216, 0.533333, 0.886275, 0.752941) + +[node name="Label" type="Label" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +autowrap_mode = 1 + +[editable path="expression_item/PankuButton"] diff --git a/godot/addons/panku_console/modules/expression_monitor/expression_monitor2.gd b/godot/addons/panku_console/modules/expression_monitor/expression_monitor2.gd new file mode 100644 index 0000000..54902dc --- /dev/null +++ b/godot/addons/panku_console/modules/expression_monitor/expression_monitor2.gd @@ -0,0 +1,24 @@ +extends Control + +@onready var monitor_groups_ui := $SmoothScrollContainer/HBoxContainer/Control/MonitorGroupsUI + +var _module:PankuModule + +func _physics_process(delta: float) -> void: + if Engine.get_physics_frames() % 10 != 1: + return + if !is_visible_in_tree(): + return + + var exprss = monitor_groups_ui.get_expressions_by_group() + var resultss = [] + for exprs in exprss: + var results = [] + for expr in exprs: + if expr == "": + continue + var eval_result_dict = _module.core.gd_exprenv.execute(expr) + var eval_result:String = str(eval_result_dict["result"]) + results.append(eval_result) + resultss.append(results) + monitor_groups_ui.set_results_by_group(resultss) diff --git a/godot/addons/panku_console/modules/expression_monitor/expression_monitor2.gd.uid b/godot/addons/panku_console/modules/expression_monitor/expression_monitor2.gd.uid new file mode 100644 index 0000000..4eb2c21 --- /dev/null +++ b/godot/addons/panku_console/modules/expression_monitor/expression_monitor2.gd.uid @@ -0,0 +1 @@ +uid://jkmkx3lj1vj3 diff --git a/godot/addons/panku_console/modules/expression_monitor/expression_monitor2.tscn b/godot/addons/panku_console/modules/expression_monitor/expression_monitor2.tscn new file mode 100644 index 0000000..abf8b5c --- /dev/null +++ b/godot/addons/panku_console/modules/expression_monitor/expression_monitor2.tscn @@ -0,0 +1,30 @@ +[gd_scene load_steps=4 format=3 uid="uid://biuybfe60pr4u"] + +[ext_resource type="Script" path="res://addons/panku_console/modules/expression_monitor/expression_monitor2.gd" id="1_ha27e"] +[ext_resource type="PackedScene" uid="uid://dyq4rjkkjs55d" path="res://addons/panku_console/common/smooth_scroll/smooth_scroll.tscn" id="2_6rd5x"] +[ext_resource type="PackedScene" uid="uid://ctgf7kewoa1cn" path="res://addons/panku_console/modules/expression_monitor/monitor_groups_ui.tscn" id="2_sa5u0"] + +[node name="expression_monitor2" type="Control"] +clip_contents = true +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_ha27e") + +[node name="SmoothScrollContainer" parent="." instance=ExtResource("2_6rd5x")] +layout_mode = 1 + +[node name="MonitorGroupsUI" parent="SmoothScrollContainer/HBoxContainer/Control" index="0" instance=ExtResource("2_sa5u0")] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_right = 0.0 +offset_bottom = 0.0 +grow_horizontal = 2 +grow_vertical = 2 + +[editable path="SmoothScrollContainer"] diff --git a/godot/addons/panku_console/modules/expression_monitor/module.gd b/godot/addons/panku_console/modules/expression_monitor/module.gd new file mode 100644 index 0000000..7c5a827 --- /dev/null +++ b/godot/addons/panku_console/modules/expression_monitor/module.gd @@ -0,0 +1,29 @@ +class_name PankuModuleExpressionMonitor extends PankuModule + +var monitor +var monitor_window:PankuLynxWindow + +func init_module(): + init_monitor_window() + load_window_data(monitor_window) + monitor.monitor_groups_ui.load_persistent_data(load_module_data("monitor_data", [{ + "group_name": "default group", + "expressions": [] + }])) + +func quit_module(): + super.quit_module() + save_window_data(monitor_window) + save_module_data("monitor_data", monitor.monitor_groups_ui.get_persistent_data()) + +func init_monitor_window(): + monitor = preload("./expression_monitor2.tscn").instantiate() + monitor._module = self +# monitor.set_data(load_module_data("exprs", [])) + monitor_window = core.windows_manager.create_window(monitor) + add_auto_save_hook(monitor_window) + monitor_window.queue_free_on_close = false + monitor_window.set_window_title_text("Expression Monitor") + +func open_window(): + monitor_window.show_window() diff --git a/godot/addons/panku_console/modules/expression_monitor/module.gd.uid b/godot/addons/panku_console/modules/expression_monitor/module.gd.uid new file mode 100644 index 0000000..746767c --- /dev/null +++ b/godot/addons/panku_console/modules/expression_monitor/module.gd.uid @@ -0,0 +1 @@ +uid://bk4d660m07xto diff --git a/godot/addons/panku_console/modules/expression_monitor/monitor_group_ui.gd b/godot/addons/panku_console/modules/expression_monitor/monitor_group_ui.gd new file mode 100644 index 0000000..ed14634 --- /dev/null +++ b/godot/addons/panku_console/modules/expression_monitor/monitor_group_ui.gd @@ -0,0 +1,133 @@ +extends VBoxContainer + +signal group_move_up +signal group_move_down + +const exp_item_ui_prefab:PackedScene = preload("./expression_item.tscn") +const play_icon:Texture2D = preload("res://addons/panku_console/res/icons2/play-1001-svgrepo-com.svg") +const pause_icon:Texture2D = preload("res://addons/panku_console/res/icons2/pause-1010-svgrepo-com.svg") +const expand_icon:Texture2D = preload("res://addons/panku_console/res/icons2/chevron_right.svg") +const collapse_icon:Texture2D = preload("res://addons/panku_console/res/icons2/expand_more.svg") + +@onready var group_toggle_button:Button = $GroupManager/ToggleButton +@onready var rename_line_edit:LineEdit = $GroupManager/RenameLineEdit +@onready var state_control_button:PankuButton = $GroupManager/StateControlButton +@onready var rename_button:PankuButton = $GroupManager/RenameButton +@onready var confirm_rename_button:PankuButton = $GroupManager/ConfirmRenameButton +@onready var cancel_rename_button:PankuButton = $GroupManager/CancelRenameButton +@onready var move_up_button:PankuButton = $GroupManager/MoveUpButton +@onready var move_down_button:PankuButton = $GroupManager/MoveDownButton + +@onready var exp_body_container:Control = $PanelContainer +@onready var exp_container:Control = $PanelContainer/VBoxContainer/ExpressionContainer +@onready var add_exp_button:Button = $PanelContainer/VBoxContainer/AddNewExpressionButton +@onready var remove_this_group_button:PankuButton = $GroupManager/RemoveButton + +@onready var normal_ui_group:Array = [ + group_toggle_button, + state_control_button, + rename_button +] + +@onready var edit_ui_group:Array = [ + rename_line_edit, + confirm_rename_button, + cancel_rename_button, + move_up_button, + move_down_button, + remove_this_group_button +] + +func _ready(): + edit_ui_group.map(func(item): item.hide()) + normal_ui_group.map(func(item): item.show()) + exp_body_container.hide() + + group_toggle_button.toggle_mode = true + group_toggle_button.button_pressed = false + group_toggle_button.toggled.connect( + func(button_pressed:bool): + exp_body_container.visible = button_pressed + group_toggle_button.icon = collapse_icon if button_pressed else expand_icon + ) + + add_exp_button.pressed.connect( + func(): + var exp_item = exp_item_ui_prefab.instantiate() + exp_container.add_child(exp_item) + ) + + state_control_button.button.toggle_mode = true + state_control_button.button.button_pressed = false + state_control_button.button.toggled.connect( + func(button_pressed:bool): + state_control_button.icon = pause_icon if button_pressed else play_icon + ) + + rename_button.pressed.connect( + func(): + edit_ui_group.map(func(item): item.show()) + normal_ui_group.map(func(item): item.hide()) + rename_line_edit.text = group_toggle_button.text + ) + + cancel_rename_button.pressed.connect( + func(): + edit_ui_group.map(func(item): item.hide()) + normal_ui_group.map(func(item): item.show()) + ) + + confirm_rename_button.pressed.connect( + func(): + edit_ui_group.map(func(item): item.hide()) + normal_ui_group.map(func(item): item.show()) + group_toggle_button.text = rename_line_edit.text + ) + + move_up_button.pressed.connect( + func(): + group_move_up.emit() + ) + + move_down_button.pressed.connect( + func(): + group_move_down.emit() + ) + + remove_this_group_button.pressed.connect(queue_free) + + load_persistent_data({ + "group_name": "Unnamed Group", + "expressions": [] + }) + +func get_expressions(show_hidden := false) -> Array: + # optimization? + var exps = [] + if state_control_button.button.button_pressed or show_hidden: + for child in exp_container.get_children(): + exps.append(child.get_expr()) + return exps + +func set_results(results:Array): + if results.size() > exp_container.get_child_count(): + push_error("unexpected parameters.") + return + for i in range(results.size()): + var result:String = results[i] + exp_container.get_child(i).set_result(result) + +func get_persistent_data() -> Dictionary: + return { + "group_name": group_toggle_button.text, + "expressions": get_expressions(true) + } + +func load_persistent_data(data:Dictionary): + group_toggle_button.text = data["group_name"] + for child in exp_container.get_children(): + child.queue_free() + for exp in data["expressions"]: + var exp_item = exp_item_ui_prefab.instantiate() + exp_container.add_child(exp_item) + exp_item.set_expr(exp) diff --git a/godot/addons/panku_console/modules/expression_monitor/monitor_group_ui.gd.uid b/godot/addons/panku_console/modules/expression_monitor/monitor_group_ui.gd.uid new file mode 100644 index 0000000..2ee52c6 --- /dev/null +++ b/godot/addons/panku_console/modules/expression_monitor/monitor_group_ui.gd.uid @@ -0,0 +1 @@ +uid://pnr5pml8b4y6 diff --git a/godot/addons/panku_console/modules/expression_monitor/monitor_group_ui.tscn b/godot/addons/panku_console/modules/expression_monitor/monitor_group_ui.tscn new file mode 100644 index 0000000..bceed67 --- /dev/null +++ b/godot/addons/panku_console/modules/expression_monitor/monitor_group_ui.tscn @@ -0,0 +1,145 @@ +[gd_scene load_steps=17 format=3 uid="uid://dlnkho5p7p2aq"] + +[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="1_5nvur"] +[ext_resource type="Script" path="res://addons/panku_console/modules/expression_monitor/monitor_group_ui.gd" id="1_b5egi"] +[ext_resource type="Texture2D" uid="uid://ws58gucuygx1" path="res://addons/panku_console/res/icons2/chevron_right.svg" id="1_k5xby"] +[ext_resource type="Texture2D" uid="uid://ecmevhk0tuas" path="res://addons/panku_console/res/icons2/play-1001-svgrepo-com.svg" id="2_wnb5s"] +[ext_resource type="Texture2D" uid="uid://2cjvp0dp8ede" path="res://addons/panku_console/res/icons2/check-svgrepo-com.svg" id="3_h1h1v"] +[ext_resource type="Texture2D" uid="uid://8g5afcuanbl6" path="res://addons/panku_console/res/icons2/close.svg" id="4_2d3kd"] +[ext_resource type="Texture2D" uid="uid://brf6iwx4r6bdd" path="res://addons/panku_console/res/icons2/rename-svgrepo-com.svg" id="4_3tm8i"] +[ext_resource type="Gradient" uid="uid://nr65cgweqh8n" path="res://addons/panku_console/res/green_gradient_1d.tres" id="4_gsqii"] +[ext_resource type="PackedScene" uid="uid://drn5t13m088fb" path="res://addons/panku_console/common/panku_button.tscn" id="5_6smru"] +[ext_resource type="Texture2D" uid="uid://d0k813mm5y0d5" path="res://addons/panku_console/res/icons2/arrow-up-md-svgrepo-com.svg" id="5_xed2e"] +[ext_resource type="Texture2D" uid="uid://cdxbns8lyctqp" path="res://addons/panku_console/res/icons2/arrow-down-svgrepo-com.svg" id="6_168yw"] +[ext_resource type="PackedScene" uid="uid://om8bp40jo1e" path="res://addons/panku_console/modules/expression_monitor/expression_item.tscn" id="9_2py4a"] +[ext_resource type="Texture2D" uid="uid://cngs5d4uosvmt" path="res://addons/panku_console/res/icons2/bin-cancel-delete-remove-trash-garbage-svgrepo-com.svg" id="10_jdwtu"] +[ext_resource type="Texture2D" uid="uid://dprpfr0l5xvmu" path="res://addons/panku_console/res/icons2/add.svg" id="10_l2ajq"] + +[sub_resource type="GradientTexture1D" id="GradientTexture1D_c12ue"] +gradient = ExtResource("4_gsqii") +width = 128 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_fdb5g"] +content_margin_left = 4.0 +content_margin_top = 4.0 +content_margin_right = 4.0 +content_margin_bottom = 4.0 +bg_color = Color(0, 0, 0, 0.12549) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color(0.8, 0.8, 0.8, 0.501961) + +[node name="MonitorGroupUI" type="VBoxContainer"] +offset_right = 431.0 +offset_bottom = 124.0 +theme = ExtResource("1_5nvur") +script = ExtResource("1_b5egi") + +[node name="GroupManager" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="ToggleButton" type="Button" parent="GroupManager"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Default Group" +icon = ExtResource("1_k5xby") +flat = true +alignment = 0 +expand_icon = true + +[node name="TextureRect" type="TextureRect" parent="GroupManager/ToggleButton"] +show_behind_parent = true +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +texture = SubResource("GradientTexture1D_c12ue") +expand_mode = 1 + +[node name="RenameLineEdit" type="LineEdit" parent="GroupManager"] +visible = false +layout_mode = 2 +size_flags_horizontal = 3 +text = "Default Group" + +[node name="StateControlButton" parent="GroupManager" instance=ExtResource("5_6smru")] +layout_mode = 2 + +[node name="TextureRect" parent="GroupManager/StateControlButton/HBoxContainer" index="0"] +texture = ExtResource("2_wnb5s") + +[node name="RenameButton" parent="GroupManager" instance=ExtResource("5_6smru")] +layout_mode = 2 + +[node name="TextureRect" parent="GroupManager/RenameButton/HBoxContainer" index="0"] +texture = ExtResource("4_3tm8i") + +[node name="ConfirmRenameButton" parent="GroupManager" instance=ExtResource("5_6smru")] +visible = false +layout_mode = 2 + +[node name="TextureRect" parent="GroupManager/ConfirmRenameButton/HBoxContainer" index="0"] +texture = ExtResource("3_h1h1v") + +[node name="CancelRenameButton" parent="GroupManager" instance=ExtResource("5_6smru")] +visible = false +layout_mode = 2 + +[node name="TextureRect" parent="GroupManager/CancelRenameButton/HBoxContainer" index="0"] +texture = ExtResource("4_2d3kd") + +[node name="MoveUpButton" parent="GroupManager" instance=ExtResource("5_6smru")] +visible = false +layout_mode = 2 + +[node name="TextureRect" parent="GroupManager/MoveUpButton/HBoxContainer" index="0"] +texture = ExtResource("5_xed2e") + +[node name="MoveDownButton" parent="GroupManager" instance=ExtResource("5_6smru")] +visible = false +layout_mode = 2 + +[node name="TextureRect" parent="GroupManager/MoveDownButton/HBoxContainer" index="0"] +texture = ExtResource("6_168yw") + +[node name="RemoveButton" parent="GroupManager" instance=ExtResource("5_6smru")] +layout_mode = 2 + +[node name="TextureRect" parent="GroupManager/RemoveButton/HBoxContainer" index="0"] +texture = ExtResource("10_jdwtu") + +[node name="PanelContainer" type="PanelContainer" parent="."] +layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_fdb5g") + +[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer"] +layout_mode = 2 + +[node name="ExpressionContainer" type="VBoxContainer" parent="PanelContainer/VBoxContainer"] +layout_mode = 2 + +[node name="VBoxContainer" parent="PanelContainer/VBoxContainer/ExpressionContainer" instance=ExtResource("9_2py4a")] +layout_mode = 2 + +[node name="VBoxContainer2" parent="PanelContainer/VBoxContainer/ExpressionContainer" instance=ExtResource("9_2py4a")] +layout_mode = 2 + +[node name="AddNewExpressionButton" type="Button" parent="PanelContainer/VBoxContainer"] +layout_mode = 2 +text = "Add New Expression" +icon = ExtResource("10_l2ajq") +alignment = 0 +expand_icon = true + +[editable path="GroupManager/StateControlButton"] +[editable path="GroupManager/RenameButton"] +[editable path="GroupManager/ConfirmRenameButton"] +[editable path="GroupManager/CancelRenameButton"] +[editable path="GroupManager/MoveUpButton"] +[editable path="GroupManager/MoveDownButton"] +[editable path="GroupManager/RemoveButton"] diff --git a/godot/addons/panku_console/modules/expression_monitor/monitor_groups_ui.gd b/godot/addons/panku_console/modules/expression_monitor/monitor_groups_ui.gd new file mode 100644 index 0000000..c7349e4 --- /dev/null +++ b/godot/addons/panku_console/modules/expression_monitor/monitor_groups_ui.gd @@ -0,0 +1,50 @@ +extends VBoxContainer + +const MonitorGroup:GDScript = preload("./monitor_group_ui.gd") +const group_prefab:PackedScene = preload("./monitor_group_ui.tscn") + +@onready var groups_container:Control = $Groups +@onready var add_group_button:Button = $AddGroupButton + +func _ready(): + add_group_button.pressed.connect(add_group) + +func get_expressions_by_group() -> Array: + var result := [] + for child in groups_container.get_children(): + var group:MonitorGroup = child + result.append(group.get_expressions()) + return result + +func set_results_by_group(results:Array): + if results.size() > groups_container.get_child_count(): + push_error("unexpected parameters.") + return + for i in range(results.size()): + groups_container.get_child(i).set_results(results[i]) + +func add_group() -> MonitorGroup: + var group_ui:Node = group_prefab.instantiate() + groups_container.add_child(group_ui) + group_ui.group_move_up.connect( + func(): + groups_container.move_child(group_ui, group_ui.get_index() - 1) + ) + group_ui.group_move_down.connect( + func(): + groups_container.move_child(group_ui, group_ui.get_index() + 1) + ) + return group_ui + +func get_persistent_data() -> Array: + var data := [] + for child in groups_container.get_children(): + data.append(child.get_persistent_data()) + return data + +func load_persistent_data(data:Array): + for child in groups_container.get_children(): + child.queue_free() + for group_data in data: + var group_ui = add_group() + group_ui.load_persistent_data(group_data) diff --git a/godot/addons/panku_console/modules/expression_monitor/monitor_groups_ui.gd.uid b/godot/addons/panku_console/modules/expression_monitor/monitor_groups_ui.gd.uid new file mode 100644 index 0000000..97b54cb --- /dev/null +++ b/godot/addons/panku_console/modules/expression_monitor/monitor_groups_ui.gd.uid @@ -0,0 +1 @@ +uid://c7nca3l6nwgyw diff --git a/godot/addons/panku_console/modules/expression_monitor/monitor_groups_ui.tscn b/godot/addons/panku_console/modules/expression_monitor/monitor_groups_ui.tscn new file mode 100644 index 0000000..3f67e27 --- /dev/null +++ b/godot/addons/panku_console/modules/expression_monitor/monitor_groups_ui.tscn @@ -0,0 +1,31 @@ +[gd_scene load_steps=5 format=3 uid="uid://ctgf7kewoa1cn"] + +[ext_resource type="Script" path="res://addons/panku_console/modules/expression_monitor/monitor_groups_ui.gd" id="1_8ojgn"] +[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="1_gc4dk"] +[ext_resource type="PackedScene" uid="uid://dlnkho5p7p2aq" path="res://addons/panku_console/modules/expression_monitor/monitor_group_ui.tscn" id="1_l15o5"] +[ext_resource type="Texture2D" uid="uid://dprpfr0l5xvmu" path="res://addons/panku_console/res/icons2/add.svg" id="4_utrvo"] + +[node name="MonitorGroupsUI" type="VBoxContainer"] +offset_right = 411.0 +offset_bottom = 309.0 +theme = ExtResource("1_gc4dk") +script = ExtResource("1_8ojgn") + +[node name="Groups" type="VBoxContainer" parent="."] +layout_mode = 2 + +[node name="MonitorGroupUI" parent="Groups" instance=ExtResource("1_l15o5")] +layout_mode = 2 + +[node name="MonitorGroupUI2" parent="Groups" instance=ExtResource("1_l15o5")] +layout_mode = 2 + +[node name="MonitorGroupUI3" parent="Groups" instance=ExtResource("1_l15o5")] +layout_mode = 2 + +[node name="AddGroupButton" type="Button" parent="."] +layout_mode = 2 +text = "Add New Group" +icon = ExtResource("4_utrvo") +alignment = 0 +expand_icon = true diff --git a/godot/addons/panku_console/modules/general_settings/env.gd b/godot/addons/panku_console/modules/general_settings/env.gd new file mode 100644 index 0000000..27c1092 --- /dev/null +++ b/godot/addons/panku_console/modules/general_settings/env.gd @@ -0,0 +1,4 @@ +var _module:PankuModule + +func open(): + _module.open_settings_window() diff --git a/godot/addons/panku_console/modules/general_settings/env.gd.uid b/godot/addons/panku_console/modules/general_settings/env.gd.uid new file mode 100644 index 0000000..304b89e --- /dev/null +++ b/godot/addons/panku_console/modules/general_settings/env.gd.uid @@ -0,0 +1 @@ +uid://b0m1kd1d2kjyc diff --git a/godot/addons/panku_console/modules/general_settings/module.gd b/godot/addons/panku_console/modules/general_settings/module.gd new file mode 100644 index 0000000..4d15ea7 --- /dev/null +++ b/godot/addons/panku_console/modules/general_settings/module.gd @@ -0,0 +1,68 @@ +class_name PankuModuleGeneralSettings extends PankuModule + +var window:PankuLynxWindow + +func open_settings_window(): + if window: return + # create a new exporter window + window = core.create_data_controller_window.call( + core.module_manager.get_module_option_objects() + ) + window.set_window_title_text("General Settings") + load_window_data(window) + window.show_window() + window.window_closed.connect( + func(): + save_window_data(window) + window = null + ) + +# Taken from https://github.com/godotengine/godot/blob/master/editor/editor_settings.cpp#L1539 +static func get_auto_display_scale() -> float: + var flag := false + match OS.get_name(): + "macOS": + flag = true + "Linux", "FreeBSD", "NetBSD", "OpenBSD", "BSD": + if DisplayServer.get_name() == "Wayland": + flag = true + "Android": + flag = true + "iOS": + flag = true + if flag: + return DisplayServer.screen_get_max_scale() + + var screen := DisplayServer.window_get_current_screen() + + if (DisplayServer.screen_get_size(screen) == Vector2i()): + # Invalid screen size, skip. + return 1.0 + + # Use the smallest dimension to use a correct display scale on portrait displays. + var smallest_dimension = min(DisplayServer.screen_get_size().x, DisplayServer.screen_get_size().y) + if DisplayServer.screen_get_dpi(screen) >= 192 and smallest_dimension >= 1400: + # hiDPI display. + return 2.0 + elif smallest_dimension >= 1700: + # Likely a hiDPI display, but we aren't certain due to the returned DPI. + # Use an intermediate scale to handle this situation. + return 1.5 + elif smallest_dimension <= 800: + # Small loDPI display. Use a smaller display scale so that editor elements fit more easily. + # Icons won't look great, but this is better than having editor elements overflow from its window. + return 0.75 + return 1.0 + +func init_module(): + # load settings + get_module_opt().window_blur_effect = load_module_data("window_blur_effect", true) + get_module_opt().window_base_color = load_module_data("window_base_color", Color("#000c1880")) + get_module_opt().enable_os_window = load_module_data("enable_os_window", false) + get_module_opt().os_window_bg_color = load_module_data("os_window_bg_color", Color(0, 0, 0, 0)) + get_module_opt().global_font_size = load_module_data("global_font_size", int(16 * get_auto_display_scale())) + +func quit_module(): + super.quit_module() + if window: + save_window_data(window) diff --git a/godot/addons/panku_console/modules/general_settings/module.gd.uid b/godot/addons/panku_console/modules/general_settings/module.gd.uid new file mode 100644 index 0000000..555916f --- /dev/null +++ b/godot/addons/panku_console/modules/general_settings/module.gd.uid @@ -0,0 +1 @@ +uid://bqx8byqbawedh diff --git a/godot/addons/panku_console/modules/general_settings/opt.gd b/godot/addons/panku_console/modules/general_settings/opt.gd new file mode 100644 index 0000000..4b89d96 --- /dev/null +++ b/godot/addons/panku_console/modules/general_settings/opt.gd @@ -0,0 +1,49 @@ +extends ModuleOptions + +@export_group("general_settings") + +@export var window_blur_effect:bool = true: + set(v): + PankuLynxWindow.lynx_window_shader_material.set("shader_parameter/lod", 4.0 if v else 0.0) + get: + return PankuLynxWindow.lynx_window_shader_material.get("shader_parameter/lod") > 0.0 + +@export var window_base_color:Color = Color(0.0, 0.0, 0.0, 0.1): + set(v): + PankuLynxWindow.lynx_window_shader_material.set("shader_parameter/modulate", v) + get: + return PankuLynxWindow.lynx_window_shader_material.get("shader_parameter/modulate") + +@export var enable_os_window := false: + set(v): + _module.core.windows_manager.enable_os_popup_btns(v) + get: + return _module.core.windows_manager.os_popup_btn_enabled + +@export var os_window_bg_color:Color: + set(v): + _module.core.windows_manager.set_os_window_bg_color(v) + get: + return _module.core.windows_manager.os_window_bg_color + +@export var global_font_size:int: + set(v): + _module.core.windows_manager.theme.default_font_size = v + get: + return _module.core.windows_manager.theme.default_font_size + +@export var export_comment_auto_global_font_size = ( + "Adjust global font size automatically according to your device DPI" +) + +@export var export_button_auto_global_font_size := "Auto Global Font Size" +func auto_global_font_size(): + global_font_size = int(16 * _module.get_auto_display_scale()) + +@export var export_button_report_bugs := "Report Bugs" +func report_bugs(): + OS.shell_open("https://github.com/Ark2000/PankuConsole/issues") + +@export var export_button_suggest_features := "Suggest Features" +func suggest_features(): + OS.shell_open("https://github.com/Ark2000/PankuConsole/issues") diff --git a/godot/addons/panku_console/modules/general_settings/opt.gd.uid b/godot/addons/panku_console/modules/general_settings/opt.gd.uid new file mode 100644 index 0000000..dd20c02 --- /dev/null +++ b/godot/addons/panku_console/modules/general_settings/opt.gd.uid @@ -0,0 +1 @@ +uid://bkxa6b0jf83y3 diff --git a/godot/addons/panku_console/modules/history_manager/env.gd b/godot/addons/panku_console/modules/history_manager/env.gd new file mode 100644 index 0000000..dae4497 --- /dev/null +++ b/godot/addons/panku_console/modules/history_manager/env.gd @@ -0,0 +1,4 @@ +var _module:PankuModule + +func open() -> void: + _module.open_window() diff --git a/godot/addons/panku_console/modules/history_manager/env.gd.uid b/godot/addons/panku_console/modules/history_manager/env.gd.uid new file mode 100644 index 0000000..ff67f05 --- /dev/null +++ b/godot/addons/panku_console/modules/history_manager/env.gd.uid @@ -0,0 +1 @@ +uid://cr2kkri0xrsqv diff --git a/godot/addons/panku_console/modules/history_manager/exp_history.gd b/godot/addons/panku_console/modules/history_manager/exp_history.gd new file mode 100644 index 0000000..96926d3 --- /dev/null +++ b/godot/addons/panku_console/modules/history_manager/exp_history.gd @@ -0,0 +1,206 @@ +extends Control + +@onready var console:PankuConsole + +const exp_item_prefab = preload("./exp_history_item.tscn") +const CFG_EXP_HISTORY = "exp_history" + +@export var item_container:VBoxContainer +@export var copy_button:Button +@export var monitor_button:Button +@export var favorite_button:Button +@export var delete_button:Button +@export var reverse_select_button:Button +@export var prev_page_button:Button +@export var next_page_button:Button +@export var first_page_button:Button +@export var last_page_button:Button +@export var page_ledit:LineEdit +@export var page_label:Label + +var current_page := 1 +var all_pages := 1 +var items_per_page := 5 +#[checked:bool, fav:bool, exp:String] +var item_data := [] + +func _ready(): + load_data() + copy_button.pressed.connect(copy_selected) + monitor_button.pressed.connect(monitor_selected) + favorite_button.pressed.connect(star_selected) + delete_button.pressed.connect(remove_selected) + reverse_select_button.pressed.connect(invert_selected) + prev_page_button.pressed.connect( + func(): + current_page -= 1 + reload() + ) + next_page_button.pressed.connect( + func(): + current_page += 1 + reload() + ) + first_page_button.pressed.connect( + func(): + current_page = 1; + reload() + ) + last_page_button.pressed.connect( + func(): + current_page = 99999999; + reload() + ) + page_ledit.text_submitted.connect( + func(_new_text:String): + current_page = page_ledit.text.to_int() + reload() + ) + page_ledit.focus_exited.connect( + func(): + current_page = page_ledit.text.to_int() + reload() + ) + create_tween().set_loops().set_process_mode(Tween.TWEEN_PROCESS_PHYSICS).tween_callback( + func(): + if !is_visible_in_tree(): return + if item_container.get_child_count() < 1: return + var item_height = item_container.get_child(0).size.y + var item_gap = item_container.get("theme_override_constants/separation") + var container_height = item_container.get_parent().size.y + var _items_per_page = floor((container_height + item_gap) / (item_height + item_gap)) + _items_per_page = max(5, _items_per_page) + if _items_per_page != items_per_page: + items_per_page = _items_per_page + reload() + ).set_delay(0.1) + + visibility_changed.connect( + func(): + if is_visible_in_tree(): reload() + ) + +func reload(): + #calculate pages + all_pages = max(1, ceil(1.0 * item_data.size() / items_per_page)) + current_page = clamp(current_page, 1, all_pages) + page_label.text = " / %d" % all_pages + page_ledit.text = str(current_page) + + #remove existing list items + var start_idx := (current_page - 1) * items_per_page + var end_idx := mini(start_idx + items_per_page, item_data.size()) + for c in item_container.get_children(): + c.queue_free() + + #add new list items + for i in range(start_idx, end_idx): + var list_item = exp_item_prefab.instantiate() + list_item.checkbox.button_pressed = item_data[i][0] + list_item.fav_icon.visible = item_data[i][1] + list_item.line_edit.text = item_data[i][2] + list_item.checkbox.toggled.connect( + func(val:bool): item_data[i][0] = val + ) + list_item.line_edit.text_changed.connect( + func(val:String): item_data[i][2] = val + ) + item_container.add_child(list_item) + +func copy_selected(): + var result = combine_selected() + if result != "": + DisplayServer.clipboard_set(result) + console.notify("Combined expression has beed added to clipboard!") + clear_selected() + +func monitor_selected(): + var result = combine_selected() + if result != "": + pass + # console.add_monitor_window(result, 0.1).centered() + clear_selected() + +func combine_selected() -> String: + var selected_exp = [] + var combined_exp = "" + for d in item_data: + if !d[0]: continue + selected_exp.append(d[2]) + if selected_exp.size() > 8: + console.notify("Maximum 8 items!") + return "" + if selected_exp.size() == 0: + console.notify("Nothing to copy!") + return "" + elif selected_exp.size() == 1: + combined_exp = selected_exp[0] + else: + for i in range(selected_exp.size()): + selected_exp[i] = "'%s: ' + str(%s)" % [selected_exp[i], selected_exp[i]] + combined_exp = " + '\\n' + ".join(PackedStringArray(selected_exp)) + return combined_exp + +func clear_selected(): + for d in item_data: + d[0] = false + reload() + +func invert_selected(): + for d in item_data: + d[0] = !d[0] + reload() + +func star_selected(): + var flag := true + for d in item_data: + if !d[0]: continue + d[1] = !d[1] + d[0] = false + flag = false + if flag: + console.notify("No selected items!") + return + + #sort favorite + var fav_id := 0 + var fav_items := [] + var items := [] + for d in item_data: + if d[1]: fav_items.append(d) + else: items.append(d) + item_data = fav_items + items + reload() + +func remove_selected(): + var result = [] + for d in item_data: + if d[0]: continue + result.append(d) + if item_data.size() == result.size(): + console.notify("No selected items!") + return + console.notify("Removed %d items." % (item_data.size() - result.size())) + item_data = result + reload() + +func load_data(): + #get saved data from cfg + var cfg = PankuConfig.get_config() + item_data = cfg.get(CFG_EXP_HISTORY, []) + +func save_data(): + var cfg = PankuConfig.get_config() + cfg[CFG_EXP_HISTORY] = item_data + PankuConfig.set_config(cfg) + +func _notification(what): + if what == NOTIFICATION_WM_CLOSE_REQUEST: + save_data() + +func add_history(exp:String): + #ignore consecutive same + if item_data.size() > 0 and exp == item_data.back()[2]: + return + item_data.append([false, false, exp]) + if is_visible_in_tree(): reload() diff --git a/godot/addons/panku_console/modules/history_manager/exp_history.gd.uid b/godot/addons/panku_console/modules/history_manager/exp_history.gd.uid new file mode 100644 index 0000000..876b83d --- /dev/null +++ b/godot/addons/panku_console/modules/history_manager/exp_history.gd.uid @@ -0,0 +1 @@ +uid://nsybsat5vf4e diff --git a/godot/addons/panku_console/modules/history_manager/exp_history.tscn b/godot/addons/panku_console/modules/history_manager/exp_history.tscn new file mode 100644 index 0000000..2c485ef --- /dev/null +++ b/godot/addons/panku_console/modules/history_manager/exp_history.tscn @@ -0,0 +1,149 @@ +[gd_scene load_steps=4 format=3 uid="uid://fladd1y6sa1j"] + +[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="1_q7hjy"] +[ext_resource type="Script" path="res://addons/panku_console/modules/history_manager/exp_history.gd" id="2_kgk33"] +[ext_resource type="PackedScene" uid="uid://dhsvbbxqlb1xy" path="res://addons/panku_console/modules/history_manager/exp_history_item.tscn" id="3_wac0s"] + +[node name="ExpHistory" type="Control" node_paths=PackedStringArray("item_container", "copy_button", "monitor_button", "favorite_button", "delete_button", "reverse_select_button", "prev_page_button", "next_page_button", "first_page_button", "last_page_button", "page_ledit", "page_label")] +clip_contents = true +layout_mode = 3 +anchors_preset = 0 +offset_left = 227.0 +offset_top = 149.0 +offset_right = 634.0 +offset_bottom = 437.0 +theme = ExtResource("1_q7hjy") +script = ExtResource("2_kgk33") +item_container = NodePath("VBoxContainer2/Control/ItemContainer") +copy_button = NodePath("VBoxContainer2/HBoxContainer/CopyButton") +monitor_button = NodePath("VBoxContainer2/HBoxContainer/MonitorButton") +favorite_button = NodePath("VBoxContainer2/HBoxContainer/FavoriteButton") +delete_button = NodePath("VBoxContainer2/HBoxContainer/DeleteButton") +reverse_select_button = NodePath("VBoxContainer2/HBoxContainer/InvertSelect") +prev_page_button = NodePath("VBoxContainer2/HBoxContainer2/PrevPageButton") +next_page_button = NodePath("VBoxContainer2/HBoxContainer2/NextPageButton") +first_page_button = NodePath("VBoxContainer2/HBoxContainer2/FirstpageButton") +last_page_button = NodePath("VBoxContainer2/HBoxContainer2/LastPageButton") +page_ledit = NodePath("VBoxContainer2/HBoxContainer2/PageNumberEdit") +page_label = NodePath("VBoxContainer2/HBoxContainer2/TotalPageLabel") +metadata/_edit_vertical_guides_ = [161.838] + +[node name="Panel" type="Panel" parent="."] +visible = false +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="VBoxContainer2" type="VBoxContainer" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 4.0 +offset_top = 4.0 +offset_right = -4.0 +offset_bottom = -4.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer2"] +layout_mode = 2 + +[node name="CopyButton" type="Button" parent="VBoxContainer2/HBoxContainer"] +visible = false +layout_mode = 2 +size_flags_horizontal = 3 +text = "Copy" + +[node name="MonitorButton" type="Button" parent="VBoxContainer2/HBoxContainer"] +visible = false +layout_mode = 2 +size_flags_horizontal = 3 +text = "Monitor" + +[node name="FavoriteButton" type="Button" parent="VBoxContainer2/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Favorite" + +[node name="DeleteButton" type="Button" parent="VBoxContainer2/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Delete" + +[node name="InvertSelect" type="Button" parent="VBoxContainer2/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Invert Select" + +[node name="HSeparator2" type="HSeparator" parent="VBoxContainer2"] +layout_mode = 2 + +[node name="Control" type="Control" parent="VBoxContainer2"] +clip_contents = true +layout_mode = 2 +size_flags_vertical = 3 + +[node name="ItemContainer" type="VBoxContainer" parent="VBoxContainer2/Control"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_vertical = 3 +theme_override_constants/separation = 2 + +[node name="ExpItem" parent="VBoxContainer2/Control/ItemContainer" instance=ExtResource("3_wac0s")] +layout_mode = 2 + +[node name="ExpItem2" parent="VBoxContainer2/Control/ItemContainer" instance=ExtResource("3_wac0s")] +layout_mode = 2 + +[node name="ExpItem3" parent="VBoxContainer2/Control/ItemContainer" instance=ExtResource("3_wac0s")] +layout_mode = 2 + +[node name="HSeparator" type="HSeparator" parent="VBoxContainer2"] +layout_mode = 2 + +[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer2"] +layout_mode = 2 + +[node name="FirstpageButton" type="Button" parent="VBoxContainer2/HBoxContainer2"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "<<<" + +[node name="PrevPageButton" type="Button" parent="VBoxContainer2/HBoxContainer2"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "<" + +[node name="PageNumberEdit" type="LineEdit" parent="VBoxContainer2/HBoxContainer2"] +layout_mode = 2 +text = "1" + +[node name="TotalPageLabel" type="Label" parent="VBoxContainer2/HBoxContainer2"] +layout_mode = 2 +text = "/ 10" +vertical_alignment = 1 + +[node name="NextPageButton" type="Button" parent="VBoxContainer2/HBoxContainer2"] +layout_mode = 2 +size_flags_horizontal = 3 +text = ">" + +[node name="LastPageButton" type="Button" parent="VBoxContainer2/HBoxContainer2"] +layout_mode = 2 +size_flags_horizontal = 3 +text = ">>>" + +[node name="HFlowContainer" type="HFlowContainer" parent="."] +layout_mode = 2 +offset_right = 399.0 +size_flags_vertical = 0 diff --git a/godot/addons/panku_console/modules/history_manager/exp_history_item.gd b/godot/addons/panku_console/modules/history_manager/exp_history_item.gd new file mode 100644 index 0000000..23c6e27 --- /dev/null +++ b/godot/addons/panku_console/modules/history_manager/exp_history_item.gd @@ -0,0 +1,5 @@ +extends HBoxContainer + +@export var checkbox:CheckBox +@export var fav_icon:TextureRect +@export var line_edit:LineEdit diff --git a/godot/addons/panku_console/modules/history_manager/exp_history_item.gd.uid b/godot/addons/panku_console/modules/history_manager/exp_history_item.gd.uid new file mode 100644 index 0000000..0878ea8 --- /dev/null +++ b/godot/addons/panku_console/modules/history_manager/exp_history_item.gd.uid @@ -0,0 +1 @@ +uid://dy7ywh6we3xug diff --git a/godot/addons/panku_console/modules/history_manager/exp_history_item.tscn b/godot/addons/panku_console/modules/history_manager/exp_history_item.tscn new file mode 100644 index 0000000..a0e3378 --- /dev/null +++ b/godot/addons/panku_console/modules/history_manager/exp_history_item.tscn @@ -0,0 +1,27 @@ +[gd_scene load_steps=4 format=3 uid="uid://dhsvbbxqlb1xy"] + +[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="1_rsfup"] +[ext_resource type="Script" path="res://addons/panku_console/modules/history_manager/exp_history_item.gd" id="2_a3mfr"] +[ext_resource type="Texture2D" uid="uid://hf6h8otb8qkv" path="res://addons/panku_console/res/icons2/favorite.svg" id="3_1odvn"] + +[node name="ExpItem" type="HBoxContainer" node_paths=PackedStringArray("checkbox", "fav_icon", "line_edit")] +offset_right = 155.0 +offset_bottom = 20.0 +theme = ExtResource("1_rsfup") +script = ExtResource("2_a3mfr") +checkbox = NodePath("CheckBox") +fav_icon = NodePath("TextureRect") +line_edit = NodePath("LineEdit") + +[node name="CheckBox" type="CheckBox" parent="."] +layout_mode = 2 +flat = true + +[node name="TextureRect" type="TextureRect" parent="."] +layout_mode = 2 +texture = ExtResource("3_1odvn") +stretch_mode = 3 + +[node name="LineEdit" type="LineEdit" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 diff --git a/godot/addons/panku_console/modules/history_manager/module.gd b/godot/addons/panku_console/modules/history_manager/module.gd new file mode 100644 index 0000000..24a7607 --- /dev/null +++ b/godot/addons/panku_console/modules/history_manager/module.gd @@ -0,0 +1,26 @@ +class_name PankuModuleHistoryManager extends PankuModule + +var window:PankuLynxWindow + +func init_module(): + # setup ui + var ui = preload("./exp_history.tscn").instantiate() + ui.console = core + core.new_expression_entered.connect( + func(expression, result): + ui.add_history(expression) + ) + + # bind window + window = core.windows_manager.create_window(ui) + add_auto_save_hook(window) + window.queue_free_on_close = false + window.set_window_title_text("History Manager") + load_window_data(window) + +func quit_module(): + super.quit_module() + save_window_data(window) + +func open_window(): + window.show_window() diff --git a/godot/addons/panku_console/modules/history_manager/module.gd.uid b/godot/addons/panku_console/modules/history_manager/module.gd.uid new file mode 100644 index 0000000..beea25c --- /dev/null +++ b/godot/addons/panku_console/modules/history_manager/module.gd.uid @@ -0,0 +1 @@ +uid://du280gsd10ts4 diff --git a/godot/addons/panku_console/modules/history_manager/opt.gd b/godot/addons/panku_console/modules/history_manager/opt.gd new file mode 100644 index 0000000..0721510 --- /dev/null +++ b/godot/addons/panku_console/modules/history_manager/opt.gd @@ -0,0 +1,7 @@ +extends ModuleOptions + +@export_group("history_manager") + +@export var export_button_open_window := "Open Window" +func open_window(): + _module.open_window() diff --git a/godot/addons/panku_console/modules/history_manager/opt.gd.uid b/godot/addons/panku_console/modules/history_manager/opt.gd.uid new file mode 100644 index 0000000..d79ff21 --- /dev/null +++ b/godot/addons/panku_console/modules/history_manager/opt.gd.uid @@ -0,0 +1 @@ +uid://bf7hmiyq45wgk diff --git a/godot/addons/panku_console/modules/interactive_shell/console_logs/console_logs.gd b/godot/addons/panku_console/modules/interactive_shell/console_logs/console_logs.gd new file mode 100644 index 0000000..5010582 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/console_logs/console_logs.gd @@ -0,0 +1,29 @@ +extends MarginContainer + +@export var rlabel:RichTextLabel + +#not sure about the performance +const MAX_LOGS = 400 + +func _ready(): + rlabel.meta_clicked.connect( + func(meta): + OS.shell_open(meta) + ) + +func add_log(bbcode:String): + rlabel.text += (bbcode + "\n") + +func clear(): + rlabel.text = "" + +func set_font_size(sz:int): + rlabel.set("theme_override_font_sizes/normal_font_size", sz) + rlabel.set("theme_override_font_sizes/bold_font_size", sz) + rlabel.set("theme_override_font_sizes/italics_font_size", sz) + rlabel.set("theme_override_font_sizes/bold_italics_font_size", sz) + rlabel.set("theme_override_font_sizes/mono_font_size", sz) + +func get_font_size() -> int: + #return rlabel.get("theme_override_font_sizes/normal_font_size") + return 12 diff --git a/godot/addons/panku_console/modules/interactive_shell/console_logs/console_logs.gd.uid b/godot/addons/panku_console/modules/interactive_shell/console_logs/console_logs.gd.uid new file mode 100644 index 0000000..9940ee6 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/console_logs/console_logs.gd.uid @@ -0,0 +1 @@ +uid://bjf0ovt7iyqe8 diff --git a/godot/addons/panku_console/modules/interactive_shell/console_logs/console_logs.tscn b/godot/addons/panku_console/modules/interactive_shell/console_logs/console_logs.tscn new file mode 100644 index 0000000..41232a5 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/console_logs/console_logs.tscn @@ -0,0 +1,48 @@ +[gd_scene load_steps=4 format=3 uid="uid://nynkaa0igrh5"] + +[ext_resource type="Script" path="res://addons/panku_console/modules/interactive_shell/console_logs/console_logs.gd" id="1_3r4hk"] +[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="1_b2qej"] +[ext_resource type="Script" path="res://addons/panku_console/common/smooth_scroll/smooth_scroll.gd" id="2_46ya8"] + +[node name="ConsoleLogs" type="MarginContainer" node_paths=PackedStringArray("rlabel")] +clip_contents = true +offset_right = 365.0 +offset_bottom = 357.0 +theme = ExtResource("1_b2qej") +theme_override_constants/margin_left = 8 +theme_override_constants/margin_top = 8 +theme_override_constants/margin_right = 8 +theme_override_constants/margin_bottom = 8 +script = ExtResource("1_3r4hk") +rlabel = NodePath("SmoothScrollContainer/HBoxContainer/Control/RichTextLabel") + +[node name="SmoothScrollContainer" type="PanelContainer" parent="." node_paths=PackedStringArray("clip_container", "scrollbar")] +self_modulate = Color(1, 1, 1, 0) +layout_mode = 2 +script = ExtResource("2_46ya8") +clip_container = NodePath("HBoxContainer/Control") +scrollbar = NodePath("HBoxContainer/VScrollBar") + +[node name="HBoxContainer" type="HBoxContainer" parent="SmoothScrollContainer"] +layout_mode = 2 + +[node name="Control" type="Control" parent="SmoothScrollContainer/HBoxContainer"] +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="RichTextLabel" type="RichTextLabel" parent="SmoothScrollContainer/HBoxContainer/Control"] +layout_mode = 1 +anchors_preset = 10 +anchor_right = 1.0 +grow_horizontal = 2 +focus_mode = 2 +bbcode_enabled = true +fit_content = true +context_menu_enabled = true +selection_enabled = true + +[node name="VScrollBar" type="VScrollBar" parent="SmoothScrollContainer/HBoxContainer"] +layout_mode = 2 +page = 20.0 +value = 80.0 diff --git a/godot/addons/panku_console/modules/interactive_shell/console_ui/help_bar.tscn b/godot/addons/panku_console/modules/interactive_shell/console_ui/help_bar.tscn new file mode 100644 index 0000000..9582038 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/console_ui/help_bar.tscn @@ -0,0 +1,21 @@ +[gd_scene load_steps=2 format=3 uid="uid://cbijhl1nhy64n"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_c7j4l"] +bg_color = Color(0.180392, 0.32549, 0.403922, 1) + +[node name="HelpBar" type="PanelContainer"] +anchors_preset = 12 +anchor_top = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_top = -50.0 +offset_bottom = -26.0 +grow_horizontal = 2 +grow_vertical = 0 + +[node name="Label" type="Label" parent="."] +layout_mode = 2 +theme_override_styles/normal = SubResource("StyleBoxFlat_c7j4l") +text = "[Help] This is hint!" +vertical_alignment = 1 +clip_text = true diff --git a/godot/addons/panku_console/modules/interactive_shell/console_ui/panku_console_ui.gd b/godot/addons/panku_console/modules/interactive_shell/console_ui/panku_console_ui.gd new file mode 100644 index 0000000..f7e3942 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/console_ui/panku_console_ui.gd @@ -0,0 +1,54 @@ +extends Control + +@onready var _console_logs = $HBoxContainer/Control/VBoxContainer/ConsoleLogs +@onready var _repl := $REPL +@onready var side_button_separator:Node = $HBoxContainer/SideButtons/Space +@onready var side_buttons:Control = $HBoxContainer/SideButtons +@onready var side_separator:Control = $HBoxContainer/VSeparator + +const side_button_packed := preload("res://addons/panku_console/common/panku_button.tscn") +const side_menu_config_file_path := "res://addons/panku_console/modules/interactive_shell/side_menu_config.json" + +var enable_side_menu := true + +func _ready() -> void: + _repl.output.connect(output) + + var config_str := FileAccess.get_file_as_string(side_menu_config_file_path) + var cfg:Dictionary = JSON.parse_string(config_str) + + for item in cfg["items.top"]: + add_side_button(item["command"], load(item["icon"]), item["text"]) + for item in cfg["items.bottom"]: + add_side_button(item["command"], load(item["icon"]), item["text"], false) + + resized.connect( + func(): + var vis := side_buttons.get_minimum_size().y < size.y + vis = vis and enable_side_menu + side_buttons.visible = vis + side_separator.visible = vis + ) + +## Output [code]any[/code] to the console +func output(any): + var text = str(any) + _console_logs.add_log(text) + +func clear_output(): + _console_logs.clear() + +func add_side_button(exp:String, icon:Texture2D, text:String, top:= true): + var new_button:PankuButton = side_button_packed.instantiate() + new_button.icon = icon + side_button_separator.get_parent().add_child(new_button) + side_button_separator.get_parent().move_child( + new_button, + side_button_separator.get_index() + int(!top) + ) + new_button.pressed.connect( + func(): + _repl._module.core.gd_exprenv.execute(exp) + ) + new_button.set_meta("text", " " + text) + new_button.text = "" diff --git a/godot/addons/panku_console/modules/interactive_shell/console_ui/panku_console_ui.gd.uid b/godot/addons/panku_console/modules/interactive_shell/console_ui/panku_console_ui.gd.uid new file mode 100644 index 0000000..42c52a6 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/console_ui/panku_console_ui.gd.uid @@ -0,0 +1 @@ +uid://qh5xix4av8cw diff --git a/godot/addons/panku_console/modules/interactive_shell/console_ui/panku_console_ui.tscn b/godot/addons/panku_console/modules/interactive_shell/console_ui/panku_console_ui.tscn new file mode 100644 index 0000000..d3bc7b6 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/console_ui/panku_console_ui.tscn @@ -0,0 +1,111 @@ +[gd_scene load_steps=12 format=3 uid="uid://bqfm16y5vcgl3"] + +[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="1_8mhrg"] +[ext_resource type="Script" path="res://addons/panku_console/modules/interactive_shell/console_ui/panku_console_ui.gd" id="1_aab8v"] +[ext_resource type="PackedScene" uid="uid://nynkaa0igrh5" path="res://addons/panku_console/modules/interactive_shell/console_logs/console_logs.tscn" id="1_jb1ae"] +[ext_resource type="PackedScene" uid="uid://bme8twac4ick5" path="res://addons/panku_console/modules/interactive_shell/input_field/input_area.tscn" id="2_w7j54"] +[ext_resource type="PackedScene" uid="uid://b3jf18wonocnv" path="res://addons/panku_console/modules/interactive_shell/hints_list/hints_list.tscn" id="3_qw8p4"] +[ext_resource type="PackedScene" uid="uid://drn5t13m088fb" path="res://addons/panku_console/common/panku_button.tscn" id="4_5x5gm"] +[ext_resource type="PackedScene" uid="uid://ca0bkchv6nsrb" path="res://addons/panku_console/modules/interactive_shell/console_ui/repl.tscn" id="4_ihf0b"] +[ext_resource type="Script" path="res://addons/panku_console/modules/interactive_shell/console_ui/side_buttons_controller.gd" id="5_2te5e"] +[ext_resource type="PackedScene" uid="uid://cbijhl1nhy64n" path="res://addons/panku_console/modules/interactive_shell/console_ui/help_bar.tscn" id="10_0thy6"] +[ext_resource type="Script" path="res://addons/panku_console/modules/interactive_shell/console_ui/remote_control_node.gd" id="11_epqvn"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_i3l80"] +bg_color = Color(0.6, 0.6, 0.6, 0.435294) +border_width_left = 1 +border_color = Color(0.8, 0.8, 0.8, 0.352941) + +[node name="PankuConsoleUI" type="Control"] +clip_contents = true +custom_minimum_size = Vector2(0, 1) +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme = ExtResource("1_8mhrg") +script = ExtResource("1_aab8v") + +[node name="REPL" parent="." node_paths=PackedStringArray("_input_area", "_hints", "_helpbar", "_helpbar_label") instance=ExtResource("4_ihf0b")] +_input_area = NodePath("../HBoxContainer/Control/VBoxContainer/InputArea") +_hints = NodePath("../HBoxContainer/Control/Layer2/HintsList") +_helpbar = NodePath("../HBoxContainer/Control/Layer2/HelpBar") +_helpbar_label = NodePath("../HBoxContainer/Control/Layer2/HelpBar/Label") + +[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 +theme_override_constants/separation = 0 + +[node name="SideButtons" type="VBoxContainer" parent="HBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 0 + +[node name="ControllerButton" parent="HBoxContainer/SideButtons" instance=ExtResource("4_5x5gm")] +layout_mode = 2 +script = ExtResource("5_2te5e") + +[node name="Space" type="Control" parent="HBoxContainer/SideButtons"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="VSeparator" type="VSeparator" parent="HBoxContainer"] +layout_mode = 2 +theme_override_styles/separator = SubResource("StyleBoxFlat_i3l80") + +[node name="Control" type="Control" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer/Control"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/separation = 0 + +[node name="ConsoleLogs" parent="HBoxContainer/Control/VBoxContainer" instance=ExtResource("1_jb1ae")] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="InputArea" parent="HBoxContainer/Control/VBoxContainer" instance=ExtResource("2_w7j54")] +layout_mode = 2 + +[node name="Layer2" type="VBoxContainer" parent="HBoxContainer/Control"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +theme_override_constants/separation = 0 +alignment = 2 + +[node name="HintsList" parent="HBoxContainer/Control/Layer2" instance=ExtResource("3_qw8p4")] +layout_mode = 2 +size_flags_vertical = 3 +mouse_filter = 2 + +[node name="HelpBar" parent="HBoxContainer/Control/Layer2" instance=ExtResource("10_0thy6")] +layout_mode = 2 +mouse_filter = 2 + +[node name="RemoteControl" type="ColorRect" parent="HBoxContainer/Control/Layer2" node_paths=PackedStringArray("target_control")] +layout_mode = 2 +mouse_filter = 2 +color = Color(1, 0, 0, 0) +script = ExtResource("11_epqvn") +target_control = NodePath("../../VBoxContainer/InputArea") + +[editable path="HBoxContainer/Control/VBoxContainer/InputArea"] +[editable path="HBoxContainer/Control/VBoxContainer/InputArea/Button"] +[editable path="HBoxContainer/Control/Layer2/HelpBar"] diff --git a/godot/addons/panku_console/modules/interactive_shell/console_ui/remote_control_node.gd b/godot/addons/panku_console/modules/interactive_shell/console_ui/remote_control_node.gd new file mode 100644 index 0000000..01534d5 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/console_ui/remote_control_node.gd @@ -0,0 +1,15 @@ +extends Control + +@export +var target_control:Control + +func _ready(): + if not target_control: + return + + target_control.resized.connect( + func(): + custom_minimum_size = target_control.get_minimum_size() + ) + + target_control.resized.emit() diff --git a/godot/addons/panku_console/modules/interactive_shell/console_ui/remote_control_node.gd.uid b/godot/addons/panku_console/modules/interactive_shell/console_ui/remote_control_node.gd.uid new file mode 100644 index 0000000..1cef121 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/console_ui/remote_control_node.gd.uid @@ -0,0 +1 @@ +uid://bctccrx5gl50x diff --git a/godot/addons/panku_console/modules/interactive_shell/console_ui/repl.gd b/godot/addons/panku_console/modules/interactive_shell/console_ui/repl.gd new file mode 100644 index 0000000..f6a63e3 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/console_ui/repl.gd @@ -0,0 +1,102 @@ +extends Node + +var _module:PankuModule: + set(v): + _module = v + _input_area.input.module = v + +@export_subgroup("Dependency") +@export var _input_area:Control +@export var _hints:Control +@export var _helpbar:Control +@export var _helpbar_label:Control + +@export_subgroup("Config") +@export var show_all_hints_if_input_is_empty := false + +signal output(bbcode:String) +signal output_echo(bbcode:String) +signal output_result(bbcode:String) +signal output_error(bbcode:String) + +var _current_hints := {} +var _hint_idx := 0 +func _set_hint_idx(v): + _hint_idx = v + if _current_hints["hints_value"].size() > 0: + v = wrapi(v, 0, _current_hints["hints_value"].size()) + var k = _current_hints["hints_value"][v] + + #if the bbcode ends with ')',then we believe it is a method + #(I know maybe it's a bad practice, but the hinting system needs refactor) + var is_method = _current_hints["hints_bbcode"][v].ends_with(")") + + _hint_idx = v + _hints.selected = v + _input_area.input.text = k + ("()" if is_method else "") + _input_area.input.caret_column = k.length() + (1 if is_method else 0) + _helpbar_label.text = "[Help] %s" % _module.core.gd_exprenv.get_help_info(k) + +func execute(exp:String): + exp = exp.lstrip(" ").rstrip(" ") + if exp.is_empty(): + return + var echo:String = "[b][You][/b] " + exp + output.emit(echo) + output_echo.emit(echo) + var result = _module.core.gd_exprenv.execute(exp) + if !result["failed"]: + # ignore the expression result if it is null + if result["result"] != null: + var result_str:String = str(result["result"]) + output.emit(result_str) + output_result.emit(result_str) + else: + var error_str:String = "[color=red]%s[/color]"%(result["result"]) + output.emit(error_str) + output_error.emit(error_str) + _module.core.new_expression_entered.emit(exp, result) + +func _update_hints(exp:String): + _current_hints = _module.core.gd_exprenv.parse_exp(exp, show_all_hints_if_input_is_empty) + _hints.visible = _current_hints["hints_value"].size() > 0 + _helpbar.visible = _hints.visible + _input_area.input.hints = _current_hints["hints_value"] + _hints.set_hints(_current_hints["hints_bbcode"]) + _hint_idx = -1 + _helpbar_label.text = "[Hint] Use TAB or up/down to autocomplete!" + +func _ready(): + _input_area.visibility_changed.connect( + func(): + #initialize all hints if is shown and the input is empty + if _input_area.visible and _input_area.input.text.is_empty() and !_hints.visible and show_all_hints_if_input_is_empty: + _update_hints("") + ) + _input_area.submitted.connect(execute) + _input_area.update_hints.connect(_update_hints) + _input_area.next_hint.connect( + func(): + _set_hint_idx(_hint_idx + 1) + ) + _input_area.prev_hint.connect( + func(): + if _hint_idx == -1: + _hint_idx = 0 + _set_hint_idx(_hint_idx - 1) + ) + _input_area.navigate_histories.connect( + func(histories, id): + if histories.size() > 0: + _hints.set_hints(histories) + _hints.selected = id + _hints.visible = true + else: + _hints.visible = false + _helpbar.visible = _hints.visible + _helpbar_label.text = "[Hint] Use up/down to navigate through submit histories!" + + ) + + _helpbar.hide() + _hints.hide() diff --git a/godot/addons/panku_console/modules/interactive_shell/console_ui/repl.gd.uid b/godot/addons/panku_console/modules/interactive_shell/console_ui/repl.gd.uid new file mode 100644 index 0000000..43b74bc --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/console_ui/repl.gd.uid @@ -0,0 +1 @@ +uid://ic51t4b4v6fl diff --git a/godot/addons/panku_console/modules/interactive_shell/console_ui/repl.tscn b/godot/addons/panku_console/modules/interactive_shell/console_ui/repl.tscn new file mode 100644 index 0000000..1e569af --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/console_ui/repl.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3 uid="uid://ca0bkchv6nsrb"] + +[ext_resource type="Script" path="res://addons/panku_console/modules/interactive_shell/console_ui/repl.gd" id="1_dk53o"] + +[node name="REPL" type="Node"] +script = ExtResource("1_dk53o") diff --git a/godot/addons/panku_console/modules/interactive_shell/console_ui/side_buttons_controller.gd b/godot/addons/panku_console/modules/interactive_shell/console_ui/side_buttons_controller.gd new file mode 100644 index 0000000..d16d5c3 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/console_ui/side_buttons_controller.gd @@ -0,0 +1,30 @@ +extends PankuButton + +func _ready(): + super._ready() + set_meta("text", " Fold Menu") + text = "" + var img = Image.new() + img.copy_from(icon.get_image()) + img.flip_x() + var unfold_icon = ImageTexture.create_from_image(img) + var fold_icon = icon + + icon = unfold_icon + + button.toggle_mode = true + button.toggled.connect( + func(button_pressed:bool): + if button_pressed: + icon = fold_icon + else: + icon = unfold_icon + + for node in get_parent().get_children(): + if not (node is PankuButton): + continue + if button_pressed: + node.text = node.get_meta("text") + else: + node.text = "" + ) diff --git a/godot/addons/panku_console/modules/interactive_shell/console_ui/side_buttons_controller.gd.uid b/godot/addons/panku_console/modules/interactive_shell/console_ui/side_buttons_controller.gd.uid new file mode 100644 index 0000000..5b88497 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/console_ui/side_buttons_controller.gd.uid @@ -0,0 +1 @@ +uid://dbknokoygt463 diff --git a/godot/addons/panku_console/modules/interactive_shell/env.gd b/godot/addons/panku_console/modules/interactive_shell/env.gd new file mode 100644 index 0000000..550e482 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/env.gd @@ -0,0 +1,11 @@ +var _module:PankuModule + +func open_window(): _module.open_window() + +func open_launcher(): _module.open_launcher() + +func set_unified_window_visibility(enabled:bool): + _module.set_unified_window_visibility(enabled) + +func set_pause_if_popup(enabled:bool): + _module.set_pause_if_popup(enabled) diff --git a/godot/addons/panku_console/modules/interactive_shell/env.gd.uid b/godot/addons/panku_console/modules/interactive_shell/env.gd.uid new file mode 100644 index 0000000..008e77a --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/env.gd.uid @@ -0,0 +1 @@ +uid://dk268bsmvnisk diff --git a/godot/addons/panku_console/modules/interactive_shell/hints_list/hint.gd b/godot/addons/panku_console/modules/interactive_shell/hints_list/hint.gd new file mode 100644 index 0000000..1e3e7e6 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/hints_list/hint.gd @@ -0,0 +1,8 @@ +extends PanelContainer + +@export var label:RichTextLabel +@export var bg2:ColorRect + +func set_highlight(b:bool): + bg2.scale.x = 1.0 if b else 0.0 + bg2.visible = b diff --git a/godot/addons/panku_console/modules/interactive_shell/hints_list/hint.gd.uid b/godot/addons/panku_console/modules/interactive_shell/hints_list/hint.gd.uid new file mode 100644 index 0000000..f47df9e --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/hints_list/hint.gd.uid @@ -0,0 +1 @@ +uid://br60e27sllo1h diff --git a/godot/addons/panku_console/modules/interactive_shell/hints_list/hint.tscn b/godot/addons/panku_console/modules/interactive_shell/hints_list/hint.tscn new file mode 100644 index 0000000..4a9750a --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/hints_list/hint.tscn @@ -0,0 +1,44 @@ +[gd_scene load_steps=5 format=3 uid="uid://dbtn0x604fx5o"] + +[ext_resource type="Script" path="res://addons/panku_console/modules/interactive_shell/hints_list/hint.gd" id="1_sa53g"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_56dbv"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_6xc2u"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ganpp"] +content_margin_left = 4.0 +content_margin_top = 4.0 +content_margin_right = 4.0 +content_margin_bottom = 4.0 + +[node name="Hint" type="PanelContainer" node_paths=PackedStringArray("label", "bg2")] +anchors_preset = 10 +anchor_right = 1.0 +grow_horizontal = 2 +theme_override_styles/panel = SubResource("StyleBoxEmpty_56dbv") +script = ExtResource("1_sa53g") +label = NodePath("RichTextLabel") +bg2 = NodePath("Bg2") + +[node name="Blur" type="ColorRect" parent="."] +layout_mode = 2 +color = Color(0.219608, 0.219608, 0.223529, 0.658824) + +[node name="Bg2" type="ColorRect" parent="."] +visible = false +layout_mode = 2 +color = Color(0.290196, 0.509804, 0.305882, 1) + +[node name="RichTextLabel" type="RichTextLabel" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 4 +mouse_filter = 2 +theme_override_styles/focus = SubResource("StyleBoxEmpty_6xc2u") +theme_override_styles/normal = SubResource("StyleBoxEmpty_ganpp") +bbcode_enabled = true +text = "[color=cyan]w_button[/color][color=gray]([/color]display_name:[color=green]String[/color], env:[color=green]String[/color], exp:[color=green]String[/color][color=gray])[/color]" +fit_content = true +scroll_active = false +autowrap_mode = 0 diff --git a/godot/addons/panku_console/modules/interactive_shell/hints_list/hints_list.gd b/godot/addons/panku_console/modules/interactive_shell/hints_list/hints_list.gd new file mode 100644 index 0000000..e80acf8 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/hints_list/hints_list.gd @@ -0,0 +1,54 @@ +extends ScrollContainer + +const hint_pck = preload("./hint.tscn") + +const MAX_HEIGHT = 400 + +@export var auto_resize := false + +@export var container:VBoxContainer + +var hints_count = 0 + +var selected:int = 0: + set(v): + if !container: return + if v < container.get_child_count(): + if selected < container.get_child_count(): + container.get_child(selected).set_highlight(false) + container.get_child(v).set_highlight(true) + selected = v + + #follow selected + var bar = get_v_scroll_bar() + if bar.visible: + var a = bar.max_value + var b = bar.value + var c = bar.page + var d = bar.max_value / hints_count + var l = d * selected + var r = d * (selected + 1) + if b > l: b = l + if b + c < r: b = r - c + bar.value = b + +func set_hints(texts:Array): + hints_count = texts.size() + for i in range(texts.size()): + var h + if i < container.get_child_count(): + h = container.get_child(i) + h.show() + else: + h = hint_pck.instantiate() + container.add_child(h) + h.set_meta("idx", i) + h.label.text = texts[i] + h.set_highlight(false) + if texts.size() < container.get_child_count(): + for i in range(texts.size(), container.get_child_count()): + container.get_child(i).hide() + + if auto_resize: + await get_tree().process_frame + custom_minimum_size.y = min(MAX_HEIGHT, container.size.y) diff --git a/godot/addons/panku_console/modules/interactive_shell/hints_list/hints_list.gd.uid b/godot/addons/panku_console/modules/interactive_shell/hints_list/hints_list.gd.uid new file mode 100644 index 0000000..3d35450 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/hints_list/hints_list.gd.uid @@ -0,0 +1 @@ +uid://drcrjq1q1qqhd diff --git a/godot/addons/panku_console/modules/interactive_shell/hints_list/hints_list.tscn b/godot/addons/panku_console/modules/interactive_shell/hints_list/hints_list.tscn new file mode 100644 index 0000000..16bcdc8 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/hints_list/hints_list.tscn @@ -0,0 +1,19 @@ +[gd_scene load_steps=2 format=3 uid="uid://b3jf18wonocnv"] + +[ext_resource type="Script" path="res://addons/panku_console/modules/interactive_shell/hints_list/hints_list.gd" id="1_yd1qq"] + +[node name="HintsList" type="ScrollContainer" node_paths=PackedStringArray("container")] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_yd1qq") +container = NodePath("VBoxContainer") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +theme_override_constants/separation = 0 +alignment = 2 diff --git a/godot/addons/panku_console/modules/interactive_shell/input_field/input_area.gd b/godot/addons/panku_console/modules/interactive_shell/input_field/input_area.gd new file mode 100644 index 0000000..721b374 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/input_field/input_area.gd @@ -0,0 +1,34 @@ +extends HBoxContainer + +@onready var console:PankuConsole = get_node(PankuConsole.SingletonPath) + +signal submitted(exp:String) +signal update_hints(exp:String) +signal next_hint() +signal prev_hint() +signal navigate_histories(histories:Array, cur:int) + +@export var input:LineEdit +@export var btn:PankuButton + +func _ready(): + input.text_submitted.connect( + func(s): + submitted.emit(s) + ) + input.text_changed.connect( + func(s): + update_hints.emit(s) + ) + btn.pressed.connect( + func(): + submitted.emit(input.text) + input.on_text_submitted(input.text) + ) + + #get focus automatically. + visibility_changed.connect( + func(): + if is_visible_in_tree(): + input.call_deferred("grab_focus") + ) diff --git a/godot/addons/panku_console/modules/interactive_shell/input_field/input_area.gd.uid b/godot/addons/panku_console/modules/interactive_shell/input_field/input_area.gd.uid new file mode 100644 index 0000000..4579705 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/input_field/input_area.gd.uid @@ -0,0 +1 @@ +uid://djjw21iltjovc diff --git a/godot/addons/panku_console/modules/interactive_shell/input_field/input_area.tscn b/godot/addons/panku_console/modules/interactive_shell/input_field/input_area.tscn new file mode 100644 index 0000000..15521f5 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/input_field/input_area.tscn @@ -0,0 +1,41 @@ +[gd_scene load_steps=6 format=3 uid="uid://bme8twac4ick5"] + +[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="1_rocdy"] +[ext_resource type="Script" path="res://addons/panku_console/modules/interactive_shell/input_field/input_area.gd" id="2_6g40s"] +[ext_resource type="PackedScene" uid="uid://drn5t13m088fb" path="res://addons/panku_console/common/panku_button.tscn" id="4_6t5yf"] +[ext_resource type="Script" path="res://addons/panku_console/modules/interactive_shell/input_field/input_field.gd" id="4_xjt2l"] +[ext_resource type="Texture2D" uid="uid://b4jd6tqlie0wx" path="res://addons/panku_console/res/icons2/reply.svg" id="6_w88f1"] + +[node name="InputArea" type="HBoxContainer" node_paths=PackedStringArray("input", "btn")] +offset_right = 277.0 +offset_bottom = 26.0 +theme = ExtResource("1_rocdy") +theme_override_constants/separation = 0 +script = ExtResource("2_6g40s") +input = NodePath("InputField") +btn = NodePath("Button") + +[node name="InputField" type="LineEdit" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +focus_neighbor_left = NodePath(".") +focus_neighbor_top = NodePath(".") +focus_neighbor_right = NodePath(".") +focus_neighbor_bottom = NodePath(".") +focus_next = NodePath(".") +focus_previous = NodePath(".") +placeholder_text = "Input expression here..." +clear_button_enabled = true +caret_blink = true +script = ExtResource("4_xjt2l") + +[node name="Button" parent="." instance=ExtResource("4_6t5yf")] +layout_mode = 2 + +[node name="TextureRect" parent="Button/HBoxContainer" index="0"] +texture = ExtResource("6_w88f1") + +[node name="Label" parent="Button/HBoxContainer" index="1"] +text = "" + +[editable path="Button"] diff --git a/godot/addons/panku_console/modules/interactive_shell/input_field/input_field.gd b/godot/addons/panku_console/modules/interactive_shell/input_field/input_field.gd new file mode 100644 index 0000000..8ba120f --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/input_field/input_field.gd @@ -0,0 +1,45 @@ +extends LineEdit + +var module:PankuModuleInteractiveShell + +#up/down history +var history_idx := 0 + +var hints = [] + +func _ready(): + text_submitted.connect(on_text_submitted) + +func on_text_submitted(s:String): + var histories = module.get_histories() + if histories.size() > 0 and history_idx < histories.size() and text == histories[history_idx]: + pass + else: + module.add_history(s) + history_idx = histories.size() + clear() + +func _gui_input(e): + #navigate through histories + var histories = module.get_histories() + if hints.is_empty(): + if e is InputEventKey and e.keycode == KEY_UP and e.pressed: + if !histories.is_empty() : + history_idx = wrapi(history_idx-1, 0, histories.size()) + text = histories[history_idx] + get_parent().navigate_histories.emit(histories, history_idx) + await get_tree().process_frame + caret_column = text.length() + elif e is InputEventKey and e.keycode == KEY_DOWN and e.pressed: + if !histories.is_empty(): + history_idx = wrapi(history_idx+1, 0, histories.size()) + text = histories[history_idx] + get_parent().navigate_histories.emit(histories, history_idx) + await get_tree().process_frame + caret_column = text.length() + #navigate through hints + else: + if e is InputEventKey and e.keycode == KEY_UP and e.pressed: + get_parent().prev_hint.emit() + elif e is InputEventKey and (e.keycode in [KEY_DOWN, KEY_TAB]) and e.pressed: + get_parent().next_hint.emit() diff --git a/godot/addons/panku_console/modules/interactive_shell/input_field/input_field.gd.uid b/godot/addons/panku_console/modules/interactive_shell/input_field/input_field.gd.uid new file mode 100644 index 0000000..ac0255f --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/input_field/input_field.gd.uid @@ -0,0 +1 @@ +uid://crmlcgjx0rruc diff --git a/godot/addons/panku_console/modules/interactive_shell/mini_repl_2.gd b/godot/addons/panku_console/modules/interactive_shell/mini_repl_2.gd new file mode 100644 index 0000000..c74eb05 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/mini_repl_2.gd @@ -0,0 +1,13 @@ +extends VBoxContainer + +var console:PankuConsole + +@export var input_area:Node +@export var repl:Node + +func _ready() -> void: + repl.output_result.connect(console.notify) + repl.output_error.connect(console.notify) + input_area.submitted.connect( + func(_s): hide() + ) diff --git a/godot/addons/panku_console/modules/interactive_shell/mini_repl_2.gd.uid b/godot/addons/panku_console/modules/interactive_shell/mini_repl_2.gd.uid new file mode 100644 index 0000000..162e92a --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/mini_repl_2.gd.uid @@ -0,0 +1 @@ +uid://e1chjcdql5bm diff --git a/godot/addons/panku_console/modules/interactive_shell/mini_repl_2.tscn b/godot/addons/panku_console/modules/interactive_shell/mini_repl_2.tscn new file mode 100644 index 0000000..34d48d5 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/mini_repl_2.tscn @@ -0,0 +1,61 @@ +[gd_scene load_steps=10 format=3 uid="uid://7782tkm11uco"] + +[ext_resource type="PackedScene" uid="uid://bme8twac4ick5" path="res://addons/panku_console/modules/interactive_shell/input_field/input_area.tscn" id="1_cerpp"] +[ext_resource type="Script" path="res://addons/panku_console/modules/interactive_shell/mini_repl_2.gd" id="1_qrxrm"] +[ext_resource type="Script" path="res://addons/panku_console/modules/interactive_shell/console_ui/repl.gd" id="1_tygtx"] +[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="1_yfc5r"] +[ext_resource type="PackedScene" uid="uid://cbijhl1nhy64n" path="res://addons/panku_console/modules/interactive_shell/console_ui/help_bar.tscn" id="2_2k26n"] +[ext_resource type="Shader" path="res://addons/panku_console/res/shader/simple_fast_blur.gdshader" id="4_djxpe"] +[ext_resource type="PackedScene" uid="uid://b3jf18wonocnv" path="res://addons/panku_console/modules/interactive_shell/hints_list/hints_list.tscn" id="5_i3ldx"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_xty2u"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_kt6ig"] +shader = ExtResource("4_djxpe") +shader_parameter/lod = 4.0 +shader_parameter/modulate = Color(0, 0, 0, 0.25098) + +[node name="MiniREPL" type="VBoxContainer" node_paths=PackedStringArray("input_area", "repl")] +z_index = 2 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +theme = ExtResource("1_yfc5r") +theme_override_constants/separation = 0 +alignment = 2 +script = ExtResource("1_qrxrm") +input_area = NodePath("PanelContainer/InputArea") +repl = NodePath("REPL") + +[node name="REPL" type="Node" parent="." node_paths=PackedStringArray("_input_area", "_hints", "_helpbar", "_helpbar_label")] +script = ExtResource("1_tygtx") +_input_area = NodePath("../PanelContainer/InputArea") +_hints = NodePath("../HintsList") +_helpbar = NodePath("../HelpBar") +_helpbar_label = NodePath("../HelpBar/Label") + +[node name="HintsList" parent="." instance=ExtResource("5_i3ldx")] +layout_mode = 2 +auto_resize = true + +[node name="HelpBar" parent="." instance=ExtResource("2_2k26n")] +custom_minimum_size = Vector2(0, 24) +layout_mode = 2 + +[node name="PanelContainer" type="PanelContainer" parent="."] +layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxEmpty_xty2u") + +[node name="ColorRect" type="ColorRect" parent="PanelContainer"] +material = SubResource("ShaderMaterial_kt6ig") +layout_mode = 2 + +[node name="InputArea" parent="PanelContainer" instance=ExtResource("1_cerpp")] +custom_minimum_size = Vector2(0, 24) +layout_mode = 2 + +[editable path="HintsList"] +[editable path="HelpBar"] diff --git a/godot/addons/panku_console/modules/interactive_shell/module.gd b/godot/addons/panku_console/modules/interactive_shell/module.gd new file mode 100644 index 0000000..2050319 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/module.gd @@ -0,0 +1,171 @@ +class_name PankuModuleInteractiveShell extends PankuModule + +var window:PankuLynxWindow +var interactive_shell:Control +var simple_launcher:Control + +enum InputMode { + Window, + Launcher +} + +var gui_mode:InputMode = InputMode.Window +var pause_if_input:bool = true +var unified_window_visibility:bool = false +var init_expr:String = "" +var _is_gui_open:bool = false +var _was_tree_paused: bool = false +var _previous_mouse_mode := Input.MOUSE_MODE_VISIBLE +var _show_side_menu:bool + +func get_intro() -> String: + var intro:PackedStringArray = PackedStringArray() + intro.append("[color=#ffffff44][b][i]> Panku Console[/i][/b][/color]") + intro.append("[color=#ffffff44]Feature-Packed Runtime Debugging Toolkit for Godot[/color]") + intro.append("[color=#ffffff44]Version: %s([url=%s][color=#10a00c]%s[/color][/url]) | Visit [color=#3feeb6][url=https://github.com/Ark2000/PankuConsole]github repo[/url][/color] for more info[/color]" % [PankuUtils.get_plugin_version(), PankuUtils.get_commit_url(), PankuUtils.get_commit_sha_short()]) + return "\n".join(intro) + +func init_module(): + interactive_shell = preload("./console_ui/panku_console_ui.tscn").instantiate() + window = core.windows_manager.create_window(interactive_shell) + add_auto_save_hook(window) + interactive_shell._repl._module = self + window.queue_free_on_close = false + window.set_window_title_text("Interactive Shell V2") + load_window_data(window) + window.hide_window() + + interactive_shell.output(get_intro()) + + simple_launcher = preload("./mini_repl_2.tscn").instantiate() + simple_launcher.console = core + core.add_child(simple_launcher) + simple_launcher.repl._module = self + simple_launcher.hide() + + core.toggle_console_action_just_pressed.connect( + func(): + if gui_mode == InputMode.Window: + if window.visible: + window.hide_window() + else: + window.show_window() + elif gui_mode == InputMode.Launcher: + simple_launcher.visible = not simple_launcher.visible + ) + + # Grab the mouse when the dev console is visible (e.g. FPS games) + window.visibility_changed.connect( + func(): + # the mouse is grabbed when the window is visible + if window.visible: + _previous_mouse_mode = Input.mouse_mode + Input.mouse_mode = Input.MOUSE_MODE_VISIBLE + # restore the mouse mode when the window is hidden + else: + Input.mouse_mode = _previous_mouse_mode + ) + + gui_mode = load_module_data("gui_mode", InputMode.Window) + pause_if_input = load_module_data("pause_if_popup", true) + unified_window_visibility = load_module_data("unified_visibility", false) + init_expr = load_module_data("init_expression", "print('Panku Console Loaded!')") + + _show_side_menu = load_module_data("show_side_menu", true) + set_side_menu_visible(_show_side_menu) + + window.visibility_changed.connect(update_gui_state) + simple_launcher.visibility_changed.connect(update_gui_state) + _is_gui_open = not (window.visible or simple_launcher.visible) + update_gui_state() + + # TODO: this signal is emitted twice when the window is shown, investigate + # window.visibility_changed.connect( + # func(): + # print("window visibility changed: ", window.visible) + # ) + + # execute init_expr after a short delay + if init_expr != "": + core.create_tween().tween_callback( + func(): + var result = core.gd_exprenv.execute(init_expr) + core.new_expression_entered.emit(init_expr, result) + ).set_delay(0.1) + + _input_histories = load_module_data("histories", []) + +func quit_module(): + super.quit_module() + save_window_data(window) + save_module_data("gui_mode", gui_mode) + save_module_data("histories", _input_histories) + save_module_data("show_side_menu", _show_side_menu) + +func update_gui_state(): + var is_gui_open = window.visible or simple_launcher.visible + + if is_gui_open == _is_gui_open: + return + + if _is_gui_open != is_gui_open: + core._shell_visibility = is_gui_open + core.interactive_shell_visibility_changed.emit(is_gui_open) + _is_gui_open = is_gui_open + + if pause_if_input: + if _is_gui_open: + _was_tree_paused = core.get_tree().paused + core.get_tree().paused = true + else: + if core.get_tree().paused: + core.get_tree().paused = _was_tree_paused + + if unified_window_visibility: + core.windows_manager.visible = _is_gui_open + +func open_window(): + if gui_mode == InputMode.Window: + if not window.visible: + window.show_window() + else: + core.notify("The window is alreay opened.") + elif gui_mode == InputMode.Launcher: + gui_mode = InputMode.Window + simple_launcher.hide() + window.show_window() + +func open_launcher(): + if gui_mode == InputMode.Window: + gui_mode = InputMode.Launcher + window.hide_window() + simple_launcher.show() + elif gui_mode == InputMode.Launcher: + if not simple_launcher.visible: + simple_launcher.show() + else: + core.notify("The launcher is alreay opened.") + +func set_side_menu_visible(enabled:bool): + _show_side_menu = enabled + interactive_shell.enable_side_menu = enabled + interactive_shell.resized.emit() + +func set_unified_window_visibility(enabled:bool): + unified_window_visibility = enabled + update_gui_state() + +func set_pause_if_popup(enabled:bool): + pause_if_input = enabled + update_gui_state() + +const MAX_HISTORY = 10 +var _input_histories := [] + +func get_histories() -> Array: + return _input_histories + +func add_history(s:String) -> void: + _input_histories.append(s) + if _input_histories.size() > MAX_HISTORY: + _input_histories.remove_at(0) diff --git a/godot/addons/panku_console/modules/interactive_shell/module.gd.uid b/godot/addons/panku_console/modules/interactive_shell/module.gd.uid new file mode 100644 index 0000000..3ea5746 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/module.gd.uid @@ -0,0 +1 @@ +uid://qyi713yh7kco diff --git a/godot/addons/panku_console/modules/interactive_shell/opt.gd b/godot/addons/panku_console/modules/interactive_shell/opt.gd new file mode 100644 index 0000000..a913952 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/opt.gd @@ -0,0 +1,31 @@ +extends ModuleOptions + +@export_group("interactive_shell") + +@export var export_comment_show_side_menu = "config file at side_menu_config.json" +@export var show_side_menu:bool: + get: + return _module._show_side_menu + set(v): + _module.set_side_menu_visible(v) + +@export var export_comment_unified_visibility = "unified_visibility will keep all windows' visibility the same as interactive shell" +@export var unified_visibility:bool = false: + get: + return _module.unified_window_visibility + set(v): + _module.set_unified_window_visibility(v) + +@export var export_comment_pause_if_popup = "Whether the whole game should be paused when interactive shell is visible" +@export var pause_if_popup:bool = false: + get: + return _module.pause_if_input + set(v): + _module.set_pause_if_popup(v) + +@export var export_comment_init_expression = "init_expression will be executed when the project starts" +@export var init_expression:String = "": + get: + return _module.init_expr + set(v): + _module.init_expr = v diff --git a/godot/addons/panku_console/modules/interactive_shell/opt.gd.uid b/godot/addons/panku_console/modules/interactive_shell/opt.gd.uid new file mode 100644 index 0000000..9111062 --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/opt.gd.uid @@ -0,0 +1 @@ +uid://yh85n6ws8ne5 diff --git a/godot/addons/panku_console/modules/interactive_shell/side_menu_config.json b/godot/addons/panku_console/modules/interactive_shell/side_menu_config.json new file mode 100644 index 0000000..e8af52e --- /dev/null +++ b/godot/addons/panku_console/modules/interactive_shell/side_menu_config.json @@ -0,0 +1,36 @@ +{ + "items.top":[ + { + "text": "Debug Logs", + "icon": "res://addons/panku_console/res/icons2/info2.svg", + "command": "native_logger.open()" + }, + { + "text": "Watch Exp", + "icon": "res://addons/panku_console/res/icons2/eye.svg", + "command": "expression_monitor.open_window()" + }, + { + "text": "Shortcut", + "icon": "res://addons/panku_console/res/icons2/keyboard.svg", + "command": "keyboard_shortcuts.open()" + }, + { + "text": "History", + "icon": "res://addons/panku_console/res/icons2/history.svg", + "command": "history_manager.open()" + } + ], + "items.bottom":[ + { + "text": "Settings", + "icon": "res://addons/panku_console/res/icons2/gear.svg", + "command": "general_settings.open()" + }, + { + "text": "About", + "icon": "res://addons/panku_console/res/icons2/question.svg", + "command": "about.open()" + } + ] +} diff --git a/godot/addons/panku_console/modules/keyboard_shortcuts/env.gd b/godot/addons/panku_console/modules/keyboard_shortcuts/env.gd new file mode 100644 index 0000000..dae4497 --- /dev/null +++ b/godot/addons/panku_console/modules/keyboard_shortcuts/env.gd @@ -0,0 +1,4 @@ +var _module:PankuModule + +func open() -> void: + _module.open_window() diff --git a/godot/addons/panku_console/modules/keyboard_shortcuts/env.gd.uid b/godot/addons/panku_console/modules/keyboard_shortcuts/env.gd.uid new file mode 100644 index 0000000..793839d --- /dev/null +++ b/godot/addons/panku_console/modules/keyboard_shortcuts/env.gd.uid @@ -0,0 +1 @@ +uid://c543ph1ee3se6 diff --git a/godot/addons/panku_console/modules/keyboard_shortcuts/exp_key_item.gd b/godot/addons/panku_console/modules/keyboard_shortcuts/exp_key_item.gd new file mode 100644 index 0000000..8658b83 --- /dev/null +++ b/godot/addons/panku_console/modules/keyboard_shortcuts/exp_key_item.gd @@ -0,0 +1,19 @@ +extends HBoxContainer + +signal exp_edit_submitted(new_exp:String) + +@export var exp_edit:LineEdit +@export var remap_button:Button +@export var delete_button:Button + +func _ready(): + delete_button.pressed.connect(queue_free) + exp_edit.text_submitted.connect( + func(new_text:String): + exp_edit.release_focus() + exp_edit_submitted.emit(new_text) + ) + exp_edit.focus_exited.connect( + func(): + exp_edit_submitted.emit(exp_edit.text) + ) diff --git a/godot/addons/panku_console/modules/keyboard_shortcuts/exp_key_item.gd.uid b/godot/addons/panku_console/modules/keyboard_shortcuts/exp_key_item.gd.uid new file mode 100644 index 0000000..88f87fd --- /dev/null +++ b/godot/addons/panku_console/modules/keyboard_shortcuts/exp_key_item.gd.uid @@ -0,0 +1 @@ +uid://5ridrx8lft6u diff --git a/godot/addons/panku_console/modules/keyboard_shortcuts/exp_key_item.tscn b/godot/addons/panku_console/modules/keyboard_shortcuts/exp_key_item.tscn new file mode 100644 index 0000000..d4c5b4a --- /dev/null +++ b/godot/addons/panku_console/modules/keyboard_shortcuts/exp_key_item.tscn @@ -0,0 +1,34 @@ +[gd_scene load_steps=5 format=3 uid="uid://dkw70e7xyrqxi"] + +[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="1_u320k"] +[ext_resource type="Script" path="res://addons/panku_console/modules/keyboard_shortcuts/exp_key_item.gd" id="2_7ijd8"] +[ext_resource type="Script" path="res://addons/panku_console/modules/keyboard_shortcuts/remap_button.gd" id="3_3bdj0"] +[ext_resource type="Texture2D" uid="uid://dnexm7u6lq3km" path="res://addons/panku_console/res/icons2/remove.svg" id="4_vif73"] + +[node name="ExpkeyItem" type="HBoxContainer" node_paths=PackedStringArray("exp_edit", "remap_button", "delete_button")] +offset_right = 280.0 +offset_bottom = 31.0 +theme = ExtResource("1_u320k") +script = ExtResource("2_7ijd8") +exp_edit = NodePath("ExpressionEdit") +remap_button = NodePath("RemapButton") +delete_button = NodePath("DeleteButton") + +[node name="ExpressionEdit" type="LineEdit" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "Expression" +clear_button_enabled = true + +[node name="RemapButton" type="Button" parent="."] +layout_mode = 2 +toggle_mode = true +text = "Unassigned" +script = ExtResource("3_3bdj0") + +[node name="DeleteButton" type="Button" parent="."] +custom_minimum_size = Vector2(27, 0) +layout_mode = 2 +toggle_mode = true +icon = ExtResource("4_vif73") +expand_icon = true diff --git a/godot/addons/panku_console/modules/keyboard_shortcuts/exp_key_mapper_2.gd b/godot/addons/panku_console/modules/keyboard_shortcuts/exp_key_mapper_2.gd new file mode 100644 index 0000000..19d8158 --- /dev/null +++ b/godot/addons/panku_console/modules/keyboard_shortcuts/exp_key_mapper_2.gd @@ -0,0 +1,92 @@ +extends Control + +signal key_binding_added(key: InputEventKey, expression: String) +signal key_binding_changed(key: InputEventKey, expression: String) + +const INFO_STRING := "Yes, I know it." +const exp_key_item := preload("./exp_key_item.tscn") + +var console: PankuConsole + +@export var add_btn: Button +@export var container: VBoxContainer + +var mapping_data = [] + +@onready var info_btn: Button = %InfoButton + + +func _ready(): + info_btn.pressed.connect(_console_notify.bind(INFO_STRING)) + + #when clicking the button, add a new exp key mapping item + add_btn.pressed.connect( + func(): + var default_exp = "" + var default_event = null + add_item(default_exp, default_event) + mapping_data.push_back([default_exp, default_event]) + ) + + +func _console_notify(txt: String) -> void: + if console: + console.notify(txt) + + +#handle input here. +func _unhandled_input(e): + if e is InputEventKey: + for i in range(len(mapping_data)): + var key_mapping = mapping_data[i] + var exp:String = key_mapping[0] + var event:InputEventKey = key_mapping[1] + if !event: continue + if e.keycode == event.keycode and e.pressed and !e.echo: + #execute the exp + var result = console.gd_exprenv.execute(exp) + if result.failed: + _console_notify("[color=red]%s[/color]" % result.result) + else: + #ignore null result + if result.result: + _console_notify(str(result.result)) + + +func add_item(exp:String, event:InputEventKey): + var item = exp_key_item.instantiate() + container.add_child(item) + container.move_child(item, container.get_child_count() - 2) + item.exp_edit.text = exp + item.remap_button.key_event = event + + item.exp_edit_submitted.connect( + func(new_exp:String): + mapping_data[item.get_index()][0] = new_exp + if(key_binding_added.get_connections().size() > 0): + key_binding_added.emit(event, new_exp) + ) + item.remap_button.key_event_changed.connect( + func(new_event:InputEventKey): + await get_tree().process_frame + mapping_data[item.get_index()][1] = new_event + if(key_binding_changed.get_connections().size() > 0): + key_binding_changed.emit(new_event, mapping_data[item.get_index()][0]) + ) + item.tree_exiting.connect( + func(): + mapping_data.remove_at(item.get_index()) + ) + +func get_data() -> Array: + return mapping_data + +func load_data(data:Array): + mapping_data = data + + #load data + for i in range(len(mapping_data)): + var key_mapping = mapping_data[i] + var exp:String = key_mapping[0] + var event:InputEventKey = key_mapping[1] + add_item(exp, event) diff --git a/godot/addons/panku_console/modules/keyboard_shortcuts/exp_key_mapper_2.gd.uid b/godot/addons/panku_console/modules/keyboard_shortcuts/exp_key_mapper_2.gd.uid new file mode 100644 index 0000000..ed92246 --- /dev/null +++ b/godot/addons/panku_console/modules/keyboard_shortcuts/exp_key_mapper_2.gd.uid @@ -0,0 +1 @@ +uid://gr6addua2s0a diff --git a/godot/addons/panku_console/modules/keyboard_shortcuts/exp_key_mapper_2.tscn b/godot/addons/panku_console/modules/keyboard_shortcuts/exp_key_mapper_2.tscn new file mode 100644 index 0000000..7583903 --- /dev/null +++ b/godot/addons/panku_console/modules/keyboard_shortcuts/exp_key_mapper_2.tscn @@ -0,0 +1,61 @@ +[gd_scene load_steps=6 format=3 uid="uid://c6hm8vweq0j4f"] + +[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="1_0xd5p"] +[ext_resource type="Script" path="res://addons/panku_console/modules/keyboard_shortcuts/exp_key_mapper_2.gd" id="2_vxcow"] +[ext_resource type="Texture2D" uid="uid://dprpfr0l5xvmu" path="res://addons/panku_console/res/icons2/add.svg" id="3_0d2ct"] +[ext_resource type="Texture2D" uid="uid://b6jt0ggmuoyeb" path="res://addons/panku_console/res/icons2/info2.svg" id="3_ofrgs"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_i7jk5"] +content_margin_left = 8.0 +content_margin_top = 8.0 +content_margin_right = 8.0 +content_margin_bottom = 8.0 + +[node name="ExpKeyMapper" type="Control" node_paths=PackedStringArray("add_btn", "container")] +clip_contents = true +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme = ExtResource("1_0xd5p") +script = ExtResource("2_vxcow") +add_btn = NodePath("ScrollContainer/PanelContainer/VBoxContainer2/VBoxContainer/Add") +container = NodePath("ScrollContainer/PanelContainer/VBoxContainer2/VBoxContainer") + +[node name="ScrollContainer" type="ScrollContainer" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +horizontal_scroll_mode = 0 + +[node name="PanelContainer" type="PanelContainer" parent="ScrollContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +theme_override_styles/panel = SubResource("StyleBoxEmpty_i7jk5") + +[node name="VBoxContainer2" type="VBoxContainer" parent="ScrollContainer/PanelContainer"] +layout_mode = 2 + +[node name="InfoButton" type="Button" parent="ScrollContainer/PanelContainer/VBoxContainer2"] +unique_name_in_owner = true +layout_mode = 2 +text = "Edit expression key bindings here." +icon = ExtResource("3_ofrgs") +alignment = 0 +expand_icon = true + +[node name="VBoxContainer" type="VBoxContainer" parent="ScrollContainer/PanelContainer/VBoxContainer2"] +layout_mode = 2 + +[node name="Add" type="Button" parent="ScrollContainer/PanelContainer/VBoxContainer2/VBoxContainer"] +layout_mode = 2 +text = " " +icon = ExtResource("3_0d2ct") +icon_alignment = 1 +expand_icon = true diff --git a/godot/addons/panku_console/modules/keyboard_shortcuts/module.gd b/godot/addons/panku_console/modules/keyboard_shortcuts/module.gd new file mode 100644 index 0000000..db00dd2 --- /dev/null +++ b/godot/addons/panku_console/modules/keyboard_shortcuts/module.gd @@ -0,0 +1,34 @@ +class_name PankuModuleKeyboardShortcuts extends PankuModule + +var window:PankuLynxWindow +var key_mapper + +func init_module(): + # setup ui + key_mapper = preload("./exp_key_mapper_2.tscn").instantiate() + key_mapper.console = core + + # bind window + window = core.windows_manager.create_window(key_mapper) + add_auto_save_hook(window) + window.queue_free_on_close = false + window.set_window_title_text("Keyboard Shortcuts") + + load_window_data(window) + key_mapper.load_data(load_module_data("key_mapper", [])) + key_mapper.key_binding_added.connect( + func(key: InputEventKey, expression: String): + save_module_data("key_mapper", key_mapper.get_data()) + ) + key_mapper.key_binding_changed.connect( + func(key: InputEventKey, expression: String): + save_module_data("key_mapper", key_mapper.get_data()) + ) + +func quit_module(): + super.quit_module() + save_window_data(window) + save_module_data("key_mapper", key_mapper.get_data()) + +func open_window(): + window.show_window() diff --git a/godot/addons/panku_console/modules/keyboard_shortcuts/module.gd.uid b/godot/addons/panku_console/modules/keyboard_shortcuts/module.gd.uid new file mode 100644 index 0000000..900200a --- /dev/null +++ b/godot/addons/panku_console/modules/keyboard_shortcuts/module.gd.uid @@ -0,0 +1 @@ +uid://ciqyqor6o5wst diff --git a/godot/addons/panku_console/modules/keyboard_shortcuts/opt.gd b/godot/addons/panku_console/modules/keyboard_shortcuts/opt.gd new file mode 100644 index 0000000..ac27bb8 --- /dev/null +++ b/godot/addons/panku_console/modules/keyboard_shortcuts/opt.gd @@ -0,0 +1,8 @@ +extends ModuleOptions + +@export_group("keyboard_shortcuts") + +@export var export_button_open_keyboard_shortcuts := "Open Keyboard Shortcuts" + +func open_keyboard_shortcuts(): + _module.open_window() diff --git a/godot/addons/panku_console/modules/keyboard_shortcuts/opt.gd.uid b/godot/addons/panku_console/modules/keyboard_shortcuts/opt.gd.uid new file mode 100644 index 0000000..cd7f7b0 --- /dev/null +++ b/godot/addons/panku_console/modules/keyboard_shortcuts/opt.gd.uid @@ -0,0 +1 @@ +uid://c3qb8rvua37fs diff --git a/godot/addons/panku_console/modules/keyboard_shortcuts/remap_button.gd b/godot/addons/panku_console/modules/keyboard_shortcuts/remap_button.gd new file mode 100644 index 0000000..4391139 --- /dev/null +++ b/godot/addons/panku_console/modules/keyboard_shortcuts/remap_button.gd @@ -0,0 +1,27 @@ +extends Button + +signal key_event_changed(new_event:InputEventKey) + +var key_event:InputEventKey: + set(v): + key_event = v + var key_name = "unassigned" + if key_event: + key_name = "Key " + OS.get_keycode_string(key_event.keycode) + text = key_name + key_event_changed.emit(v) + +func _ready(): + set_process_unhandled_key_input(false) + toggled.connect( + func(button_pressed:bool): + set_process_unhandled_key_input(button_pressed) + if button_pressed: + text = "Waiting..." + else: + release_focus() + ) + +func _unhandled_key_input(event): + key_event = event + button_pressed = false diff --git a/godot/addons/panku_console/modules/keyboard_shortcuts/remap_button.gd.uid b/godot/addons/panku_console/modules/keyboard_shortcuts/remap_button.gd.uid new file mode 100644 index 0000000..5f06e73 --- /dev/null +++ b/godot/addons/panku_console/modules/keyboard_shortcuts/remap_button.gd.uid @@ -0,0 +1 @@ +uid://tvvj5uqe67ov diff --git a/godot/addons/panku_console/modules/native_logger/env.gd b/godot/addons/panku_console/modules/native_logger/env.gd new file mode 100644 index 0000000..aee7d7e --- /dev/null +++ b/godot/addons/panku_console/modules/native_logger/env.gd @@ -0,0 +1,13 @@ +var _module:PankuModule + +const _HELP_open = "Open logger window" +func open() -> void: + _module.open_window() + +const _HELP_toggle_overlay = "Toggle visibility of logger overlay" +func toggle_overlay() -> void: + _module.toggle_overlay() + +const _HELP_clear = "Clear logs" +func clear() -> void: + _module.logger_ui.clear_all() diff --git a/godot/addons/panku_console/modules/native_logger/env.gd.uid b/godot/addons/panku_console/modules/native_logger/env.gd.uid new file mode 100644 index 0000000..28b3ee3 --- /dev/null +++ b/godot/addons/panku_console/modules/native_logger/env.gd.uid @@ -0,0 +1 @@ +uid://dpi48sns7m7ch diff --git a/godot/addons/panku_console/modules/native_logger/godot_log_monitor.gd b/godot/addons/panku_console/modules/native_logger/godot_log_monitor.gd new file mode 100644 index 0000000..45cd568 --- /dev/null +++ b/godot/addons/panku_console/modules/native_logger/godot_log_monitor.gd @@ -0,0 +1,59 @@ +extends Node +#Monitor built-in logs + +signal error_msg_received(msg:String) +signal warning_msg_received(msg:String) +signal info_msg_received(msg:String) + +const UPDATE_INTERVAL := 0.1 +const ERROR_MSG_PREFIX := "USER ERROR: " +const WARNING_MSG_PREFIX := "USER WARNING: " +#Any logs with three spaces at the beginning will be ignored. +const IGNORE_PREFIX := " " + +var godot_log: FileAccess +var godot_log_path: String + + +func _ready(): + if not _is_log_enabled(): + push_warning("You have to enable file logging in order to use engine log monitor!") + return + + godot_log_path = ProjectSettings.get("debug/file_logging/log_path") + if not FileAccess.file_exists(godot_log_path): + push_warning("Log file not fount by path " + godot_log_path) + return + + _start_watching() + + +func _start_watching() -> void: + godot_log = FileAccess.open(godot_log_path, FileAccess.READ) + create_tween().set_loops().tween_callback(_read_data).set_delay(UPDATE_INTERVAL) + + +func _is_log_enabled() -> bool: + + if ProjectSettings.get("debug/file_logging/enable_file_logging"): + return true + + # this feels so weird and wrong + # what about other platforms? + if OS.has_feature("pc") and ProjectSettings.get("debug/file_logging/enable_file_logging.pc"): + return true + + return false + + +func _read_data(): + while godot_log.get_position() < godot_log.get_length(): + var new_line = godot_log.get_line() + if new_line.begins_with(IGNORE_PREFIX): + continue + if new_line.begins_with(ERROR_MSG_PREFIX): + error_msg_received.emit(new_line.trim_prefix(ERROR_MSG_PREFIX)) + elif new_line.begins_with(WARNING_MSG_PREFIX): + warning_msg_received.emit(new_line.trim_prefix(WARNING_MSG_PREFIX)) + else: + info_msg_received.emit(new_line) diff --git a/godot/addons/panku_console/modules/native_logger/godot_log_monitor.gd.uid b/godot/addons/panku_console/modules/native_logger/godot_log_monitor.gd.uid new file mode 100644 index 0000000..e260c54 --- /dev/null +++ b/godot/addons/panku_console/modules/native_logger/godot_log_monitor.gd.uid @@ -0,0 +1 @@ +uid://bpansextixugq diff --git a/godot/addons/panku_console/modules/native_logger/log_overlay.tscn b/godot/addons/panku_console/modules/native_logger/log_overlay.tscn new file mode 100644 index 0000000..16dfe9d --- /dev/null +++ b/godot/addons/panku_console/modules/native_logger/log_overlay.tscn @@ -0,0 +1,21 @@ +[gd_scene load_steps=2 format=3 uid="uid://clwb00tc8ogtr"] + +[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="1_2qqxo"] + +[node name="LogOverlay" type="RichTextLabel"] +modulate = Color(1, 1, 1, 0.501961) +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +mouse_filter = 2 +theme = ExtResource("1_2qqxo") +bbcode_enabled = true +text = "Output Area" +scroll_active = false +scroll_following = true +autowrap_mode = 0 +shortcut_keys_enabled = false diff --git a/godot/addons/panku_console/modules/native_logger/log_view_tag.gd b/godot/addons/panku_console/modules/native_logger/log_view_tag.gd new file mode 100644 index 0000000..280b00b --- /dev/null +++ b/godot/addons/panku_console/modules/native_logger/log_view_tag.gd @@ -0,0 +1,12 @@ +extends Control + +@export var tag_btn:Button +@export var rm_btn:Button + +var tag_text:String +var tag_number:int = 0 + +func check(message:String): + if message.contains(tag_text): + tag_number += 1 + tag_btn.text = "%s (%d)" % [tag_text, tag_number] diff --git a/godot/addons/panku_console/modules/native_logger/log_view_tag.gd.uid b/godot/addons/panku_console/modules/native_logger/log_view_tag.gd.uid new file mode 100644 index 0000000..ffc42e5 --- /dev/null +++ b/godot/addons/panku_console/modules/native_logger/log_view_tag.gd.uid @@ -0,0 +1 @@ +uid://d1cqmpqf4q3if diff --git a/godot/addons/panku_console/modules/native_logger/log_view_tag.tscn b/godot/addons/panku_console/modules/native_logger/log_view_tag.tscn new file mode 100644 index 0000000..66762cd --- /dev/null +++ b/godot/addons/panku_console/modules/native_logger/log_view_tag.tscn @@ -0,0 +1,47 @@ +[gd_scene load_steps=6 format=3 uid="uid://dpurdc5me82ds"] + +[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="1_e0ejw"] +[ext_resource type="Script" path="res://addons/panku_console/modules/native_logger/log_view_tag.gd" id="2_ia8vx"] +[ext_resource type="PackedScene" uid="uid://drn5t13m088fb" path="res://addons/panku_console/common/panku_button.tscn" id="3_cc2ep"] +[ext_resource type="Texture2D" uid="uid://8g5afcuanbl6" path="res://addons/panku_console/res/icons2/close.svg" id="4_msugh"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_jvhll"] +bg_color = Color(1, 1, 1, 1) +corner_radius_top_left = 2 +corner_radius_top_right = 2 +corner_radius_bottom_right = 2 +corner_radius_bottom_left = 2 +shadow_color = Color(0, 0, 0, 0.188235) +shadow_size = 1 +shadow_offset = Vector2(1, 1) + +[node name="LoggerViewTag" type="PanelContainer" node_paths=PackedStringArray("tag_btn", "rm_btn")] +self_modulate = Color(0.027451, 0.490196, 0.333333, 1) +offset_right = 123.0 +offset_bottom = 31.0 +size_flags_vertical = 4 +theme = ExtResource("1_e0ejw") +theme_override_styles/panel = SubResource("StyleBoxFlat_jvhll") +script = ExtResource("2_ia8vx") +tag_btn = NodePath("HBoxContainer/Button") +rm_btn = NodePath("HBoxContainer/Button2/Button") + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 +theme_override_constants/separation = 0 + +[node name="Button" type="Button" parent="HBoxContainer"] +layout_mode = 2 +text = "[info] (428)" +flat = true + +[node name="Button2" parent="HBoxContainer" instance=ExtResource("3_cc2ep")] +layout_mode = 2 + +[node name="Button" parent="HBoxContainer/Button2" index="0"] +flat = true + +[node name="TextureRect" parent="HBoxContainer/Button2/HBoxContainer" index="0"] +texture = ExtResource("4_msugh") + +[editable path="HBoxContainer/Button2"] diff --git a/godot/addons/panku_console/modules/native_logger/logger_view.gd b/godot/addons/panku_console/modules/native_logger/logger_view.gd new file mode 100644 index 0000000..7cd31d1 --- /dev/null +++ b/godot/addons/panku_console/modules/native_logger/logger_view.gd @@ -0,0 +1,150 @@ +extends Control + +signal content_updated(bbcode:String) + +var console:PankuConsole +var _module:PankuModule + +const MAX_LOGS = 128 + +@export var tag_prefab:PackedScene +@export var search_box:LineEdit +@export var search_btn:Button +@export var pin_btn:Button +@export var cls_btn:Button +@export var tags_container2:ScrollContainer +@export var tags_container:HBoxContainer +@export var rlabel:RichTextLabel + +var current_filter:String = "" +var logs:Array = [] + +const CFG_LOGGER_TAGS = "logger_tags" +const CFG_LOGGER_OUTPUT_FONT_SIZE = "logger_output_font_size" + +#level: #1.info 2.warning 3.error +func add_log(message:String, level:int): + #add prefix + if level == 2: + message = "[bgcolor=yellow][color=black][warning][/color][/bgcolor] " + message + elif level == 3: + message = "[bgcolor=red][color=white][error][/color][/bgcolor] " + message + + #update tags + for tag in tags_container.get_children(): + tag.check(message) + + if logs.size() > 0: + var last_log = logs.back() + if (last_log["message"] == message) and (Time.get_unix_time_from_system() - last_log["timestamp"] < 1.0): + last_log["count"] += 1 + last_log["timestamp"] = Time.get_unix_time_from_system() + update_view() + return + + logs.push_back({ + "message": message, + "level": level, + "timestamp": Time.get_unix_time_from_system(), + "count": 1 + }) + + #TODO: support more logs + if logs.size() >= MAX_LOGS: + logs = logs.slice(int(MAX_LOGS / 2)) + + update_view() + +func search(filter_string:String): + current_filter = filter_string + search_box.text = current_filter + update_view() + +func clear_all(): + logs.clear() + update_view() + +func add_tag(filter_string:String): + if filter_string.trim_prefix(" ").trim_suffix(" ").is_empty(): + return + var tag = tag_prefab.instantiate() + tag.tag_btn.text = filter_string + tag.tag_text = filter_string + tag.tag_btn.pressed.connect( + func(): + search(filter_string) + ) + tag.rm_btn.pressed.connect( + func(): + if tags_container.get_child_count() == 1: + tags_container2.hide() + tag.queue_free() + ) + #special treatment + if filter_string == "[warning]": + tag.self_modulate = Color("#f5c518") + tag.tag_btn.self_modulate = Color("#0a1014") + tag.rm_btn.self_modulate = Color("#0a1014") + elif filter_string == "[error]": + tag.self_modulate = Color("#d91f11") + + tags_container.add_child(tag) + tags_container2.show() + +func update_view(): + #TODO: optimization + var result:PackedStringArray = PackedStringArray() + + for log in logs: + if !current_filter.is_empty() and !log["message"].contains(current_filter): + continue + var s = "" + if log["level"] == 1: + s = log["message"] + elif log["level"] == 2: + s = "[color=#e1ed96]%s[/color]" % log["message"] + elif log["level"] == 3: + s = "[color=#dd7085]%s[/color]" % log["message"] + if log["count"] > 1: + s = "[b](%d)[/b] %s" % [log["count"], s] + # add timestamp prefix + if _module.show_timestamp: + var time_str := Time.get_time_string_from_unix_time(log["timestamp"] + Time.get_time_zone_from_system()['bias'] * 60) + s = "[color=#a0a0a0][%s][/color] %s" % [time_str, s] + result.append(s) + + var content:String = "\n".join(result) + #sync content + rlabel.text = content + content_updated.emit(content) + +func load_data(data:Array): + for item in data: + var text:String = item + add_tag(text) + +func get_data() -> Array: + var tags := PackedStringArray() + for tag in tags_container.get_children(): + tags.push_back(tag.tag_text) + return tags + +func _ready(): + + #ui callbacks + search_btn.pressed.connect( + func(): + search(search_box.text) + ) + search_box.text_submitted.connect( + func(text:String): + search(search_box.text) + ) + pin_btn.pressed.connect( + func(): + add_tag(search_box.text) + search_box.clear() + ) + cls_btn.pressed.connect(clear_all) + + clear_all() diff --git a/godot/addons/panku_console/modules/native_logger/logger_view.gd.uid b/godot/addons/panku_console/modules/native_logger/logger_view.gd.uid new file mode 100644 index 0000000..587aeec --- /dev/null +++ b/godot/addons/panku_console/modules/native_logger/logger_view.gd.uid @@ -0,0 +1 @@ +uid://duhsvwne7e1il diff --git a/godot/addons/panku_console/modules/native_logger/logger_view.tscn b/godot/addons/panku_console/modules/native_logger/logger_view.tscn new file mode 100644 index 0000000..5bb6e3c --- /dev/null +++ b/godot/addons/panku_console/modules/native_logger/logger_view.tscn @@ -0,0 +1,136 @@ +[gd_scene load_steps=5 format=3 uid="uid://b1c075ic6oru7"] + +[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="1_gcj58"] +[ext_resource type="PackedScene" uid="uid://dpurdc5me82ds" path="res://addons/panku_console/modules/native_logger/log_view_tag.tscn" id="2_06ga0"] +[ext_resource type="Script" path="res://addons/panku_console/modules/native_logger/logger_view.gd" id="2_8mrs2"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ggi4i"] +bg_color = Color(0.6, 0.6, 0.6, 0) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color(0.639216, 0.639216, 0.639216, 0.501961) + +[node name="logger_view" type="Control" node_paths=PackedStringArray("search_box", "search_btn", "pin_btn", "cls_btn", "tags_container2", "tags_container", "rlabel")] +clip_contents = true +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_right = -882.0 +offset_bottom = -417.0 +grow_horizontal = 2 +grow_vertical = 2 +theme = ExtResource("1_gcj58") +script = ExtResource("2_8mrs2") +tag_prefab = ExtResource("2_06ga0") +search_box = NodePath("VBoxContainer/HBoxContainer/LineEdit") +search_btn = NodePath("VBoxContainer/HBoxContainer/Button") +pin_btn = NodePath("VBoxContainer/HBoxContainer/Button2") +cls_btn = NodePath("VBoxContainer/HBoxContainer/Button3") +tags_container2 = NodePath("VBoxContainer/ScrollContainer") +tags_container = NodePath("VBoxContainer/ScrollContainer/HBoxContainer/HBoxContainer2") +rlabel = NodePath("VBoxContainer/PanelContainer/MarginContainer/RichTextLabel") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="Control" type="Control" parent="VBoxContainer"] +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 2 + +[node name="LineEdit" type="LineEdit" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "search..." +clear_button_enabled = true + +[node name="Button" type="Button" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "OK" + +[node name="Button2" type="Button" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Pin" + +[node name="Button3" type="Button" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Clear All" + +[node name="ScrollContainer" type="ScrollContainer" parent="VBoxContainer"] +visible = false +custom_minimum_size = Vector2(0, 24) +layout_mode = 2 +vertical_scroll_mode = 0 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/ScrollContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="Label" type="Label" parent="VBoxContainer/ScrollContainer/HBoxContainer"] +layout_mode = 2 +size_flags_vertical = 1 +text = " Tags: " +vertical_alignment = 1 + +[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer/ScrollContainer/HBoxContainer"] +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="PanelContainer" type="PanelContainer" parent="VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +theme_override_styles/panel = SubResource("StyleBoxFlat_ggi4i") + +[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/PanelContainer"] +layout_mode = 2 +theme_override_constants/margin_left = 8 +theme_override_constants/margin_top = 8 +theme_override_constants/margin_right = 8 +theme_override_constants/margin_bottom = 8 + +[node name="RichTextLabel" type="RichTextLabel" parent="VBoxContainer/PanelContainer/MarginContainer"] +layout_mode = 2 +bbcode_enabled = true +text = "Hello +Some text here +Hello +Some text here +Hello +Some text here +Hello +Some text here +Hello +Some text here +Hello +Some text here +Hello +Some text here +Hello +Some text here +Hello +Some text here +Hello +Some text here +Hello +Some text here +Hello +Some text here +Hello +Some text here +Hello +Some text here +Hello +Some text here" +scroll_following = true diff --git a/godot/addons/panku_console/modules/native_logger/module.gd b/godot/addons/panku_console/modules/native_logger/module.gd new file mode 100644 index 0000000..eaeb555 --- /dev/null +++ b/godot/addons/panku_console/modules/native_logger/module.gd @@ -0,0 +1,99 @@ +class_name PankuModuleNativeLogger extends PankuModule + +var output_overlay:RichTextLabel +var native_logs_monitor:Node +var window:PankuLynxWindow +var logger_ui:Node +var output_overlay_display_mode:ScreenOverlayDisplayMode +var show_timestamp:bool + +enum ScreenOverlayDisplayMode { + AlwaysShow, + ShowIfShellVisible, + NeverShow +} + +func init_module(): + # add godot log monitor + native_logs_monitor = preload("./godot_log_monitor.gd").new() + core.add_child(native_logs_monitor) + + # add output overlay + output_overlay = preload("./log_overlay.tscn").instantiate() + output_overlay.clear() + core.add_child(output_overlay) + + # add logger window + logger_ui = preload("./logger_view.tscn").instantiate() + logger_ui._module = self + logger_ui.console = core + + window = core.windows_manager.create_window(logger_ui) + add_auto_save_hook(window) + window.queue_free_on_close = false + window.set_window_title_text("Native Logger") + + native_logs_monitor.error_msg_received.connect( + func(msg:String): + logger_ui.add_log(msg, 3) + ) + native_logs_monitor.warning_msg_received.connect( + func(msg:String): + logger_ui.add_log(msg, 2) + ) + native_logs_monitor.info_msg_received.connect( + func(msg:String): + logger_ui.add_log(msg, 1) + ) + logger_ui.content_updated.connect( + func(bbcode:String): + output_overlay.text = bbcode + ) + + core.interactive_shell_visibility_changed.connect( + func(v:bool): + if output_overlay_display_mode == ScreenOverlayDisplayMode.ShowIfShellVisible: + output_overlay.visible = v + ) + + # load data + load_window_data(window) + get_module_opt().screen_overlay = load_module_data("screen_overlay", ScreenOverlayDisplayMode.AlwaysShow) + get_module_opt().screen_overlay_alpha = load_module_data("screen_overlay_alpha", 0.3) + get_module_opt().screen_overlay_color = load_module_data("screen_overlay_color", Color(1, 1, 1, 0.878)) + get_module_opt().screen_overlay_font_shadow = load_module_data("screen_overlay_font_shadow", false) + get_module_opt().screen_overlay_override_font_size = load_module_data("screen_overlay_override_font_size", 0) + get_module_opt().show_timestamp = load_module_data("show_timestamp", true) + logger_ui.load_data(load_module_data("logger_tags", ["[error]", "[warning]"])) + +func quit_module(): + super.quit_module() + # properties defined in opt.gd will be automatically saved as soon as the value is changed + # we only need to manually save properties outside opt.gd + save_window_data(window) + save_module_data("logger_tags", logger_ui.get_data()) + +func open_window(): + window.show_window() + +func toggle_overlay(): + var next = { + ScreenOverlayDisplayMode.AlwaysShow: ScreenOverlayDisplayMode.NeverShow, + ScreenOverlayDisplayMode.ShowIfShellVisible: ScreenOverlayDisplayMode.NeverShow, + ScreenOverlayDisplayMode.NeverShow: ScreenOverlayDisplayMode.AlwaysShow + } + output_overlay_display_mode = next[output_overlay_display_mode] + set_overlay_display_mode(output_overlay_display_mode) + +func set_overlay_display_mode(mode:ScreenOverlayDisplayMode): + output_overlay_display_mode = mode + if output_overlay_display_mode == ScreenOverlayDisplayMode.AlwaysShow: + output_overlay.visible = true + elif output_overlay_display_mode == ScreenOverlayDisplayMode.ShowIfShellVisible: + output_overlay.visible = core.get_shell_visibility() + elif output_overlay_display_mode == ScreenOverlayDisplayMode.NeverShow: + output_overlay.visible = false + +func set_show_timestamp(v:bool): + show_timestamp = v + logger_ui.update_view() diff --git a/godot/addons/panku_console/modules/native_logger/module.gd.uid b/godot/addons/panku_console/modules/native_logger/module.gd.uid new file mode 100644 index 0000000..1b1426f --- /dev/null +++ b/godot/addons/panku_console/modules/native_logger/module.gd.uid @@ -0,0 +1 @@ +uid://bkaci1j5h5nwf diff --git a/godot/addons/panku_console/modules/native_logger/opt.gd b/godot/addons/panku_console/modules/native_logger/opt.gd new file mode 100644 index 0000000..4b0a339 --- /dev/null +++ b/godot/addons/panku_console/modules/native_logger/opt.gd @@ -0,0 +1,67 @@ +extends ModuleOptions + +@export_group("native_logger") + +@export var export_button_open_window := "Open Logger Window" +func open_window(): + _module.open_window() + +@export var export_comment_1 = "The logger is built upon the native engine file logging utility." + +@export var export_button_open_engine_log_folder:String = "Open Engine Logs Folder" + +@export_enum("Always Show", "Show If Shell Visible", "Never Show") var screen_overlay:int: + set(v): + _module.set_overlay_display_mode(v) + get: + return _module.output_overlay_display_mode + +@export var show_timestamp:bool = true: + set(v): + _module.set_show_timestamp(v) + get: + return _module.show_timestamp + +@export_range(0.0, 1.0, 0.01) var screen_overlay_alpha:float = 0.5: + set(v): + _module.output_overlay.modulate.a = v + get: + return _module.output_overlay.modulate.a + +@export var screen_overlay_color:Color: + set(v): + _module.output_overlay["theme_override_colors/default_color"] = v + get: + return _module.output_overlay["theme_override_colors/default_color"] + +@export var screen_overlay_override_font_size:int = 0: + set(v): + var overlay:RichTextLabel = _module.output_overlay + if (v <= 0): + overlay.remove_theme_font_size_override("normal_font_size") + overlay.remove_theme_font_size_override("bold_font_size") + overlay.remove_theme_font_size_override("italics_font_size") + overlay.remove_theme_font_size_override("bold_italics_font_size") + overlay.remove_theme_font_size_override("mono_font_size") + else: + overlay.add_theme_font_size_override("normal_font_size", v) + overlay.add_theme_font_size_override("bold_font_size", v) + overlay.add_theme_font_size_override("italics_font_size", v) + overlay.add_theme_font_size_override("bold_italics_font_size", v) + overlay.add_theme_font_size_override("mono_font_size", v) + get: + #return _module.output_overlay.theme.default_font_size + var overlay:RichTextLabel = _module.output_overlay + if overlay.has_theme_font_size_override("normal_font_size"): + return overlay.get("theme_override_font_sizes/normal_font_size") + return 0 + +@export var screen_overlay_font_shadow:bool = false: + set(v): + var val = Color.BLACK if v else null + _module.output_overlay.set("theme_override_colors/font_shadow_color", val) + get: + return _module.output_overlay.get("theme_override_colors/font_shadow_color") != null + +func open_engine_log_folder(): + OS.shell_open(ProjectSettings.globalize_path(ProjectSettings.get_setting("debug/file_logging/log_path").get_base_dir())) diff --git a/godot/addons/panku_console/modules/native_logger/opt.gd.uid b/godot/addons/panku_console/modules/native_logger/opt.gd.uid new file mode 100644 index 0000000..e680c9e --- /dev/null +++ b/godot/addons/panku_console/modules/native_logger/opt.gd.uid @@ -0,0 +1 @@ +uid://ue3kbguiqdvt diff --git a/godot/addons/panku_console/modules/screen_crt_effect/crt_effect_layer.tscn b/godot/addons/panku_console/modules/screen_crt_effect/crt_effect_layer.tscn new file mode 100644 index 0000000..201c93c --- /dev/null +++ b/godot/addons/panku_console/modules/screen_crt_effect/crt_effect_layer.tscn @@ -0,0 +1,18 @@ +[gd_scene load_steps=3 format=3 uid="uid://c0hv8f6lk2d2d"] + +[ext_resource type="Shader" path="res://addons/panku_console/res/shader/mattias_crt.gdshader" id="1_ulpy0"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_p7j4u"] +shader = ExtResource("1_ulpy0") + +[node name="CrtEffectLayer" type="CanvasLayer"] +layer = 64 + +[node name="ColorRect" type="ColorRect" parent="."] +material = SubResource("ShaderMaterial_p7j4u") +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 diff --git a/godot/addons/panku_console/modules/screen_crt_effect/env.gd b/godot/addons/panku_console/modules/screen_crt_effect/env.gd new file mode 100644 index 0000000..32387fa --- /dev/null +++ b/godot/addons/panku_console/modules/screen_crt_effect/env.gd @@ -0,0 +1,5 @@ +var _module:PankuModule + +const _HELP_toggle = "The good old days" +func toggle() -> void: + _module.toggle_crt_effect() \ No newline at end of file diff --git a/godot/addons/panku_console/modules/screen_crt_effect/env.gd.uid b/godot/addons/panku_console/modules/screen_crt_effect/env.gd.uid new file mode 100644 index 0000000..511edba --- /dev/null +++ b/godot/addons/panku_console/modules/screen_crt_effect/env.gd.uid @@ -0,0 +1 @@ +uid://bvru8qq3ixkex diff --git a/godot/addons/panku_console/modules/screen_crt_effect/module.gd b/godot/addons/panku_console/modules/screen_crt_effect/module.gd new file mode 100644 index 0000000..edd5fe9 --- /dev/null +++ b/godot/addons/panku_console/modules/screen_crt_effect/module.gd @@ -0,0 +1,11 @@ +class_name PankuModuleScreenCrtEffect extends PankuModule + +var crt_effect_enabled := false +var crt_effect_layer:CanvasLayer = null + +func toggle_crt_effect(): + crt_effect_enabled = !crt_effect_enabled + if crt_effect_layer == null: + crt_effect_layer = preload("./crt_effect_layer.tscn").instantiate() + core.add_child(crt_effect_layer) + crt_effect_layer.visible = crt_effect_enabled diff --git a/godot/addons/panku_console/modules/screen_crt_effect/module.gd.uid b/godot/addons/panku_console/modules/screen_crt_effect/module.gd.uid new file mode 100644 index 0000000..c38f4f1 --- /dev/null +++ b/godot/addons/panku_console/modules/screen_crt_effect/module.gd.uid @@ -0,0 +1 @@ +uid://c3brv46wbx5e3 diff --git a/godot/addons/panku_console/modules/screen_crt_effect/opt.gd b/godot/addons/panku_console/modules/screen_crt_effect/opt.gd new file mode 100644 index 0000000..1f6c8ef --- /dev/null +++ b/godot/addons/panku_console/modules/screen_crt_effect/opt.gd @@ -0,0 +1,16 @@ +extends ModuleOptions + +@export_group("screen_crt_effect") + +@export var export_button_toggle_crt_effect:String = "Toggle Effect" + +func toggle_crt_effect(): + _module.toggle_crt_effect() + +func set_unified_window_visibility(enabled:bool): + _module.unified_window_visibility = enabled + _module.update_gui_state() + +func set_pause_if_popup(enabled:bool): + _module.pause_if_input = enabled + _module.update_gui_state() diff --git a/godot/addons/panku_console/modules/screen_crt_effect/opt.gd.uid b/godot/addons/panku_console/modules/screen_crt_effect/opt.gd.uid new file mode 100644 index 0000000..261cb4e --- /dev/null +++ b/godot/addons/panku_console/modules/screen_crt_effect/opt.gd.uid @@ -0,0 +1 @@ +uid://rp7jyp4t82se diff --git a/godot/addons/panku_console/modules/screen_notifier/env.gd b/godot/addons/panku_console/modules/screen_notifier/env.gd new file mode 100644 index 0000000..dada0ab --- /dev/null +++ b/godot/addons/panku_console/modules/screen_notifier/env.gd @@ -0,0 +1,5 @@ +var _module:PankuModule + +const _HELP_notify = "Generate a notification" +func notify(any): + _module.notify(str(any)) diff --git a/godot/addons/panku_console/modules/screen_notifier/env.gd.uid b/godot/addons/panku_console/modules/screen_notifier/env.gd.uid new file mode 100644 index 0000000..f5c6be8 --- /dev/null +++ b/godot/addons/panku_console/modules/screen_notifier/env.gd.uid @@ -0,0 +1 @@ +uid://cs1wfvhlljx4k diff --git a/godot/addons/panku_console/modules/screen_notifier/log_item.gd b/godot/addons/panku_console/modules/screen_notifier/log_item.gd new file mode 100644 index 0000000..322bef1 --- /dev/null +++ b/godot/addons/panku_console/modules/screen_notifier/log_item.gd @@ -0,0 +1,54 @@ +extends HBoxContainer + +var life = 2.0 + +var amount := 1: + set(v): + amount = v + play_amount_pop_animation() + +@export var content_label:RichTextLabel +@export var amount_label:Label +@export var amount_panel:PanelContainer + +@export var progress_a:Panel +@export var progress_b:Control + +var amount_pop_tween:Tween +var life_tween:Tween + +func play_amount_pop_animation(): + if amount_pop_tween: amount_pop_tween.kill() + amount_pop_tween = create_tween() + amount_pop_tween.tween_property(amount_panel, "scale", Vector2(1, 1), 0.01) + amount_pop_tween.tween_property(amount_panel, "scale", Vector2(1.2, 1.2), 0.05) + amount_pop_tween.tween_property(amount_panel, "scale", Vector2(1, 1), 0.05) + +func fade_out(): + var tween = create_tween() + tween.tween_property(self, "modulate:a", 0.0, 0.2) + tween.tween_callback(queue_free).set_delay(0.2) + +func set_progress(v:float): + progress_a.size_flags_stretch_ratio = v + progress_b.size_flags_stretch_ratio = 1.0 - v + +func play_lifespan_animation(): + # interrupt and clear current tween animation + if life_tween: life_tween.kill() + life_tween = create_tween() + # create new tween animations + life_tween.tween_property(self, "modulate:a", 1.0, 0.2) + life_tween.set_parallel(true) + life_tween.tween_method(set_progress, 1.0, 0.0, life) + life_tween.set_parallel(false) + life_tween.tween_property(self, "modulate:a", 0.0, 0.2) + life_tween.tween_callback(queue_free).set_delay(0.2) + + +func _ready(): + content_label.meta_clicked.connect( + func(meta): + OS.shell_open(str(meta)) + ) + play_lifespan_animation() diff --git a/godot/addons/panku_console/modules/screen_notifier/log_item.gd.uid b/godot/addons/panku_console/modules/screen_notifier/log_item.gd.uid new file mode 100644 index 0000000..b7460be --- /dev/null +++ b/godot/addons/panku_console/modules/screen_notifier/log_item.gd.uid @@ -0,0 +1 @@ +uid://b0t7xy10eu58i diff --git a/godot/addons/panku_console/modules/screen_notifier/log_item.tscn b/godot/addons/panku_console/modules/screen_notifier/log_item.tscn new file mode 100644 index 0000000..2fd60d8 --- /dev/null +++ b/godot/addons/panku_console/modules/screen_notifier/log_item.tscn @@ -0,0 +1,83 @@ +[gd_scene load_steps=4 format=3 uid="uid://c8rfpfel4mqtm"] + +[ext_resource type="Script" path="res://addons/panku_console/modules/screen_notifier/log_item.gd" id="1_2q8bu"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_1ons3"] +bg_color = Color(0, 0, 0, 0.501961) +border_color = Color(0.8, 1, 1, 1) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_loh7i"] +bg_color = Color(1, 1, 1, 0.12549) + +[node name="LogItem" type="HBoxContainer" node_paths=PackedStringArray("content_label", "amount_label", "amount_panel", "progress_a", "progress_b")] +offset_right = 320.0 +offset_bottom = 26.0 +mouse_filter = 2 +theme_override_constants/separation = 2 +script = ExtResource("1_2q8bu") +content_label = NodePath("Content/MarginContainer/RichTextLabel") +amount_label = NodePath("Amount/MarginContainer/Label") +amount_panel = NodePath("Amount") +progress_a = NodePath("Content/HBoxContainer/A") +progress_b = NodePath("Content/HBoxContainer/B") +metadata/content_label = NodePath("Content/MarginContainer/RichTextLabel") +metadata/amount_label = NodePath("Amount/MarginContainer/Label") +metadata/amount_panel = NodePath("Amount") + +[node name="ColorRect" type="ColorRect" parent="."] +custom_minimum_size = Vector2(4, 0) +layout_mode = 2 +mouse_filter = 2 +color = Color(0, 0.752941, 0, 1) + +[node name="Content" type="PanelContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_1ons3") + +[node name="HBoxContainer" type="HBoxContainer" parent="Content"] +layout_mode = 2 +mouse_filter = 2 +theme_override_constants/separation = 0 + +[node name="A" type="Panel" parent="Content/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 0.4 +mouse_filter = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_loh7i") + +[node name="B" type="Control" parent="Content/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 0.6 +mouse_filter = 2 + +[node name="MarginContainer" type="MarginContainer" parent="Content"] +layout_mode = 2 +mouse_filter = 2 +theme_override_constants/margin_left = 8 + +[node name="RichTextLabel" type="RichTextLabel" parent="Content/MarginContainer"] +layout_mode = 2 +mouse_filter = 2 +bbcode_enabled = true +text = "yoooooooooo~" +fit_content = true + +[node name="Amount" type="PanelContainer" parent="."] +layout_mode = 2 +mouse_filter = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_1ons3") + +[node name="MarginContainer" type="MarginContainer" parent="Amount"] +layout_mode = 2 +mouse_filter = 2 +theme_override_constants/margin_left = 4 +theme_override_constants/margin_right = 4 + +[node name="Label" type="Label" parent="Amount/MarginContainer"] +layout_mode = 2 +text = "x1" +metadata/amount = 1 diff --git a/godot/addons/panku_console/modules/screen_notifier/module.gd b/godot/addons/panku_console/modules/screen_notifier/module.gd new file mode 100644 index 0000000..9a7d3a4 --- /dev/null +++ b/godot/addons/panku_console/modules/screen_notifier/module.gd @@ -0,0 +1,12 @@ +class_name PankuModuleScreenNotifier extends PankuModule + +var notifier_layer := preload("./resident_logs.tscn").instantiate() + +func notify(bbcode:String, id:=-1): + notifier_layer.add_log(bbcode, id) + +func init_module(): + core.new_notification_created.connect(notify) + + # setup ui + core.add_child(notifier_layer) diff --git a/godot/addons/panku_console/modules/screen_notifier/module.gd.uid b/godot/addons/panku_console/modules/screen_notifier/module.gd.uid new file mode 100644 index 0000000..f463e5f --- /dev/null +++ b/godot/addons/panku_console/modules/screen_notifier/module.gd.uid @@ -0,0 +1 @@ +uid://c7up8ardl8443 diff --git a/godot/addons/panku_console/modules/screen_notifier/resident_logs.gd b/godot/addons/panku_console/modules/screen_notifier/resident_logs.gd new file mode 100644 index 0000000..9b5b061 --- /dev/null +++ b/godot/addons/panku_console/modules/screen_notifier/resident_logs.gd @@ -0,0 +1,57 @@ +extends CanvasLayer + +const logitem2_proto := preload("./log_item.tscn") + +const MAX_LOGS = 10 + +var prev_log = "" + +@export var named_container:VBoxContainer +@export var unnamed_container:VBoxContainer + +# logs whose id >= 0 +var named_logs := {} + + +func add_log(bbcode:String, id:=-1): + # logs whose id>=0 will be fixed to the bottom of the log list + # useful for loop print + # you can use `get_instance_id()` as logs's unique id + if id >= 0: + if !named_logs.has(id): + var new_node = logitem2_proto.instantiate() + new_node.amount_panel.hide() + new_node.life = 1.0 + new_node.get_node("ColorRect").color = Color("#23aaf277") + named_container.add_child(new_node) + named_container.move_child(new_node, 0) + named_logs[id] = new_node + new_node.tree_exiting.connect( + func(): + named_logs.erase(id) + ) + var log_node = named_logs[id] + named_logs[id].content_label.text = bbcode + log_node.play_lifespan_animation() + return + + #see the new log if can be combined with previous one + if prev_log == bbcode and unnamed_container.get_child_count() > 0: + var prev_node = unnamed_container.get_child(unnamed_container.get_child_count() - 1) + prev_node.amount += 1 + prev_node.amount_label.text = "x" + str(prev_node.amount) + prev_node.amount_panel.show() + prev_node.play_lifespan_animation() + #create new log node + else: + if unnamed_container.get_child_count() >= MAX_LOGS: + unnamed_container.get_child(0).fade_out() + if get_tree(): + var new_node = logitem2_proto.instantiate() + new_node.content_label.text = bbcode + new_node.amount_panel.hide() + new_node.get_node("ColorRect").color = Color(0.0, 0.75, 0.0, 0.5) + await get_tree().process_frame + unnamed_container.add_child(new_node) + + prev_log = bbcode diff --git a/godot/addons/panku_console/modules/screen_notifier/resident_logs.gd.uid b/godot/addons/panku_console/modules/screen_notifier/resident_logs.gd.uid new file mode 100644 index 0000000..f97d599 --- /dev/null +++ b/godot/addons/panku_console/modules/screen_notifier/resident_logs.gd.uid @@ -0,0 +1 @@ +uid://bvgmltgih3fmw diff --git a/godot/addons/panku_console/modules/screen_notifier/resident_logs.tscn b/godot/addons/panku_console/modules/screen_notifier/resident_logs.tscn new file mode 100644 index 0000000..8d24856 --- /dev/null +++ b/godot/addons/panku_console/modules/screen_notifier/resident_logs.tscn @@ -0,0 +1,30 @@ +[gd_scene load_steps=3 format=3 uid="uid://ccr06ddwa73ca"] + +[ext_resource type="Script" path="res://addons/panku_console/modules/screen_notifier/resident_logs.gd" id="1_uq2bh"] +[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="2_npyp1"] + +[node name="ScreenNotifier" type="CanvasLayer" node_paths=PackedStringArray("named_container", "unnamed_container")] +script = ExtResource("1_uq2bh") +named_container = NodePath("ResidentLogs/Named") +unnamed_container = NodePath("ResidentLogs/Unnamed") + +[node name="ResidentLogs" type="VBoxContainer" parent="."] +anchors_preset = -1 +anchor_top = 0.25 +anchor_right = 0.5 +anchor_bottom = 0.75 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +theme = ExtResource("2_npyp1") +alignment = 2 + +[node name="Unnamed" type="VBoxContainer" parent="ResidentLogs"] +layout_mode = 2 +mouse_filter = 2 +alignment = 2 + +[node name="Named" type="VBoxContainer" parent="ResidentLogs"] +layout_mode = 2 +mouse_filter = 2 +alignment = 2 diff --git a/godot/addons/panku_console/modules/snake/env.gd b/godot/addons/panku_console/modules/snake/env.gd new file mode 100644 index 0000000..addf5b8 --- /dev/null +++ b/godot/addons/panku_console/modules/snake/env.gd @@ -0,0 +1,11 @@ +var _module:PankuModule + +const _HELP_execute = "Play Snake Game" +func play() -> void: + _module.add_snake_window() + +func leader_board() -> String: + var content = "" + content += "== Learder Board ==\n" + content += str(_module.leader_board_arr) + return content diff --git a/godot/addons/panku_console/modules/snake/env.gd.uid b/godot/addons/panku_console/modules/snake/env.gd.uid new file mode 100644 index 0000000..7553b74 --- /dev/null +++ b/godot/addons/panku_console/modules/snake/env.gd.uid @@ -0,0 +1 @@ +uid://bf1jqeceg682p diff --git a/godot/addons/panku_console/modules/snake/module.gd b/godot/addons/panku_console/modules/snake/module.gd new file mode 100644 index 0000000..da74fe8 --- /dev/null +++ b/godot/addons/panku_console/modules/snake/module.gd @@ -0,0 +1,37 @@ +class_name PankuModuleSnakeGame extends PankuModule + +var leader_board_arr = [] + +func init_module(): + leader_board_arr = load_module_data("leader_board", []) + +func add_snake_window(): + var snake_ui := preload("res://addons/panku_console/modules/snake/snake.tscn").instantiate() + var window:PankuLynxWindow = core.windows_manager.create_window(snake_ui) + window.queue_free_on_close = true + window.set_window_title_text("Snake Game") + window.position = window.get_layout_position(Control.PRESET_CENTER) + window.move_to_front() + window.size = Vector2( + snake_ui.snake_game.MAP_SIZE * snake_ui.CELL_SIZE, 0) + window.size.y = window.size.x + 24 + + core.get_tree().root.get_viewport().gui_release_focus() + + snake_ui.snake_game.game_over.connect( + func(): + var record = { + "timestamp": Time.get_datetime_string_from_system(), + "score": snake_ui.snake_game.get_snake_length() + } + leader_board_arr.append(record) + leader_board_arr.sort_custom( + func(a, b): + return a['score'] > b['score'] + ) + + if leader_board_arr.size() > 10: + leader_board_arr.resize(10) + + save_module_data("leader_board", leader_board_arr) + ) diff --git a/godot/addons/panku_console/modules/snake/module.gd.uid b/godot/addons/panku_console/modules/snake/module.gd.uid new file mode 100644 index 0000000..7f05291 --- /dev/null +++ b/godot/addons/panku_console/modules/snake/module.gd.uid @@ -0,0 +1 @@ +uid://bclkgkqflmetk diff --git a/godot/addons/panku_console/modules/snake/snake.gd b/godot/addons/panku_console/modules/snake/snake.gd new file mode 100644 index 0000000..43b400d --- /dev/null +++ b/godot/addons/panku_console/modules/snake/snake.gd @@ -0,0 +1,71 @@ +signal game_over + +const MAP_SIZE = 24 + +const DIR_REV = { + Vector2.LEFT: Vector2.RIGHT, + Vector2.RIGHT: Vector2.LEFT, + Vector2.UP: Vector2.DOWN, + Vector2.DOWN: Vector2.UP, +} + +var snake_dict:Dictionary +var snake_arr:Array +var apple:Vector2 +var move_dir:Vector2 + +func _init() -> void: + init() + +func init() -> void: + + # init snake. 0:head, -1:tail + snake_dict = {Vector2(9, 8):0, Vector2(8, 8):0} + snake_arr = snake_dict.keys() + + # init apple + apple = spawn_apple() + + move_dir = Vector2.RIGHT + +func get_snake_length() -> int: + return snake_arr.size() + +func spawn_apple() -> Vector2: + var x_range = range(MAP_SIZE) + x_range.shuffle() + var y_range = range(MAP_SIZE) + y_range.shuffle() + for y in y_range: + for x in x_range: + if !snake_dict.has(Vector2(x, y)): + return Vector2(x, y) + return Vector2(-1, -1) + +func tick(input_dir:Vector2): + + # can't turn back + if DIR_REV[input_dir] != move_dir: + move_dir = input_dir + + # create new head + var new_head:Vector2 = snake_arr[0] + move_dir + new_head.x = wrapi(new_head.x, 0, MAP_SIZE) + new_head.y = wrapi(new_head.y, 0, MAP_SIZE) + + # check if collide with self + if snake_dict.has(new_head): + # game over, restart + game_over.emit() + init() + return + + # add new head + snake_arr.push_front(new_head) + snake_dict[new_head] = 0 + + # remove tail if no apple + if new_head != apple: + snake_dict.erase(snake_arr.pop_back()) + else: + apple = spawn_apple() diff --git a/godot/addons/panku_console/modules/snake/snake.gd.uid b/godot/addons/panku_console/modules/snake/snake.gd.uid new file mode 100644 index 0000000..24a0fd0 --- /dev/null +++ b/godot/addons/panku_console/modules/snake/snake.gd.uid @@ -0,0 +1 @@ +uid://bcksf7pgn01vt diff --git a/godot/addons/panku_console/modules/snake/snake.tscn b/godot/addons/panku_console/modules/snake/snake.tscn new file mode 100644 index 0000000..66f7b56 --- /dev/null +++ b/godot/addons/panku_console/modules/snake/snake.tscn @@ -0,0 +1,20 @@ +[gd_scene load_steps=2 format=3 uid="uid://du6m05vxpcubk"] + +[ext_resource type="Script" path="res://addons/panku_console/modules/snake/snake_ui.gd" id="1_0yq81"] + +[node name="SnakeUI" type="Control" node_paths=PackedStringArray("tex_rect")] +clip_contents = true +layout_mode = 3 +anchors_preset = 0 +offset_right = 40.0 +offset_bottom = 40.0 +script = ExtResource("1_0yq81") +tex_rect = NodePath("Snake") + +[node name="Snake" type="TextureRect" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 diff --git a/godot/addons/panku_console/modules/snake/snake_gradient.tres b/godot/addons/panku_console/modules/snake/snake_gradient.tres new file mode 100644 index 0000000..b1ccdb3 --- /dev/null +++ b/godot/addons/panku_console/modules/snake/snake_gradient.tres @@ -0,0 +1,4 @@ +[gd_resource type="Gradient" format=3 uid="uid://chic0ft8frrr8"] + +[resource] +colors = PackedColorArray(0.156863, 0.788235, 0, 1, 0, 0.658824, 0, 0.27451) diff --git a/godot/addons/panku_console/modules/snake/snake_ui.gd b/godot/addons/panku_console/modules/snake/snake_ui.gd new file mode 100644 index 0000000..f725ce4 --- /dev/null +++ b/godot/addons/panku_console/modules/snake/snake_ui.gd @@ -0,0 +1,66 @@ +extends Control + +const CELL_SIZE = 12 +const COLOR_EMPTY = Color(0.0, 0.0, 0.0, 0.0) +const COLOR_APPLE = Color8(255, 112, 133) +const COLOR_SNAKE = preload("./snake_gradient.tres") + +@export var tex_rect:TextureRect + +const KEY_SCHEME = { + KEY_UP: Vector2.UP, + KEY_DOWN: Vector2.DOWN, + KEY_LEFT: Vector2.LEFT, + KEY_RIGHT: Vector2.RIGHT, +} + +var snake_game := preload("./snake.gd").new() +var cached_input := Vector2.RIGHT +var delay := 0.5 +var img_buffer:Image + +func _ready(): + img_buffer = Image.create( + CELL_SIZE * snake_game.MAP_SIZE, + CELL_SIZE * snake_game.MAP_SIZE, + false, Image.FORMAT_RGBA8) + draw() + +func draw(): + # draw background + img_buffer.fill(COLOR_EMPTY) + + # draw snake + var gradient = GradientTexture1D.new() + for i in range(snake_game.snake_arr.size()): + var s = snake_game.snake_arr[i] + img_buffer.fill_rect( + Rect2i(s * CELL_SIZE, Vector2.ONE * CELL_SIZE), + COLOR_SNAKE.sample(1.0 * i / snake_game.snake_arr.size()) + ) + + # draw apple + img_buffer.fill_rect( + Rect2i(snake_game.apple * CELL_SIZE, Vector2.ONE * CELL_SIZE), + COLOR_APPLE + ) + + # update texture + tex_rect.texture = ImageTexture.create_from_image(img_buffer) + +func _input(event:InputEvent): + if event is InputEventKey: + var key_event = event as InputEventKey + if key_event.pressed: + if KEY_SCHEME.has(key_event.keycode): + cached_input = KEY_SCHEME[key_event.keycode] + # if key is pressed, update immediately + delay = 0.0 + +func _physics_process(delta): + delay -= delta + if delay <= 0.0: + snake_game.tick(cached_input) + draw() + # speed up as snake grows + delay = 2.0 / min(20, snake_game.get_snake_length() / 3.0 + 3) diff --git a/godot/addons/panku_console/modules/snake/snake_ui.gd.uid b/godot/addons/panku_console/modules/snake/snake_ui.gd.uid new file mode 100644 index 0000000..ca07530 --- /dev/null +++ b/godot/addons/panku_console/modules/snake/snake_ui.gd.uid @@ -0,0 +1 @@ +uid://bgc2g8djyaiu2 diff --git a/godot/addons/panku_console/modules/system_report/env.gd b/godot/addons/panku_console/modules/system_report/env.gd new file mode 100644 index 0000000..2e86345 --- /dev/null +++ b/godot/addons/panku_console/modules/system_report/env.gd @@ -0,0 +1,9 @@ +var _os_report = preload("./os_report.gd").new() +var _module:PankuModule + +const _HELP_execute = "Show detailed OS report" +func execute() -> String: + _module.core.notify("Please wait, this may take a while...") + _os_report.inspect() + var report = "".join(_os_report.rtl) + return report diff --git a/godot/addons/panku_console/modules/system_report/env.gd.uid b/godot/addons/panku_console/modules/system_report/env.gd.uid new file mode 100644 index 0000000..5ff078b --- /dev/null +++ b/godot/addons/panku_console/modules/system_report/env.gd.uid @@ -0,0 +1 @@ +uid://bnbehkvc4pl6t diff --git a/godot/addons/panku_console/modules/system_report/module.gd b/godot/addons/panku_console/modules/system_report/module.gd new file mode 100644 index 0000000..785d693 --- /dev/null +++ b/godot/addons/panku_console/modules/system_report/module.gd @@ -0,0 +1 @@ +class_name PankuModuleSystemReport extends PankuModule diff --git a/godot/addons/panku_console/modules/system_report/module.gd.uid b/godot/addons/panku_console/modules/system_report/module.gd.uid new file mode 100644 index 0000000..0a57e7f --- /dev/null +++ b/godot/addons/panku_console/modules/system_report/module.gd.uid @@ -0,0 +1 @@ +uid://b2drqk3c8lmqe diff --git a/godot/addons/panku_console/modules/system_report/os_report.gd b/godot/addons/panku_console/modules/system_report/os_report.gd new file mode 100644 index 0000000..80fa3cc --- /dev/null +++ b/godot/addons/panku_console/modules/system_report/os_report.gd @@ -0,0 +1,168 @@ +#reference: https://github.com/godotengine/godot-demo-projects/blob/4.0-dev/misc/os_test/os_test.gd + +var rtl := PackedStringArray() + +# Returns a human-readable string from a date and time, date, or time dictionary. +func datetime_to_string(date): + if ( + date.has("year") + and date.has("month") + and date.has("day") + and date.has("hour") + and date.has("minute") + and date.has("second") + ): + # Date and time. + return "{year}-{month}-{day} {hour}:{minute}:{second}".format({ + year = str(date.year).pad_zeros(2), + month = str(date.month).pad_zeros(2), + day = str(date.day).pad_zeros(2), + hour = str(date.hour).pad_zeros(2), + minute = str(date.minute).pad_zeros(2), + second = str(date.second).pad_zeros(2), + }) + elif date.has("year") and date.has("month") and date.has("day"): + # Date only. + return "{year}-{month}-{day}".format({ + year = str(date.year).pad_zeros(2), + month = str(date.month).pad_zeros(2), + day = str(date.day).pad_zeros(2), + }) + else: + # Time only. + return "{hour}:{minute}:{second}".format({ + hour = str(date.hour).pad_zeros(2), + minute = str(date.minute).pad_zeros(2), + second = str(date.second).pad_zeros(2), + }) + + +func scan_midi_devices(): + OS.open_midi_inputs() + var devices = ", ".join(OS.get_connected_midi_inputs()) + OS.close_midi_inputs() + return devices + + +func add_header(header): + rtl.append("\n[font_size=24][color=#6df]{header}[/color][/font_size]\n\n".format({ + header = header, + })) + + +func add_line(key, value): + rtl.append("[color=#adf]{key}:[/color] {value}\n".format({ + key = key, + value = value if str(value) != "" else "[color=#fff8](empty)[/color]", + })) + + +func inspect(): + add_header("Audio") + add_line("Mix rate", "%d Hz" % AudioServer.get_mix_rate()) + add_line("Output latency", "%f ms" % (AudioServer.get_output_latency() * 1000)) + add_line("Output device list", ", ".join(AudioServer.get_output_device_list())) + add_line("Capture device list", ", ".join(AudioServer.get_input_device_list())) + + add_header("Date") + add_line("Date and time (local)", Time.get_datetime_string_from_system(false, true)) + add_line("Date and time (UTC)", Time.get_datetime_string_from_system(true, true)) + add_line("Date (local)", Time.get_date_string_from_system(false)) + add_line("Date (UTC)", Time.get_date_string_from_system(true)) + add_line("Time (local)", Time.get_time_string_from_system(false)) + add_line("Time (UTC)", Time.get_time_string_from_system(true)) + add_line("Timezone", Time.get_time_zone_from_system()) + add_line("UNIX time", Time.get_unix_time_from_system()) + + add_header("Display") + add_line("Screen count", DisplayServer.get_screen_count()) + add_line("DPI", DisplayServer.screen_get_dpi()) + add_line("Scale factor", DisplayServer.screen_get_scale()) + add_line("Maximum scale factor", DisplayServer.screen_get_max_scale()) + add_line("Startup screen position", DisplayServer.screen_get_position()) + add_line("Startup screen size", DisplayServer.screen_get_size()) + add_line("Startup screen refresh rate", ("%f Hz" % DisplayServer.screen_get_refresh_rate()) if DisplayServer.screen_get_refresh_rate() > 0.0 else "") + add_line("Usable (safe) area rectangle", DisplayServer.get_display_safe_area()) + add_line("Screen orientation", [ + "Landscape", + "Portrait", + "Landscape (reverse)", + "Portrait (reverse)", + "Landscape (defined by sensor)", + "Portrait (defined by sensor)", + "Defined by sensor", + ][DisplayServer.screen_get_orientation()]) + + add_header("Engine") + add_line("Version", Engine.get_version_info()["string"]) + add_line("Command-line arguments", str(OS.get_cmdline_args())) + add_line("Is debug build", OS.is_debug_build()) + add_line("Executable path", OS.get_executable_path()) + add_line("User data directory", OS.get_user_data_dir()) + add_line("Filesystem is persistent", OS.is_userfs_persistent()) + + add_header("Environment") + add_line("Value of `PATH`", OS.get_environment("PATH")) + add_line("Value of `path`", OS.get_environment("path")) + + add_header("Hardware") + add_line("Model name", OS.get_model_name()) + add_line("Processor name", OS.get_processor_name()) + add_line("Processor count", OS.get_processor_count()) + add_line("Device unique ID", OS.get_unique_id()) + + add_header("Input") + add_line("Device has touch screen", DisplayServer.is_touchscreen_available()) + var has_virtual_keyboard = DisplayServer.has_feature(DisplayServer.FEATURE_VIRTUAL_KEYBOARD) + add_line("Device has virtual keyboard", has_virtual_keyboard) + if has_virtual_keyboard: + add_line("Virtual keyboard height", DisplayServer.virtual_keyboard_get_height()) + + add_header("Localization") + add_line("Locale", OS.get_locale()) + + add_header("Mobile") + add_line("Granted permissions", OS.get_granted_permissions()) + +# add_header(".NET (C#)") +# var csharp_enabled = ResourceLoader.exists("res://CSharpTest.cs") +# add_line("Mono module enabled", "Yes" if csharp_enabled else "No") +# if csharp_enabled: +# csharp_test.set_script(load("res://CSharpTest.cs")) +# add_line("Operating System", csharp_test.OperatingSystem()) +# add_line("Platform Type", csharp_test.PlatformType()) + + add_header("Software") + add_line("OS name", OS.get_name()) + add_line("Process ID", OS.get_process_id()) + add_line("System dark mode supported", DisplayServer.is_dark_mode_supported()) + add_line("System dark mode enabled", DisplayServer.is_dark_mode()) + add_line("System accent color", "#%s" % DisplayServer.get_accent_color().to_html()) + + add_header("System directories") + add_line("Desktop", OS.get_system_dir(OS.SYSTEM_DIR_DESKTOP)) + add_line("DCIM", OS.get_system_dir(OS.SYSTEM_DIR_DCIM)) + add_line("Documents", OS.get_system_dir(OS.SYSTEM_DIR_DOCUMENTS)) + add_line("Downloads", OS.get_system_dir(OS.SYSTEM_DIR_DOWNLOADS)) + add_line("Movies", OS.get_system_dir(OS.SYSTEM_DIR_MOVIES)) + add_line("Music", OS.get_system_dir(OS.SYSTEM_DIR_MUSIC)) + add_line("Pictures", OS.get_system_dir(OS.SYSTEM_DIR_PICTURES)) + add_line("Ringtones", OS.get_system_dir(OS.SYSTEM_DIR_RINGTONES)) + + add_header("Video") + add_line("Adapter name", RenderingServer.get_video_adapter_name()) + add_line("Adapter vendor", RenderingServer.get_video_adapter_vendor()) + add_line("Adapter type", [ + "Other (Unknown)", + "Integrated", + "Discrete", + "Virtual", + "CPU", + ][RenderingServer.get_video_adapter_type()]) + add_line("Adapter graphics API version", RenderingServer.get_video_adapter_api_version()) + + var video_adapter_driver_info = OS.get_video_adapter_driver_info() + if video_adapter_driver_info.size() > 0: + add_line("Adapter driver name", video_adapter_driver_info[0]) + if video_adapter_driver_info.size() > 1: + add_line("Adapter driver version", video_adapter_driver_info[1]) diff --git a/godot/addons/panku_console/modules/system_report/os_report.gd.uid b/godot/addons/panku_console/modules/system_report/os_report.gd.uid new file mode 100644 index 0000000..18779f3 --- /dev/null +++ b/godot/addons/panku_console/modules/system_report/os_report.gd.uid @@ -0,0 +1 @@ +uid://cf6l16wrpj31l diff --git a/godot/addons/panku_console/modules/texture_viewer/module.gd b/godot/addons/panku_console/modules/texture_viewer/module.gd new file mode 100644 index 0000000..5088464 --- /dev/null +++ b/godot/addons/panku_console/modules/texture_viewer/module.gd @@ -0,0 +1,21 @@ +class_name PankuModuleTextureViewer extends PankuModule + +const texture_viewer_prefab = preload("./texture_viewer.tscn") + +func init_module(): + core.new_expression_entered.connect( + func(exp:String, result): + if !result["failed"] and result["result"] is Texture2D: + add_texture_viewer_window(exp) + ) + +func add_texture_viewer_window(expr:String): + #print("add_texture_viewer_window(%s)"%expr) + var texture_viewer := texture_viewer_prefab.instantiate() + texture_viewer.expr = expr + texture_viewer._module = self + var window:PankuLynxWindow = core.windows_manager.create_window(texture_viewer) + window.queue_free_on_close = true + window.set_window_title_text("Texture: " + expr) + window.position = window.get_layout_position(Control.PRESET_BOTTOM_LEFT) + window.move_to_front() diff --git a/godot/addons/panku_console/modules/texture_viewer/module.gd.uid b/godot/addons/panku_console/modules/texture_viewer/module.gd.uid new file mode 100644 index 0000000..5506ce9 --- /dev/null +++ b/godot/addons/panku_console/modules/texture_viewer/module.gd.uid @@ -0,0 +1 @@ +uid://cxcih636vv2rn diff --git a/godot/addons/panku_console/modules/texture_viewer/texture_viewer.gd b/godot/addons/panku_console/modules/texture_viewer/texture_viewer.gd new file mode 100644 index 0000000..bb47bb6 --- /dev/null +++ b/godot/addons/panku_console/modules/texture_viewer/texture_viewer.gd @@ -0,0 +1,13 @@ +extends Control + +@onready var trect:TextureRect = $TextureRect + +var _module:PankuModule +var expr:String + +func _physics_process(delta: float) -> void: + if Engine.get_physics_frames() % 10 != 1: + return + var result = _module.core.gd_exprenv.execute(expr)["result"] + if result is Texture2D: + trect.texture = ImageTexture.create_from_image(result.get_image()) diff --git a/godot/addons/panku_console/modules/texture_viewer/texture_viewer.gd.uid b/godot/addons/panku_console/modules/texture_viewer/texture_viewer.gd.uid new file mode 100644 index 0000000..8d025ad --- /dev/null +++ b/godot/addons/panku_console/modules/texture_viewer/texture_viewer.gd.uid @@ -0,0 +1 @@ +uid://bs33mg5qx50it diff --git a/godot/addons/panku_console/modules/texture_viewer/texture_viewer.tscn b/godot/addons/panku_console/modules/texture_viewer/texture_viewer.tscn new file mode 100644 index 0000000..df593f4 --- /dev/null +++ b/godot/addons/panku_console/modules/texture_viewer/texture_viewer.tscn @@ -0,0 +1,21 @@ +[gd_scene load_steps=2 format=3 uid="uid://diohs08jsami2"] + +[ext_resource type="Script" path="res://addons/panku_console/modules/texture_viewer/texture_viewer.gd" id="1_vljdg"] + +[node name="TextureViewer" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_vljdg") + +[node name="TextureRect" type="TextureRect" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +expand_mode = 1 diff --git a/godot/addons/panku_console/modules/variable_tracker/module.gd b/godot/addons/panku_console/modules/variable_tracker/module.gd new file mode 100644 index 0000000..e7283b3 --- /dev/null +++ b/godot/addons/panku_console/modules/variable_tracker/module.gd @@ -0,0 +1,172 @@ +class_name PankuModuleVariableTracker extends PankuModule +## Module to register and update some common environments. +## +## On module startup current scene root node registered as 'current' environment var, +## for more convenient access from interactive shell. Module constantly monitoring node +## tree afterwards and auto rebind 'current' environment in case of current scene changed. +## Also all user autoload singletons registered with its root node names. + +const PROJECT_AUTOLOAD_PREFIX := "autoload/" +const CURRENT_SCENE_ENV := "current" +const SHELL_MODULE_NAME := "interactive_shell" +const DEFAULT_TRACKING_DELAY := 0.5 + +const CURRENT_REGISTERED_TIP := "[tip] Node '%s' registered as current scene, you can access it by [b]%s[/b]." +const CURRENT_REMOVED_TIP := "[tip] No current scene found, [b]%s[/b] keyword is no longer available." +const USER_AUTOLOADS_TIP := "[tip] Accessible user singleton modules: [b]%s[/b]" + +var _raw_exceptions_string: String = "" +var _nodes_exception_regexp: RegEx + +var _reverse_root_nodes_order: bool +var _current_scene_root:Node +var _user_singleton_files := [] +var _tween_loop:Tween +var _loop_call_back:CallbackTweener + + +func init_module(): + get_module_opt().tracking_delay = load_module_data("tracking_delay", DEFAULT_TRACKING_DELAY) + _reverse_root_nodes_order = load_module_data("use_last_as_current", true) + _raw_exceptions_string = load_module_data("root_node_exceptions", _raw_exceptions_string) + + await core.get_tree().process_frame # not sure if it is necessary + + update_exceptions_regexp() + _update_project_singleton_files() + _setup_scene_root_tracker() + _check_autoloads() + + +# Build root node exceptions regular expression +func update_exceptions_regexp() -> void: + if _raw_exceptions_string.is_empty(): + _nodes_exception_regexp = RegEx.new() # not valid expression + return + + _nodes_exception_regexp = RegEx.create_from_string(_raw_exceptions_string) + + if not _nodes_exception_regexp.is_valid(): + push_error("Can't parse '%s' expression for variable tracker" % _raw_exceptions_string) + + +# Parse project setting and collect and autoload files. +func _update_project_singleton_files() -> void: + _user_singleton_files.clear() + for property in ProjectSettings.get_property_list(): + if property.name.begins_with(PROJECT_AUTOLOAD_PREFIX): + _user_singleton_files.append(ProjectSettings.get_setting(property.name).trim_prefix("*")) + + +# Check if given node is autoload singleton. +func _is_singleton(node: Node) -> bool: + # Comparing scene file and script file with list of autoload files + # from project settings. I'm not sure that approach hundred percent perfect, + # but it works so far. + if node.scene_file_path in _user_singleton_files: + return true + + var script = node.get_script() + if script and (script.get_path() in _user_singleton_files): + return true + + return false + + +# Setup monitoring loop for current scene root node. +func _setup_scene_root_tracker() -> void: + _check_current_scene() + # The whole idea looping something in the background + # while dev console is not even opened does not feel so right. + # Have no idea how to make it more elegant way, + # so lets make loop interval user controllable at least. + var tracking_delay = get_module_opt().tracking_delay + + _tween_loop = core.create_tween() + _loop_call_back = _tween_loop.set_loops().tween_callback(_check_current_scene).set_delay(tracking_delay) + + +## Set current scene root node monitoring interval. +func change_tracking_delay(delay: float) -> void: + if _loop_call_back: + _loop_call_back.set_delay(delay) + + +# Update current scene root node environment. +func _check_current_scene() -> void: + var scene_root_found: Node = get_scene_root() + + if scene_root_found: + if scene_root_found != _current_scene_root: + core.gd_exprenv.register_env(CURRENT_SCENE_ENV, scene_root_found) + _print_to_interactive_shell(CURRENT_REGISTERED_TIP % [scene_root_found.name, CURRENT_SCENE_ENV]) + + else: + if _current_scene_root: + core.gd_exprenv.remove_env(CURRENT_SCENE_ENV) + _print_to_interactive_shell(CURRENT_REMOVED_TIP % CURRENT_SCENE_ENV) + + _current_scene_root = scene_root_found + + +## Find the root node of current active scene. +func get_scene_root() -> Node: + # Assuming current scene is the first node in tree that is not autoload singleton. + for node in _get_valid_root_nodes(): + if not _is_singleton(node): + return node + + return null + + +# Get list of tree root nodes filtered and sorted according module settings +func _get_valid_root_nodes() -> Array: + var nodes: Array = core.get_tree().root.get_children().filter(_root_nodes_filter) + + if _reverse_root_nodes_order: + nodes.reverse() + + return nodes + + +# Filter function for tree root nodes +func _root_nodes_filter(node: Node) -> bool: + # skip panku plugin itself + if node.name == core.SingletonName: + return false + + # skip os window + if node.get_meta(PankuLynxWindow.OS_WINDOW_MARKER, false): + return false + + # skip user defined exceptions + if _nodes_exception_regexp.is_valid() and _nodes_exception_regexp.search(node.name): + return false + + return true + + +# Find all autoload singletons and bind its to environment vars. +func _check_autoloads() -> void: + var _user_singleton_names := [] + + for node in _get_valid_root_nodes(): + if _is_singleton(node): + # register user singleton + _user_singleton_names.append(node.name) + core.gd_exprenv.register_env(node.name, node) + + if not _user_singleton_names.is_empty(): + _print_to_interactive_shell(USER_AUTOLOADS_TIP % ",".join(_user_singleton_names)) + + +# Print a tip to interactive shell module, modules load order does matter. +func _print_to_interactive_shell(message: String) -> void: + if core.module_manager.has_module(SHELL_MODULE_NAME): + var ishell = core.module_manager.get_module(SHELL_MODULE_NAME) + ishell.interactive_shell.output(message) + + +func quit_module(): + _tween_loop.kill() + super.quit_module() diff --git a/godot/addons/panku_console/modules/variable_tracker/module.gd.uid b/godot/addons/panku_console/modules/variable_tracker/module.gd.uid new file mode 100644 index 0000000..32d5777 --- /dev/null +++ b/godot/addons/panku_console/modules/variable_tracker/module.gd.uid @@ -0,0 +1 @@ +uid://dkpfrtlppo525 diff --git a/godot/addons/panku_console/modules/variable_tracker/opt.gd b/godot/addons/panku_console/modules/variable_tracker/opt.gd new file mode 100644 index 0000000..57114fa --- /dev/null +++ b/godot/addons/panku_console/modules/variable_tracker/opt.gd @@ -0,0 +1,32 @@ +extends ModuleOptions + +@export_group("variable_tracker") + +@export var export_comment_use_last_as_current = ( + "Use last non singleton node as current scene. " + + "First node will be used if this option disabled." +) +@export var use_last_as_current: bool: + get: + return _module._reverse_root_nodes_order + set(value): + use_last_as_current = value + _module._reverse_root_nodes_order = value + +@export var export_comment_root_node_exceptions = ( + "Top level nodes which will be ignored by variable tracker. " + + "Regular expressions can be used e.g. '(SignalBus|Game*)'." +) +@export var root_node_exceptions: String: + get: + return _module._raw_exceptions_string + set(value): + root_node_exceptions = value + _module._raw_exceptions_string = value + _module.update_exceptions_regexp() + +@export var export_comment_tracking_delay = "Current scene checking interval." +@export_range(0.1, 2.0, 0.1) var tracking_delay := 0.5: + set(v): + tracking_delay = v + _module.change_tracking_delay(tracking_delay) diff --git a/godot/addons/panku_console/modules/variable_tracker/opt.gd.uid b/godot/addons/panku_console/modules/variable_tracker/opt.gd.uid new file mode 100644 index 0000000..632ff37 --- /dev/null +++ b/godot/addons/panku_console/modules/variable_tracker/opt.gd.uid @@ -0,0 +1 @@ +uid://hluoefbsmxj4 diff --git a/godot/addons/panku_console/plugin.cfg b/godot/addons/panku_console/plugin.cfg new file mode 100644 index 0000000..68b1516 --- /dev/null +++ b/godot/addons/panku_console/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="PankuConsole" +description="All-in-One Godot Engine runtime debugging tool." +author="Feo (k2kra) Wu" +version="1.7.9" +script="plugin.gd" diff --git a/godot/addons/panku_console/plugin.gd b/godot/addons/panku_console/plugin.gd new file mode 100644 index 0000000..f37ee49 --- /dev/null +++ b/godot/addons/panku_console/plugin.gd @@ -0,0 +1,89 @@ +@tool +class_name PankuConsolePlugin +extends EditorPlugin + +const SINGLETON_NAME = "Panku" +const SINGLETON_PATH = "res://addons/panku_console/console.tscn" +const SINGLETON_OPTION = "autoload/" + SINGLETON_NAME + +var exporter: PankuExporter + + +# Custom export plugin to automatically disable console in release builds +class PankuExporter extends EditorExportPlugin: + const NAME = "PankuReleaseExporter" + var owner: EditorPlugin + var need_restore_singleton: bool + + + func _get_name() -> String: + # Have no clue where this name will be used + # It just should be implemented according the docs + return NAME + + + func _export_begin(_features: PackedStringArray, is_debug: bool, _path: String, _flags: int) -> void: + need_restore_singleton = false + var disable_activated: bool = ProjectSettings.get_setting( + PankuConfig.panku_option(PankuConfig.OPTIONS.DISABLE_ON_RELEASE) + ) + + if not is_debug and disable_activated: + need_restore_singleton = ProjectSettings.has_setting(SINGLETON_OPTION) + owner.safe_remove_singleton() + + + func _export_end() -> void: + if need_restore_singleton: + owner.safe_add_singleton() + + +func _enable_exporter() -> void: + if not exporter: + # See https://github.com/godotengine/godot/issues/73525 + exporter = (PankuExporter as Variant).new() + exporter.owner = self + add_export_plugin(exporter) + + +func _disable_exporter() -> void: + if exporter: + remove_export_plugin(exporter) + + +# Adding singleton with preliminary check to avoid any conflicts. +func safe_add_singleton() -> void: + if not ProjectSettings.has_setting(SINGLETON_OPTION): + add_autoload_singleton(SINGLETON_NAME, SINGLETON_PATH) + + +# Removing singleton with preliminary check to avoid any conflicts. +func safe_remove_singleton() -> void: + if ProjectSettings.has_setting(SINGLETON_OPTION): + remove_autoload_singleton(SINGLETON_NAME) + + +func _enable_plugin() -> void: + safe_add_singleton() + + print("[Panku Console] enabled.") + + +func _disable_plugin() -> void: + safe_remove_singleton() + PankuConfig.clear_all_project_settings() + + print("[Panku Console] disabled.") + + +func _enter_tree() -> void: + PankuConfig.init_all_project_settings() + _enable_exporter() + + print("[Panku Console] initialized! Project page: https://github.com/Ark2000/PankuConsole") + + +func _exit_tree() -> void: + _disable_exporter() + + diff --git a/godot/addons/panku_console/plugin.gd.uid b/godot/addons/panku_console/plugin.gd.uid new file mode 100644 index 0000000..4b0295b --- /dev/null +++ b/godot/addons/panku_console/plugin.gd.uid @@ -0,0 +1 @@ +uid://cfo1eom2dfg0e diff --git a/godot/addons/panku_console/res/effect/square_shadow.png b/godot/addons/panku_console/res/effect/square_shadow.png new file mode 100644 index 0000000..213fe2c Binary files /dev/null and b/godot/addons/panku_console/res/effect/square_shadow.png differ diff --git a/godot/addons/panku_console/res/effect/square_shadow.png.import b/godot/addons/panku_console/res/effect/square_shadow.png.import new file mode 100644 index 0000000..1d6d561 --- /dev/null +++ b/godot/addons/panku_console/res/effect/square_shadow.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dvr12fl5prm78" +path="res://.godot/imported/square_shadow.png-0b7f91b74dd24247868957be13db72f4.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/effect/square_shadow.png" +dest_files=["res://.godot/imported/square_shadow.png-0b7f91b74dd24247868957be13db72f4.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=true +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=true +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/godot/addons/panku_console/res/green_gradient_1d.tres b/godot/addons/panku_console/res/green_gradient_1d.tres new file mode 100644 index 0000000..b2e8aa1 --- /dev/null +++ b/godot/addons/panku_console/res/green_gradient_1d.tres @@ -0,0 +1,4 @@ +[gd_resource type="Gradient" format=3 uid="uid://nr65cgweqh8n"] + +[resource] +colors = PackedColorArray(0.129412, 0.14902, 0.180392, 0.501961, 0.129412, 0.14902, 0.180392, 0) diff --git a/godot/addons/panku_console/res/icons2/add.svg b/godot/addons/panku_console/res/icons2/add.svg new file mode 100644 index 0000000..d0cbaf1 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/add.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/add.svg.import b/godot/addons/panku_console/res/icons2/add.svg.import new file mode 100644 index 0000000..4332717 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/add.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dprpfr0l5xvmu" +path="res://.godot/imported/add.svg-2a06068ce10412da423766fee4b6d4aa.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/add.svg" +dest_files=["res://.godot/imported/add.svg-2a06068ce10412da423766fee4b6d4aa.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/arrow-down-svgrepo-com.svg b/godot/addons/panku_console/res/icons2/arrow-down-svgrepo-com.svg new file mode 100644 index 0000000..429e411 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/arrow-down-svgrepo-com.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/arrow-down-svgrepo-com.svg.import b/godot/addons/panku_console/res/icons2/arrow-down-svgrepo-com.svg.import new file mode 100644 index 0000000..64bc23d --- /dev/null +++ b/godot/addons/panku_console/res/icons2/arrow-down-svgrepo-com.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cdxbns8lyctqp" +path="res://.godot/imported/arrow-down-svgrepo-com.svg-38ccb799fe0295b6eb8e51628325ac00.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/arrow-down-svgrepo-com.svg" +dest_files=["res://.godot/imported/arrow-down-svgrepo-com.svg-38ccb799fe0295b6eb8e51628325ac00.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/arrow-up-md-svgrepo-com.svg b/godot/addons/panku_console/res/icons2/arrow-up-md-svgrepo-com.svg new file mode 100644 index 0000000..85982c5 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/arrow-up-md-svgrepo-com.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/arrow-up-md-svgrepo-com.svg.import b/godot/addons/panku_console/res/icons2/arrow-up-md-svgrepo-com.svg.import new file mode 100644 index 0000000..9c881ef --- /dev/null +++ b/godot/addons/panku_console/res/icons2/arrow-up-md-svgrepo-com.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d0k813mm5y0d5" +path="res://.godot/imported/arrow-up-md-svgrepo-com.svg-0d7dc8f9b4626627fc89d656dd6522e5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/arrow-up-md-svgrepo-com.svg" +dest_files=["res://.godot/imported/arrow-up-md-svgrepo-com.svg-0d7dc8f9b4626627fc89d656dd6522e5.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/bin-cancel-delete-remove-trash-garbage-svgrepo-com.svg b/godot/addons/panku_console/res/icons2/bin-cancel-delete-remove-trash-garbage-svgrepo-com.svg new file mode 100644 index 0000000..8842fee --- /dev/null +++ b/godot/addons/panku_console/res/icons2/bin-cancel-delete-remove-trash-garbage-svgrepo-com.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/bin-cancel-delete-remove-trash-garbage-svgrepo-com.svg.import b/godot/addons/panku_console/res/icons2/bin-cancel-delete-remove-trash-garbage-svgrepo-com.svg.import new file mode 100644 index 0000000..c34228a --- /dev/null +++ b/godot/addons/panku_console/res/icons2/bin-cancel-delete-remove-trash-garbage-svgrepo-com.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cngs5d4uosvmt" +path="res://.godot/imported/bin-cancel-delete-remove-trash-garbage-svgrepo-com.svg-b7f02697b5af6027969d40533290cf43.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/bin-cancel-delete-remove-trash-garbage-svgrepo-com.svg" +dest_files=["res://.godot/imported/bin-cancel-delete-remove-trash-garbage-svgrepo-com.svg-b7f02697b5af6027969d40533290cf43.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/bookmark-filled-svgrepo-com.svg b/godot/addons/panku_console/res/icons2/bookmark-filled-svgrepo-com.svg new file mode 100644 index 0000000..e3b8168 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/bookmark-filled-svgrepo-com.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/bookmark-filled-svgrepo-com.svg.import b/godot/addons/panku_console/res/icons2/bookmark-filled-svgrepo-com.svg.import new file mode 100644 index 0000000..4770d4d --- /dev/null +++ b/godot/addons/panku_console/res/icons2/bookmark-filled-svgrepo-com.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://x2wmejhxundv" +path="res://.godot/imported/bookmark-filled-svgrepo-com.svg-36e232dcc8b8fb5b9792fabd49d75fb9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/bookmark-filled-svgrepo-com.svg" +dest_files=["res://.godot/imported/bookmark-filled-svgrepo-com.svg-36e232dcc8b8fb5b9792fabd49d75fb9.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/bookmark-svgrepo-com.svg b/godot/addons/panku_console/res/icons2/bookmark-svgrepo-com.svg new file mode 100644 index 0000000..f7fae38 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/bookmark-svgrepo-com.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/bookmark-svgrepo-com.svg.import b/godot/addons/panku_console/res/icons2/bookmark-svgrepo-com.svg.import new file mode 100644 index 0000000..6b944e5 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/bookmark-svgrepo-com.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://232vc3pkp4kt" +path="res://.godot/imported/bookmark-svgrepo-com.svg-ff120b5ee0d289505ac4f825e8ec66d9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/bookmark-svgrepo-com.svg" +dest_files=["res://.godot/imported/bookmark-svgrepo-com.svg-ff120b5ee0d289505ac4f825e8ec66d9.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/check-svgrepo-com.svg b/godot/addons/panku_console/res/icons2/check-svgrepo-com.svg new file mode 100644 index 0000000..b0a18cf --- /dev/null +++ b/godot/addons/panku_console/res/icons2/check-svgrepo-com.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/check-svgrepo-com.svg.import b/godot/addons/panku_console/res/icons2/check-svgrepo-com.svg.import new file mode 100644 index 0000000..1b60ff7 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/check-svgrepo-com.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://2cjvp0dp8ede" +path="res://.godot/imported/check-svgrepo-com.svg-034d6c5925c00dc6c3cf6966293ed643.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/check-svgrepo-com.svg" +dest_files=["res://.godot/imported/check-svgrepo-com.svg-034d6c5925c00dc6c3cf6966293ed643.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/checkbox_checked.svg b/godot/addons/panku_console/res/icons2/checkbox_checked.svg new file mode 100644 index 0000000..970edd0 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/checkbox_checked.svg @@ -0,0 +1,22 @@ + + + +Created with Fabric.js 4.6.0 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/checkbox_checked.svg.import b/godot/addons/panku_console/res/icons2/checkbox_checked.svg.import new file mode 100644 index 0000000..3752b27 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/checkbox_checked.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bua84a0uv8ntw" +path="res://.godot/imported/checkbox_checked.svg-b5d0aaca03398eb49c2d410cf3c86d9a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/checkbox_checked.svg" +dest_files=["res://.godot/imported/checkbox_checked.svg-b5d0aaca03398eb49c2d410cf3c86d9a.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/checkbox_unchecked.svg b/godot/addons/panku_console/res/icons2/checkbox_unchecked.svg new file mode 100644 index 0000000..609e889 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/checkbox_unchecked.svg @@ -0,0 +1,19 @@ + + + +Created with Fabric.js 4.6.0 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/checkbox_unchecked.svg.import b/godot/addons/panku_console/res/icons2/checkbox_unchecked.svg.import new file mode 100644 index 0000000..a659b48 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/checkbox_unchecked.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dkiyle8rjahmw" +path="res://.godot/imported/checkbox_unchecked.svg-43408d4debc25d7804c4c806c8681c45.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/checkbox_unchecked.svg" +dest_files=["res://.godot/imported/checkbox_unchecked.svg-43408d4debc25d7804c4c806c8681c45.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/chevron_right.svg b/godot/addons/panku_console/res/icons2/chevron_right.svg new file mode 100644 index 0000000..650d8f2 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/chevron_right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/chevron_right.svg.import b/godot/addons/panku_console/res/icons2/chevron_right.svg.import new file mode 100644 index 0000000..c8099a1 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/chevron_right.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ws58gucuygx1" +path="res://.godot/imported/chevron_right.svg-2c66815dcd12ccc3ba2562028a236330.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/chevron_right.svg" +dest_files=["res://.godot/imported/chevron_right.svg-2c66815dcd12ccc3ba2562028a236330.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/close.svg b/godot/addons/panku_console/res/icons2/close.svg new file mode 100644 index 0000000..05fb420 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/close.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/close.svg.import b/godot/addons/panku_console/res/icons2/close.svg.import new file mode 100644 index 0000000..cfded02 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/close.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://8g5afcuanbl6" +path="res://.godot/imported/close.svg-3a85a46ed81631640c7e8cd4342c98f0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/close.svg" +dest_files=["res://.godot/imported/close.svg-3a85a46ed81631640c7e8cd4342c98f0.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/close_20x.svg b/godot/addons/panku_console/res/icons2/close_20x.svg new file mode 100644 index 0000000..4aab7f5 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/close_20x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/close_20x.svg.import b/godot/addons/panku_console/res/icons2/close_20x.svg.import new file mode 100644 index 0000000..f9a6a2d --- /dev/null +++ b/godot/addons/panku_console/res/icons2/close_20x.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ttbgv1vr1xsc" +path="res://.godot/imported/close_20x.svg-9ead6c9c7ae149729de0bac95295aaba.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/close_20x.svg" +dest_files=["res://.godot/imported/close_20x.svg-9ead6c9c7ae149729de0bac95295aaba.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/expand_more.svg b/godot/addons/panku_console/res/icons2/expand_more.svg new file mode 100644 index 0000000..61fa21d --- /dev/null +++ b/godot/addons/panku_console/res/icons2/expand_more.svg @@ -0,0 +1 @@ + diff --git a/godot/addons/panku_console/res/icons2/expand_more.svg.import b/godot/addons/panku_console/res/icons2/expand_more.svg.import new file mode 100644 index 0000000..b7bd274 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/expand_more.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d1qaq6vnyc2f2" +path="res://.godot/imported/expand_more.svg-156eef34c01d1545ad526cf0292ef120.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/expand_more.svg" +dest_files=["res://.godot/imported/expand_more.svg-156eef34c01d1545ad526cf0292ef120.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/eye.svg b/godot/addons/panku_console/res/icons2/eye.svg new file mode 100644 index 0000000..171a612 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/eye.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/eye.svg.import b/godot/addons/panku_console/res/icons2/eye.svg.import new file mode 100644 index 0000000..4c56efd --- /dev/null +++ b/godot/addons/panku_console/res/icons2/eye.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cvli654t5ybne" +path="res://.godot/imported/eye.svg-6814b908d03cc1398c9846342a0966fc.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/eye.svg" +dest_files=["res://.godot/imported/eye.svg-6814b908d03cc1398c9846342a0966fc.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/favorite.svg b/godot/addons/panku_console/res/icons2/favorite.svg new file mode 100644 index 0000000..4bd196b --- /dev/null +++ b/godot/addons/panku_console/res/icons2/favorite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/favorite.svg.import b/godot/addons/panku_console/res/icons2/favorite.svg.import new file mode 100644 index 0000000..e6f17dc --- /dev/null +++ b/godot/addons/panku_console/res/icons2/favorite.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://hf6h8otb8qkv" +path="res://.godot/imported/favorite.svg-94e3b968ddcfab82f19abf606a6cd9bb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/favorite.svg" +dest_files=["res://.godot/imported/favorite.svg-94e3b968ddcfab82f19abf606a6cd9bb.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/fold-svgrepo-com.svg b/godot/addons/panku_console/res/icons2/fold-svgrepo-com.svg new file mode 100644 index 0000000..0d9ed74 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/fold-svgrepo-com.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/fold-svgrepo-com.svg.import b/godot/addons/panku_console/res/icons2/fold-svgrepo-com.svg.import new file mode 100644 index 0000000..23349a5 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/fold-svgrepo-com.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dchvk7qgfe37m" +path="res://.godot/imported/fold-svgrepo-com.svg-6f951c0c7f0583013a7f3fa96d045e61.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/fold-svgrepo-com.svg" +dest_files=["res://.godot/imported/fold-svgrepo-com.svg-6f951c0c7f0583013a7f3fa96d045e61.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=true +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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/gear.svg b/godot/addons/panku_console/res/icons2/gear.svg new file mode 100644 index 0000000..569706f --- /dev/null +++ b/godot/addons/panku_console/res/icons2/gear.svg @@ -0,0 +1,10 @@ + + + + + + + diff --git a/godot/addons/panku_console/res/icons2/gear.svg.import b/godot/addons/panku_console/res/icons2/gear.svg.import new file mode 100644 index 0000000..42d75bb --- /dev/null +++ b/godot/addons/panku_console/res/icons2/gear.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ch214eu302abt" +path="res://.godot/imported/gear.svg-bd633691cf7fd6c996b8a22361898045.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/gear.svg" +dest_files=["res://.godot/imported/gear.svg-bd633691cf7fd6c996b8a22361898045.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/history.svg b/godot/addons/panku_console/res/icons2/history.svg new file mode 100644 index 0000000..0d691fe --- /dev/null +++ b/godot/addons/panku_console/res/icons2/history.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/godot/addons/panku_console/res/icons2/history.svg.import b/godot/addons/panku_console/res/icons2/history.svg.import new file mode 100644 index 0000000..dbd6d5b --- /dev/null +++ b/godot/addons/panku_console/res/icons2/history.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://kkrqc0j1wdi6" +path="res://.godot/imported/history.svg-a137f2f4fbb3649b91b01d8def6f6456.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/history.svg" +dest_files=["res://.godot/imported/history.svg-a137f2f4fbb3649b91b01d8def6f6456.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/info.svg b/godot/addons/panku_console/res/icons2/info.svg new file mode 100644 index 0000000..0e9ea7a --- /dev/null +++ b/godot/addons/panku_console/res/icons2/info.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/info.svg.import b/godot/addons/panku_console/res/icons2/info.svg.import new file mode 100644 index 0000000..ecb56ba --- /dev/null +++ b/godot/addons/panku_console/res/icons2/info.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dxvodkcmn4pa8" +path="res://.godot/imported/info.svg-2b1105336c45eeebd4acdf04c60c8bdb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/info.svg" +dest_files=["res://.godot/imported/info.svg-2b1105336c45eeebd4acdf04c60c8bdb.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/info2.svg b/godot/addons/panku_console/res/icons2/info2.svg new file mode 100644 index 0000000..e3db00e --- /dev/null +++ b/godot/addons/panku_console/res/icons2/info2.svg @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/info2.svg.import b/godot/addons/panku_console/res/icons2/info2.svg.import new file mode 100644 index 0000000..aa5b413 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/info2.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b6jt0ggmuoyeb" +path="res://.godot/imported/info2.svg-c9ea3dad2575e3684098e5112249010d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/info2.svg" +dest_files=["res://.godot/imported/info2.svg-c9ea3dad2575e3684098e5112249010d.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/keyboard.svg b/godot/addons/panku_console/res/icons2/keyboard.svg new file mode 100644 index 0000000..6cdb9a1 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/keyboard.svg @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/keyboard.svg.import b/godot/addons/panku_console/res/icons2/keyboard.svg.import new file mode 100644 index 0000000..d1fcf08 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/keyboard.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bqxh6hk3op1wv" +path="res://.godot/imported/keyboard.svg-65a8773013921e61a1cc3ef80ef82693.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/keyboard.svg" +dest_files=["res://.godot/imported/keyboard.svg-65a8773013921e61a1cc3ef80ef82693.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/menu.svg b/godot/addons/panku_console/res/icons2/menu.svg new file mode 100644 index 0000000..febcbbe --- /dev/null +++ b/godot/addons/panku_console/res/icons2/menu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/menu.svg.import b/godot/addons/panku_console/res/icons2/menu.svg.import new file mode 100644 index 0000000..3a56540 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/menu.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dosm26riekruh" +path="res://.godot/imported/menu.svg-15ef2ef76b3f6c0e7fc0168d1ac05d38.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/menu.svg" +dest_files=["res://.godot/imported/menu.svg-15ef2ef76b3f6c0e7fc0168d1ac05d38.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/more_horiz.svg b/godot/addons/panku_console/res/icons2/more_horiz.svg new file mode 100644 index 0000000..73560d0 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/more_horiz.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/more_horiz.svg.import b/godot/addons/panku_console/res/icons2/more_horiz.svg.import new file mode 100644 index 0000000..9430815 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/more_horiz.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bbc41a7b3jre0" +path="res://.godot/imported/more_horiz.svg-7ca01f2b54bfa3040d05158756af7968.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/more_horiz.svg" +dest_files=["res://.godot/imported/more_horiz.svg-7ca01f2b54bfa3040d05158756af7968.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/open_with.svg b/godot/addons/panku_console/res/icons2/open_with.svg new file mode 100644 index 0000000..d6c2bae --- /dev/null +++ b/godot/addons/panku_console/res/icons2/open_with.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/open_with.svg.import b/godot/addons/panku_console/res/icons2/open_with.svg.import new file mode 100644 index 0000000..90ce2f3 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/open_with.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b22jdciwq07ic" +path="res://.godot/imported/open_with.svg-4c7b4bea2cb5c0a1af405d61d3d85fa3.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/open_with.svg" +dest_files=["res://.godot/imported/open_with.svg-4c7b4bea2cb5c0a1af405d61d3d85fa3.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/pause-1010-svgrepo-com.svg b/godot/addons/panku_console/res/icons2/pause-1010-svgrepo-com.svg new file mode 100644 index 0000000..6aba11b --- /dev/null +++ b/godot/addons/panku_console/res/icons2/pause-1010-svgrepo-com.svg @@ -0,0 +1,19 @@ + + + + + pause [#1010] + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/pause-1010-svgrepo-com.svg.import b/godot/addons/panku_console/res/icons2/pause-1010-svgrepo-com.svg.import new file mode 100644 index 0000000..812a930 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/pause-1010-svgrepo-com.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cpfnfg1aw6xso" +path="res://.godot/imported/pause-1010-svgrepo-com.svg-8a4549394af5099adcc9e7d6754d8258.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/pause-1010-svgrepo-com.svg" +dest_files=["res://.godot/imported/pause-1010-svgrepo-com.svg-8a4549394af5099adcc9e7d6754d8258.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/play-1001-svgrepo-com.svg b/godot/addons/panku_console/res/icons2/play-1001-svgrepo-com.svg new file mode 100644 index 0000000..7cebe14 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/play-1001-svgrepo-com.svg @@ -0,0 +1,19 @@ + + + + + play [#1001] + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/play-1001-svgrepo-com.svg.import b/godot/addons/panku_console/res/icons2/play-1001-svgrepo-com.svg.import new file mode 100644 index 0000000..b9b56ee --- /dev/null +++ b/godot/addons/panku_console/res/icons2/play-1001-svgrepo-com.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ecmevhk0tuas" +path="res://.godot/imported/play-1001-svgrepo-com.svg-6dda54bd1afb4351b91dc74d89d43c7f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/play-1001-svgrepo-com.svg" +dest_files=["res://.godot/imported/play-1001-svgrepo-com.svg-6dda54bd1afb4351b91dc74d89d43c7f.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/pop-out-svgrepo-com.svg b/godot/addons/panku_console/res/icons2/pop-out-svgrepo-com.svg new file mode 100644 index 0000000..e59c21a --- /dev/null +++ b/godot/addons/panku_console/res/icons2/pop-out-svgrepo-com.svg @@ -0,0 +1,14 @@ + + + + + + + + + + pop-out-line + + + + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/pop-out-svgrepo-com.svg.import b/godot/addons/panku_console/res/icons2/pop-out-svgrepo-com.svg.import new file mode 100644 index 0000000..ad501b5 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/pop-out-svgrepo-com.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://gav3m4qtvgje" +path="res://.godot/imported/pop-out-svgrepo-com.svg-54bb73635d5759933a88bbec8ed6aca8.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/pop-out-svgrepo-com.svg" +dest_files=["res://.godot/imported/pop-out-svgrepo-com.svg-54bb73635d5759933a88bbec8ed6aca8.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/question.svg b/godot/addons/panku_console/res/icons2/question.svg new file mode 100644 index 0000000..f6a29dd --- /dev/null +++ b/godot/addons/panku_console/res/icons2/question.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/question.svg.import b/godot/addons/panku_console/res/icons2/question.svg.import new file mode 100644 index 0000000..148ea93 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/question.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ca6btx2q3g7q8" +path="res://.godot/imported/question.svg-b2322d216b84b418e5a3bac06c50c9e3.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/question.svg" +dest_files=["res://.godot/imported/question.svg-b2322d216b84b418e5a3bac06c50c9e3.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/remove.svg b/godot/addons/panku_console/res/icons2/remove.svg new file mode 100644 index 0000000..bee8c68 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/remove.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/remove.svg.import b/godot/addons/panku_console/res/icons2/remove.svg.import new file mode 100644 index 0000000..55d2846 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/remove.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dnexm7u6lq3km" +path="res://.godot/imported/remove.svg-76a0d91c4b08193a23093f3f0fc3dcaf.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/remove.svg" +dest_files=["res://.godot/imported/remove.svg-76a0d91c4b08193a23093f3f0fc3dcaf.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/rename-svgrepo-com.svg b/godot/addons/panku_console/res/icons2/rename-svgrepo-com.svg new file mode 100644 index 0000000..5e80b7a --- /dev/null +++ b/godot/addons/panku_console/res/icons2/rename-svgrepo-com.svg @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/rename-svgrepo-com.svg.import b/godot/addons/panku_console/res/icons2/rename-svgrepo-com.svg.import new file mode 100644 index 0000000..2aa845c --- /dev/null +++ b/godot/addons/panku_console/res/icons2/rename-svgrepo-com.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://brf6iwx4r6bdd" +path="res://.godot/imported/rename-svgrepo-com.svg-5ec15595e7d5857527ce81e8c9082a28.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/rename-svgrepo-com.svg" +dest_files=["res://.godot/imported/rename-svgrepo-com.svg-5ec15595e7d5857527ce81e8c9082a28.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/reply.svg b/godot/addons/panku_console/res/icons2/reply.svg new file mode 100644 index 0000000..2f85918 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/reply.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/reply.svg.import b/godot/addons/panku_console/res/icons2/reply.svg.import new file mode 100644 index 0000000..2286239 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/reply.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b4jd6tqlie0wx" +path="res://.godot/imported/reply.svg-198ceccf73b6dc82a4737a0814707430.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/reply.svg" +dest_files=["res://.godot/imported/reply.svg-198ceccf73b6dc82a4737a0814707430.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/resize-svgrepo-com.svg b/godot/addons/panku_console/res/icons2/resize-svgrepo-com.svg new file mode 100644 index 0000000..c9a716d --- /dev/null +++ b/godot/addons/panku_console/res/icons2/resize-svgrepo-com.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/godot/addons/panku_console/res/icons2/resize-svgrepo-com.svg.import b/godot/addons/panku_console/res/icons2/resize-svgrepo-com.svg.import new file mode 100644 index 0000000..1f743ea --- /dev/null +++ b/godot/addons/panku_console/res/icons2/resize-svgrepo-com.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ciu5jiw4xmkq0" +path="res://.godot/imported/resize-svgrepo-com.svg-cd0763e17be8b93faf6e99fda452ac2a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/resize-svgrepo-com.svg" +dest_files=["res://.godot/imported/resize-svgrepo-com.svg-cd0763e17be8b93faf6e99fda452ac2a.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=true +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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/search.svg b/godot/addons/panku_console/res/icons2/search.svg new file mode 100644 index 0000000..e14d7af --- /dev/null +++ b/godot/addons/panku_console/res/icons2/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/godot/addons/panku_console/res/icons2/search.svg.import b/godot/addons/panku_console/res/icons2/search.svg.import new file mode 100644 index 0000000..e7910b4 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/search.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://gtslyq1kvnxc" +path="res://.godot/imported/search.svg-cbe7bc4d5cf71611ed1b364ee4407142.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/search.svg" +dest_files=["res://.godot/imported/search.svg-cbe7bc4d5cf71611ed1b364ee4407142.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/icons2/swap_horiz.svg b/godot/addons/panku_console/res/icons2/swap_horiz.svg new file mode 100644 index 0000000..4bf16b0 --- /dev/null +++ b/godot/addons/panku_console/res/icons2/swap_horiz.svg @@ -0,0 +1 @@ + diff --git a/godot/addons/panku_console/res/icons2/swap_horiz.svg.import b/godot/addons/panku_console/res/icons2/swap_horiz.svg.import new file mode 100644 index 0000000..c94e87b --- /dev/null +++ b/godot/addons/panku_console/res/icons2/swap_horiz.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bc2g8vv0x3d8y" +path="res://.godot/imported/swap_horiz.svg-3fa7c06ee39a243e7a12b5915f37a894.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/panku_console/res/icons2/swap_horiz.svg" +dest_files=["res://.godot/imported/swap_horiz.svg-3fa7c06ee39a243e7a12b5915f37a894.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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/panku_console/res/panku_console_theme.tres b/godot/addons/panku_console/res/panku_console_theme.tres new file mode 100644 index 0000000..69306e9 --- /dev/null +++ b/godot/addons/panku_console/res/panku_console_theme.tres @@ -0,0 +1,137 @@ +[gd_resource type="Theme" load_steps=26 format=3 uid="uid://bk18yfu0d77wk"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_1q17k"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_j0iw5"] +bg_color = Color(0.160784, 0.160784, 0.160784, 0.12549) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color(0.8, 0.8, 0.8, 0.0627451) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_2sv8t"] +content_margin_left = 4.0 +content_margin_top = 2.0 +content_margin_right = 4.0 +content_margin_bottom = 2.0 +bg_color = Color(0, 0, 0, 0.12549) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color(0.8, 0.8, 0.8, 0.0627451) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_oko07"] +content_margin_left = 4.0 +content_margin_top = 2.0 +content_margin_right = 4.0 +content_margin_bottom = 2.0 +bg_color = Color(0.639216, 0.639216, 0.639216, 0.12549) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color(0.8, 0.8, 0.8, 0.0627451) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_66h6h"] +bg_color = Color(1, 1, 1, 0.4) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_io0fu"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_5a1x3"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_olfos"] +content_margin_top = 8.0 +bg_color = Color(0.6, 0.6, 0.6, 0.12549) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color(0.8, 0.8, 0.8, 0.25098) +expand_margin_top = 8.0 + +[sub_resource type="ImageTexture" id="ImageTexture_p3ihr"] + +[sub_resource type="ImageTexture" id="ImageTexture_e0rko"] + +[sub_resource type="ImageTexture" id="ImageTexture_1il84"] + +[sub_resource type="ImageTexture" id="ImageTexture_amjqe"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_pc3w4"] +bg_color = Color(1, 1, 1, 0.501961) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_xodll"] +bg_color = Color(1, 1, 1, 0.501961) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_y3ihc"] +content_margin_top = 23.0 +bg_color = Color(0, 0, 0, 0.25098) +border_color = Color(0.6, 0.6, 0.6, 0.25098) + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_36yn6"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_1hrnt"] +content_margin_left = 8.0 +bg_color = Color(0, 0, 0, 0.12549) +border_width_left = 2 +border_color = Color(0.8, 0.8, 0.8, 0.25098) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_xot6g"] +content_margin_left = 4.0 +draw_center = false +border_width_left = 2 +border_color = Color(0.8, 0.8, 0.8, 0.12549) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_bcc4x"] +bg_color = Color(0.317647, 0.317647, 0.317647, 0.901961) + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_nqr1r"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_abx0a"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_37w0u"] +bg_color = Color(1, 1, 1, 0.501961) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_mhjmb"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_iamty"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_jdo31"] +content_margin_left = 8.0 +bg_color = Color(0.6, 0.6, 0.6, 0.12549) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color(0.8, 0.8, 0.8, 0.25098) + +[resource] +default_font_size = 16 +Button/styles/focus = SubResource("StyleBoxEmpty_1q17k") +Button/styles/hover = SubResource("StyleBoxFlat_j0iw5") +Button/styles/normal = SubResource("StyleBoxFlat_2sv8t") +Button/styles/pressed = SubResource("StyleBoxFlat_oko07") +HScrollBar/styles/grabber = SubResource("StyleBoxFlat_66h6h") +HScrollBar/styles/grabber_highlight = SubResource("StyleBoxFlat_io0fu") +HScrollBar/styles/grabber_pressed = SubResource("StyleBoxFlat_5a1x3") +HScrollBar/styles/scroll = SubResource("StyleBoxFlat_olfos") +HSlider/icons/grabber = SubResource("ImageTexture_p3ihr") +HSlider/icons/grabber_disabled = SubResource("ImageTexture_e0rko") +HSlider/icons/grabber_highlight = SubResource("ImageTexture_1il84") +HSlider/icons/tick = SubResource("ImageTexture_amjqe") +HSlider/styles/grabber_area = SubResource("StyleBoxFlat_pc3w4") +HSlider/styles/grabber_area_highlight = SubResource("StyleBoxFlat_xodll") +HSlider/styles/slider = SubResource("StyleBoxFlat_y3ihc") +LineEdit/styles/focus = SubResource("StyleBoxEmpty_36yn6") +LineEdit/styles/normal = SubResource("StyleBoxFlat_1hrnt") +LineEdit/styles/read_only = SubResource("StyleBoxFlat_xot6g") +PopupMenu/styles/panel = SubResource("StyleBoxFlat_bcc4x") +RichTextLabel/colors/default_color = Color(1, 1, 1, 0.878431) +RichTextLabel/styles/focus = SubResource("StyleBoxEmpty_nqr1r") +RichTextLabel/styles/normal = SubResource("StyleBoxEmpty_abx0a") +VScrollBar/styles/grabber = SubResource("StyleBoxFlat_37w0u") +VScrollBar/styles/grabber_highlight = SubResource("StyleBoxFlat_mhjmb") +VScrollBar/styles/grabber_pressed = SubResource("StyleBoxFlat_iamty") +VScrollBar/styles/scroll = SubResource("StyleBoxFlat_jdo31") diff --git a/godot/addons/panku_console/res/shader/mattias_crt.gdshader b/godot/addons/panku_console/res/shader/mattias_crt.gdshader new file mode 100644 index 0000000..1251da1 --- /dev/null +++ b/godot/addons/panku_console/res/shader/mattias_crt.gdshader @@ -0,0 +1,63 @@ +// Source: https://www.shadertoy.com/view/Ms23DR +// Loosely based on postprocessing shader by inigo quilez, License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. + +shader_type canvas_item; + +uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest; + +vec2 curve(vec2 uv) { + uv = (uv - 0.5) * 2.0; + uv *= 1.1; + uv.x *= 1.0 + pow(abs(uv.y) / 5.0, 2.0); + uv.y *= 1.0 + pow(abs(uv.x) / 4.0, 2.0); + uv = (uv / 2.0) + 0.5; + uv = uv * 0.92 + 0.04; + return uv; +} + +void fragment() { + vec2 fragCoord = FRAGCOORD.xy; + vec2 iResolution = 1.0 / SCREEN_PIXEL_SIZE; + float iTime = TIME; + vec2 q = fragCoord.xy / iResolution.xy; + vec2 uv = q; + uv = curve( uv ); + vec3 oricol = texture( screen_texture, vec2(q.x,q.y) ).xyz; + vec3 col; + float x = sin(0.3*iTime+uv.y*21.0)*sin(0.7*iTime+uv.y*29.0)*sin(0.3+0.33*iTime+uv.y*31.0)*0.0017; + + col.r = texture(screen_texture,vec2(x+uv.x+0.001,uv.y+0.001)).x+0.05; + col.g = texture(screen_texture,vec2(x+uv.x+0.000,uv.y-0.002)).y+0.05; + col.b = texture(screen_texture,vec2(x+uv.x-0.002,uv.y+0.000)).z+0.05; + col.r += 0.08*texture(screen_texture,0.75*vec2(x+0.025, -0.027)+vec2(uv.x+0.001,uv.y+0.001)).x; + col.g += 0.05*texture(screen_texture,0.75*vec2(x+-0.022, -0.02)+vec2(uv.x+0.000,uv.y-0.002)).y; + col.b += 0.08*texture(screen_texture,0.75*vec2(x+-0.02, -0.018)+vec2(uv.x-0.002,uv.y+0.000)).z; + + col = clamp(col*0.6+0.4*col*col*1.0,0.0,1.0); + + float vig = (0.0 + 1.0*16.0*uv.x*uv.y*(1.0-uv.x)*(1.0-uv.y)); + col *= vec3(pow(vig,0.3)); + + col *= vec3(0.95,1.05,0.95); + col *= 2.8; + + float scans = clamp( 0.35+0.35*sin(3.5*iTime+uv.y*iResolution.y*1.5), 0.0, 1.0); + + float s = pow(scans,1.7); + col = col*vec3( 0.4+0.7*s) ; + + col *= 1.0+0.01*sin(110.0*iTime); + if (uv.x < 0.0 || uv.x > 1.0) + col *= 0.0; + if (uv.y < 0.0 || uv.y > 1.0) + col *= 0.0; + + col*=1.0-0.65*vec3(clamp((mod(fragCoord.x, 2.0)-1.0)*2.0,0.0,1.0)); + + float comp = smoothstep( 0.1, 0.9, sin(iTime) ); + + // Remove the next line to stop cross-fade between original and postprocess +// col = mix( col, oricol, comp ); + + COLOR = vec4(col,1.0); +} diff --git a/godot/addons/panku_console/res/shader/mattias_crt.gdshader.uid b/godot/addons/panku_console/res/shader/mattias_crt.gdshader.uid new file mode 100644 index 0000000..00bd283 --- /dev/null +++ b/godot/addons/panku_console/res/shader/mattias_crt.gdshader.uid @@ -0,0 +1 @@ +uid://b4q0v3umrhemp diff --git a/godot/addons/panku_console/res/shader/simple_fast_blur.gdshader b/godot/addons/panku_console/res/shader/simple_fast_blur.gdshader new file mode 100644 index 0000000..4667743 --- /dev/null +++ b/godot/addons/panku_console/res/shader/simple_fast_blur.gdshader @@ -0,0 +1,10 @@ +shader_type canvas_item; + +uniform float lod:hint_range(0.0, 5.0) = 0.0; +uniform vec4 modulate:source_color = vec4(1.0); +uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_linear_mipmap; + +void fragment() { + vec3 col = textureLod(screen_texture, SCREEN_UV, lod).rgb; + COLOR = vec4(mix(col, modulate.rgb, modulate.a), 1.0); +} diff --git a/godot/addons/panku_console/res/shader/simple_fast_blur.gdshader.uid b/godot/addons/panku_console/res/shader/simple_fast_blur.gdshader.uid new file mode 100644 index 0000000..68a3854 --- /dev/null +++ b/godot/addons/panku_console/res/shader/simple_fast_blur.gdshader.uid @@ -0,0 +1 @@ +uid://b2ut3nil15x8o diff --git a/godot/player.tscn b/godot/player.tscn deleted file mode 100644 index 9a9540c..0000000 --- a/godot/player.tscn +++ /dev/null @@ -1,46 +0,0 @@ -[gd_scene load_steps=7 format=3 uid="uid://bx7xynpbusro6"] - -[ext_resource type="Texture2D" uid="uid://doyl1pfn8cean" path="res://art/playerGrey_up1.png" id="1_hqtel"] -[ext_resource type="Texture2D" uid="uid://cxx2twmx2cov0" path="res://art/playerGrey_up2.png" id="2_sweqy"] -[ext_resource type="Texture2D" uid="uid://y5fhjtmhqhdu" path="res://art/playerGrey_walk1.png" id="3_2hs0m"] -[ext_resource type="Texture2D" uid="uid://cihvooq6h05er" path="res://art/playerGrey_walk2.png" id="4_1jxqw"] - -[sub_resource type="SpriteFrames" id="SpriteFrames_dw050"] -animations = [{ -"frames": [{ -"duration": 1.0, -"texture": ExtResource("1_hqtel") -}, { -"duration": 1.0, -"texture": ExtResource("2_sweqy") -}], -"loop": true, -"name": &"up", -"speed": 5.0 -}, { -"frames": [{ -"duration": 1.0, -"texture": ExtResource("3_2hs0m") -}, { -"duration": 1.0, -"texture": ExtResource("4_1jxqw") -}], -"loop": true, -"name": &"walk", -"speed": 5.0 -}] - -[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_b26j0"] -radius = 27.0 -height = 68.0 - -[node name="Player" type="Player"] -metadata/_edit_group_ = true - -[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."] -scale = Vector2(0.5, 0.5) -sprite_frames = SubResource("SpriteFrames_dw050") -animation = &"walk" - -[node name="CollisionShape2D" type="CollisionShape2D" parent="."] -shape = SubResource("CapsuleShape2D_b26j0") diff --git a/godot/project.godot b/godot/project.godot index 0fb1ea7..48ff521 100644 --- a/godot/project.godot +++ b/godot/project.godot @@ -30,7 +30,6 @@ config/icon="res://icon.svg" [autoload] -GLogging="*res://addons/glogging/glogging.gd" Panku="*res://addons/panku_console/console.tscn" [display] @@ -39,7 +38,7 @@ window/stretch/mode="canvas_items" [editor_plugins] -enabled=PackedStringArray() +enabled=PackedStringArray("res://addons/panku_console/plugin.cfg") [godot_resource_groups] @@ -71,3 +70,8 @@ move_down={ , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null) ] } +toggle_console={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":96,"key_label":0,"unicode":96,"location":0,"echo":false,"script":null) +] +} diff --git a/godot/tests/test_runner.tscn b/godot/tests/test_runner.tscn new file mode 100644 index 0000000..69b6077 --- /dev/null +++ b/godot/tests/test_runner.tscn @@ -0,0 +1,5 @@ +[gd_scene format=3 uid="uid://dag477ig1al1u"] + +[node name="GdTestRunner" type="GdTestRunner"] +disallow_focus = true +run_benchmarks = false diff --git a/godot/trymap.tscn b/godot/trymap.tscn index 4b8e9a4..df95f7a 100644 --- a/godot/trymap.tscn +++ b/godot/trymap.tscn @@ -18,10 +18,11 @@ background_color = Color(1, 0, 0, 1) [node name="Node3D" type="Node3D"] [node name="Mappy" type="Mappy" parent="."] -map_width = 10 -map_height = 10 +map_width = 1024 +map_height = 1024 noise_magnitude = 50.0 texture_atlas = ExtResource("1_qcwru") +transform = Transform3D(128, 0, 0, 0, 128, 0, 0, 0, 128, 0, 0, 0) [node name="Player" type="Player" parent="."] @@ -32,4 +33,5 @@ mesh = SubResource("QuadMesh_yr18d") [node name="Camera3D" type="Camera3D" parent="Player"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 2.78414) environment = SubResource("Environment_bol8x") +projection = 1 current = true diff --git a/rust/Cargo.lock b/rust/Cargo.lock index badee07..bde2e0c 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -8,7 +8,7 @@ version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ - "gimli", + "gimli 0.32.3", ] [[package]] @@ -17,6 +17,19 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -26,6 +39,24 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "ar" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d67af77d68a931ecd5cbd8a3b5987d63a1d1d1278f7f6a60ae33db485cdebb69" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "autocfg" version = "1.5.0" @@ -42,16 +73,45 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide", - "object", + "object 0.37.3", "rustc-demangle", "windows-link", ] +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +dependencies = [ + "serde", +] + +[[package]] +name = "bytemuck" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "bytes" @@ -59,18 +119,222 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +[[package]] +name = "camino" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84982c6c0ae343635a3a4ee6dedef965513735c8b183caa7289fa6e27399ebd4" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-util-schemas" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dc1a6f7b5651af85774ae5a34b4e8be397d9cf4bc063b7e6dbd99a841837830" +dependencies = [ + "semver", + "serde", + "serde-untagged", + "serde-value", + "thiserror", + "toml", + "unicode-xid", + "url", +] + +[[package]] +name = "cargo_metadata" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cfca2aaa699835ba88faf58a06342a314a950d2b9686165e038286c30316868" +dependencies = [ + "camino", + "cargo-platform", + "cargo-util-schemas", + "semver", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.2.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "derive_more" +version = "0.99.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elsa" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9abf33c656a7256451ebb7d0082c5a471820c31269e49d807c538c252352186e" +dependencies = [ + "indexmap", + "stable_deref_trait", +] + [[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "erased-serde" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "259d404d09818dec19332e31d94558aeb442fea04c817006456c24b5460bbd4b" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "find-msvc-tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" + +[[package]] +name = "flate2" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "gd-rehearse" +version = "0.2.1" +source = "git+https://github.com/JoeyEamigh/gd-rehearse?branch=godot-4.5#1505d7b9ea0df99858a394fab7c366078eb88e2b" +dependencies = [ + "gd-rehearse-defs", + "gd-rehearse-macros", + "godot", +] + +[[package]] +name = "gd-rehearse-defs" +version = "0.2.1" +source = "git+https://github.com/JoeyEamigh/gd-rehearse?branch=godot-4.5#1505d7b9ea0df99858a394fab7c366078eb88e2b" +dependencies = [ + "godot", + "paste", +] + +[[package]] +name = "gd-rehearse-macros" +version = "0.2.1" +source = "git+https://github.com/JoeyEamigh/gd-rehearse?branch=godot-4.5#1505d7b9ea0df99858a394fab7c366078eb88e2b" +dependencies = [ + "gd-rehearse-defs", + "proc-macro2", + "quote", + "venial 0.5.0", +] + [[package]] name = "gdext-gen" version = "0.1.1" @@ -87,8 +351,30 @@ dependencies = [ [[package]] name = "gdextension-api" version = "0.3.0" +source = "git+https://github.com/godot-rust/godot4-prebuilt?branch=release-v0.3#f70baca72747869aaac7781a0cf139f53a2aac19" + +[[package]] +name = "getrandom" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e25d88dabe9fdb2e064cb545312178ec4025eefb62d9a3bbce1769088e2c381d" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.7+wasi-0.2.4", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] [[package]] name = "gimli" @@ -96,6 +382,15 @@ version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" +[[package]] +name = "glam" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5418c17512bdf42730f9032c74e1ae39afc408745ebb2acf72fbc4691c17945" +dependencies = [ + "libm", +] + [[package]] name = "glam" version = "0.30.8" @@ -111,8 +406,7 @@ checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "godot" version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90b20e19a25e45460c4fd2b11b519beea3e9bcda929c1566f8d17a369b41dd82" +source = "git+https://github.com/JoeyEamigh/gdext#a31ea94b3cd8e2871edd2b87841410258f27797e" dependencies = [ "godot-core", "godot-macros", @@ -121,8 +415,7 @@ dependencies = [ [[package]] name = "godot-bindings" version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "508d56d01018c16b67a906bda8bcd9ade7f265990e4be7c2dffecbfdebcc3992" +source = "git+https://github.com/JoeyEamigh/gdext#a31ea94b3cd8e2871edd2b87841410258f27797e" dependencies = [ "gdextension-api", ] @@ -130,14 +423,12 @@ dependencies = [ [[package]] name = "godot-cell" version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1794fbec9934ef375d717d02ec142d9e0c7d7482b24d7da463264b92bc14eaf" +source = "git+https://github.com/JoeyEamigh/gdext#a31ea94b3cd8e2871edd2b87841410258f27797e" [[package]] name = "godot-codegen" version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791e05ae1859028c3a910aaed83e4910ab7701ce32fa663d2dc7cd957287cdf5" +source = "git+https://github.com/JoeyEamigh/gdext#a31ea94b3cd8e2871edd2b87841410258f27797e" dependencies = [ "godot-bindings", "heck", @@ -150,10 +441,9 @@ dependencies = [ [[package]] name = "godot-core" version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b1717ffba78bd2655c9ee1073752ac90d969b8a614800c469f00fc3ddc02439" +source = "git+https://github.com/JoeyEamigh/gdext#a31ea94b3cd8e2871edd2b87841410258f27797e" dependencies = [ - "glam", + "glam 0.30.8", "godot-bindings", "godot-cell", "godot-codegen", @@ -163,8 +453,7 @@ dependencies = [ [[package]] name = "godot-ffi" version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "419e46ba92fba076da67f35ad96faaa830c1de4e8175db2bb4251aeb58b14b08" +source = "git+https://github.com/JoeyEamigh/gdext#a31ea94b3cd8e2871edd2b87841410258f27797e" dependencies = [ "godot-bindings", "godot-codegen", @@ -175,24 +464,37 @@ dependencies = [ [[package]] name = "godot-macros" version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a464e26854e63825d36655759c24556c970a8777535466ebf4ecc7f8e87a4638" +source = "git+https://github.com/JoeyEamigh/gdext#a31ea94b3cd8e2871edd2b87841410258f27797e" dependencies = [ "godot-bindings", "proc-macro2", "quote", - "venial", + "venial 0.6.1", ] [[package]] name = "godottest_rs" version = "0.1.0" dependencies = [ + "bytemuck", + "gd-rehearse", "gdext-gen", "godot", + "spirv-builder", "tokio", ] +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + [[package]] name = "hashbrown" version = "0.16.0" @@ -205,6 +507,113 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + [[package]] name = "indexmap" version = "2.11.4" @@ -212,26 +621,90 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.16.0", ] +[[package]] +name = "internal-iterator" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "969ee3fc68ec2e88eb21434ce4d9b7e1600d1ce92ff974560a6c4a304f5124b9" + [[package]] name = "io-uring" version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" dependencies = [ - "bitflags", + "bitflags 2.9.4", "cfg-if", "libc", ] +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom", + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + [[package]] name = "lock_api" version = "0.4.13" @@ -242,6 +715,27 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "longest-increasing-subsequence" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3bd0dd2cd90571056fdb71f6275fada10131182f84899f4b2a916e565d81d86" + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + [[package]] name = "memchr" version = "2.7.6" @@ -255,6 +749,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -264,7 +759,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", - "wasi", + "wasi 0.11.1+wasi-snapshot-preview1", "windows-sys", ] @@ -283,13 +778,74 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a846cbc04412cf509efcd8f3694b114fc700a035fb5a37f21517f9fb019f1ebc" +[[package]] +name = "noisemap" +version = "0.1.0" +dependencies = [ + "glam 0.24.2", + "libm", + "spirv-std", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "crc32fast", + "flate2", + "hashbrown 0.15.5", + "indexmap", + "memchr", + "ruzstd", +] + [[package]] name = "object" version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ + "crc32fast", + "hashbrown 0.15.5", + "indexmap", "memchr", + "wasmparser", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", ] [[package]] @@ -315,12 +871,33 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + [[package]] name = "pin-project-lite" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +[[package]] +name = "potential_utf" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +dependencies = [ + "zerovec", +] + [[package]] name = "proc-macro2" version = "1.0.101" @@ -339,13 +916,25 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "raw-string" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0501e134c6905fee1f10fed25b0a7e1261bf676cffac9543a7d0730dec01af2" + [[package]] name = "redox_syscall" version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ - "bitflags", + "bitflags 2.9.4", ] [[package]] @@ -377,18 +966,138 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +[[package]] +name = "rspirv" +version = "0.12.0+sdk-1.3.268.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cf3a93856b6e5946537278df0d3075596371b1950ccff012f02b0f7eafec8d" +dependencies = [ + "rustc-hash", + "spirv", +] + [[package]] name = "rustc-demangle" version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_codegen_spirv" +version = "0.9.0" +source = "git+https://github.com/Rust-GPU/rust-gpu?rev=56cc13214566af452de71daf39f7b3f2c65551c2#56cc13214566af452de71daf39f7b3f2c65551c2" +dependencies = [ + "ahash", + "ar", + "bytemuck", + "either", + "indexmap", + "itertools 0.14.0", + "lazy_static", + "libc", + "log", + "object 0.37.3", + "regex", + "rspirv", + "rustc-demangle", + "rustc_codegen_spirv-target-specs", + "rustc_codegen_spirv-types", + "rustix", + "sanitize-filename", + "smallvec", + "spirt", + "spirv-std-types", + "spirv-tools", + "thorin-dwp", + "tracing", + "tracing-subscriber", + "tracing-tree", +] + +[[package]] +name = "rustc_codegen_spirv-target-specs" +version = "0.9.0" +source = "git+https://github.com/Rust-GPU/rust-gpu?rev=56cc13214566af452de71daf39f7b3f2c65551c2#56cc13214566af452de71daf39f7b3f2c65551c2" + +[[package]] +name = "rustc_codegen_spirv-types" +version = "0.9.0" +source = "git+https://github.com/Rust-GPU/rust-gpu?rev=56cc13214566af452de71daf39f7b3f2c65551c2#56cc13214566af452de71daf39f7b3f2c65551c2" +dependencies = [ + "rspirv", + "serde", + "serde_json", + "spirv", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags 2.9.4", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "ruzstd" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad02996bfc73da3e301efe90b1837be9ed8f4a462b6ed410aa35d00381de89f" +dependencies = [ + "twox-hash", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "sanitize-filename" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc984f4f9ceb736a7bb755c3e3bd17dc56370af2600c9780dcc48c66453da34d" +dependencies = [ + "regex", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +dependencies = [ + "serde", + "serde_core", +] + [[package]] name = "serde" version = "1.0.228" @@ -399,6 +1108,28 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-untagged" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" +dependencies = [ + "erased-serde", + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + [[package]] name = "serde_core" version = "1.0.228" @@ -419,6 +1150,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + [[package]] name = "serde_spanned" version = "0.6.9" @@ -428,6 +1172,21 @@ dependencies = [ "serde", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.6" @@ -437,6 +1196,12 @@ dependencies = [ "libc", ] +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "slab" version = "0.4.11" @@ -448,6 +1213,9 @@ name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -459,6 +1227,114 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "spirt" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2d5968bd2a36466468aac637b355776f080edfb0c6f769b2b99b9708260c42a" +dependencies = [ + "arrayvec", + "bytemuck", + "derive_more", + "elsa", + "indexmap", + "internal-iterator", + "itertools 0.10.5", + "lazy_static", + "longest-increasing-subsequence", + "rustc-hash", + "serde", + "serde_json", + "smallvec", +] + +[[package]] +name = "spirv" +version = "0.3.0+sdk-1.3.268.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +dependencies = [ + "bitflags 2.9.4", + "serde", +] + +[[package]] +name = "spirv-builder" +version = "0.9.0" +source = "git+https://github.com/Rust-GPU/rust-gpu?rev=56cc13214566af452de71daf39f7b3f2c65551c2#56cc13214566af452de71daf39f7b3f2c65551c2" +dependencies = [ + "cargo_metadata", + "log", + "memchr", + "raw-string", + "rustc_codegen_spirv", + "rustc_codegen_spirv-target-specs", + "rustc_codegen_spirv-types", + "semver", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "spirv-std" +version = "0.9.0" +source = "git+https://github.com/Rust-GPU/rust-gpu?rev=56cc13214566af452de71daf39f7b3f2c65551c2#56cc13214566af452de71daf39f7b3f2c65551c2" +dependencies = [ + "bitflags 1.3.2", + "glam 0.24.2", + "libm", + "num-traits", + "spirv-std-macros", + "spirv-std-types", +] + +[[package]] +name = "spirv-std-macros" +version = "0.9.0" +source = "git+https://github.com/Rust-GPU/rust-gpu?rev=56cc13214566af452de71daf39f7b3f2c65551c2#56cc13214566af452de71daf39f7b3f2c65551c2" +dependencies = [ + "proc-macro2", + "quote", + "spirv-std-types", + "syn", +] + +[[package]] +name = "spirv-std-types" +version = "0.9.0" +source = "git+https://github.com/Rust-GPU/rust-gpu?rev=56cc13214566af452de71daf39f7b3f2c65551c2#56cc13214566af452de71daf39f7b3f2c65551c2" + +[[package]] +name = "spirv-tools" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b10991c25e3adc32c018c528be2cdef16c0cdfaf8581fbeabb033b547a599ec" +dependencies = [ + "spirv-tools-sys", +] + +[[package]] +name = "spirv-tools-sys" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c78c1a8af381edef1b7ca7d7caea9d6454dccb4b00a35b7b968b44b8212f487" +dependencies = [ + "cc", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "syn" version = "2.0.104" @@ -470,6 +1346,76 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thorin-dwp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e9c1e705f82a260173f3eec93f2ff6d7807f23ad5a8cc2e7316a891733ea7a1" +dependencies = [ + "gimli 0.31.1", + "hashbrown 0.15.5", + "object 0.36.7", + "tracing", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "tilemap" +version = "0.1.0" +dependencies = [ + "glam 0.24.2", + "spirv-std", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tokio" version = "1.47.1" @@ -543,12 +1489,154 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "tracing-tree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac87aa03b6a4d5a7e4810d1a80c19601dbe0f8a837e9177f23af721c7ba7beec" +dependencies = [ + "nu-ansi-term", + "tracing-core", + "tracing-log", + "tracing-subscriber", +] + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "static_assertions", +] + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + [[package]] name = "unicode-ident" version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "url" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "venial" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61584a325b16f97b5b25fcc852eb9550843a251057a5e3e5992d2376f3df4bb2" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "venial" version = "0.6.1" @@ -559,12 +1647,45 @@ dependencies = [ "quote", ] +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasmparser" +version = "0.236.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9b1e81f3eb254cf7404a82cee6926a4a3ccc5aad80cc3d43608a070c67aa1d7" +dependencies = [ + "bitflags 2.9.4", +] + [[package]] name = "windows-link" version = "0.2.1" @@ -652,3 +1773,113 @@ checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ "memchr", ] + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 97e0523..187cb9c 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -3,12 +3,26 @@ name = "godottest_rs" version = "0.1.0" edition = "2024" +[workspace] +resolver = "3" +members = ["shaders/*"] + [lib] crate-type = ["cdylib"] +[features] +default = ["gd_rehearse_tests"] +gd_rehearse_tests = ["gd-rehearse"] + [dependencies] -godot = { version = "0.4.0", features = ["api-4-5"] } +godot = { git = "https://github.com/JoeyEamigh/gdext", features = ["api-4-5"] } tokio = { version = "1.47.1", features = ["full"] } +bytemuck = { version = "1.14", features = ["derive"] } +gd-rehearse = { git = "https://github.com/JoeyEamigh/gd-rehearse", branch = "godot-4.5", optional = true } [build-dependencies] gdext-gen = { version = "0.1.1", features = ["dependencies", "find_icons"] } +spirv-builder = { git = "https://github.com/Rust-GPU/rust-gpu", rev = "56cc13214566af452de71daf39f7b3f2c65551c2", package = "spirv-builder" } + +[patch.crates-io] +godot = { git = "https://github.com/JoeyEamigh/gdext", features = ["api-4-5"] } diff --git a/rust/build.rs b/rust/build.rs index 99ebad5..678d6b5 100644 --- a/rust/build.rs +++ b/rust/build.rs @@ -1,18 +1,26 @@ use gdext_gen::prelude::*; -use std::io::Result; +use spirv_builder::{MetadataPrintout, SpirvBuilder}; + +fn main() -> Result<(), Box> { + SpirvBuilder::new("./shaders/tilemap", "spirv-unknown-spv1.6") + .print_metadata(MetadataPrintout::Full) + .build()?; + + SpirvBuilder::new("./shaders/noisemap", "spirv-unknown-spv1.6") + .print_metadata(MetadataPrintout::Full) + .build()?; -fn main() -> Result<()> { // All your variable initialization and setup goes here. generate_gdextension_file( BaseDirectory::ProjectFolder, Some("../rust/target".into()), - Some("../godot/Rust.gdextension".into()), + Some("../godot/rust.gdextension".into()), true, Some(Configuration::new( EntrySymbol::GodotRustDefault, Some((4, 1)), None, - false, + true, false, )), Some(WindowsABI::MSVC), diff --git a/rust/rust-toolchain.toml b/rust/rust-toolchain.toml new file mode 100644 index 0000000..1e4ccc6 --- /dev/null +++ b/rust/rust-toolchain.toml @@ -0,0 +1,13 @@ +[toolchain] +channel = "nightly-2025-06-30" +components = [ + "rustc", + "cargo", + "rustfmt", + "clippy", + "rust-std", + "rust-analyzer", + "rust-src", + "llvm-tools", + "rustc-dev", +] diff --git a/rust/shaders/noisemap/Cargo.toml b/rust/shaders/noisemap/Cargo.toml new file mode 100644 index 0000000..dcb0f6b --- /dev/null +++ b/rust/shaders/noisemap/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "noisemap" +version = "0.1.0" +edition = "2024" + +[lib] +crate-type = ["dylib"] + +[dependencies] +glam = { version = ">=0.22, <=0.30.7", default-features = false, features = [ + "libm", +] } +spirv-std = { git = "https://github.com/Rust-GPU/rust-gpu", rev = "56cc13214566af452de71daf39f7b3f2c65551c2", package = "spirv-std" } +libm = { version = "0.2", default-features = false } diff --git a/rust/shaders/noisemap/src/lib.rs b/rust/shaders/noisemap/src/lib.rs new file mode 100644 index 0000000..3dcdd94 --- /dev/null +++ b/rust/shaders/noisemap/src/lib.rs @@ -0,0 +1,111 @@ +#![no_std] +// HACK(eddyb) can't easily see warnings otherwise from `spirv-builder` builds. +#![deny(warnings)] +#![allow(unexpected_cfgs)] + +use libm::{fabsf, floorf}; +use spirv_std::{RuntimeArray, glam::UVec3, spirv}; + +#[repr(C)] +pub struct NoiseParams { + pub map_width: u32, + pub map_height: u32, + pub seed: u32, + pub _pad0: u32, + pub noise_scale: f32, + pub noise_magnitude: f32, + pub _pad1: f32, + pub _pad2: f32, +} + +#[inline(always)] +fn fade(t: f32) -> f32 { + t * t * t * (t * (t * 6.0 - 15.0) + 10.0) +} + +#[inline(always)] +fn lerp(a: f32, b: f32, t: f32) -> f32 { + a + (b - a) * t +} + +#[inline(always)] +fn hash(seed: u32, x: i32, y: i32) -> u32 { + let mut v = seed ^ (x as u32).wrapping_mul(0x27d4_eb2d); + v = v.wrapping_add((y as u32).wrapping_mul(0x1656_67b1)); + v ^= v >> 15; + v = v.wrapping_mul(0x85eb_ca6b); + v ^= v >> 13; + v = v.wrapping_mul(0xc2b2_ae35); + v ^ (v >> 16) +} + +#[inline(always)] +fn grad(hash: u32, x: f32, y: f32) -> f32 { + let h = (hash & 0x7) as i32; + let u = if h < 4 { x } else { y }; + let v = if h < 4 { y } else { x }; + let mut result = if (h & 1) == 0 { u } else { -u }; + result += if (h & 2) == 0 { v } else { -v }; + result +} + +#[inline(always)] +fn clampf(value: f32, min: f32, max: f32) -> f32 { + if value < min { + min + } else if value > max { + max + } else { + value + } +} + +#[spirv(compute(threads(16, 16, 1)))] +pub fn main( + #[spirv(global_invocation_id)] id: UVec3, + #[spirv(storage_buffer, descriptor_set = 0, binding = 0)] params: &NoiseParams, + #[spirv(storage_buffer, descriptor_set = 0, binding = 1)] output_map: &mut RuntimeArray, +) { + let x = id.x; + let y = id.y; + + if x >= params.map_width || y >= params.map_height { + return; + } + + let width = params.map_width; + let index = (y * width + x) as usize; + + let scale = if params.noise_scale.abs() < 0.0001 { + 1.0 + } else { + params.noise_scale + }; + let sample_x = (x as f32 + 0.5) * scale; + let sample_y = (y as f32 + 0.5) * scale; + + let ix = floorf(sample_x) as i32; + let iy = floorf(sample_y) as i32; + let fx = clampf(sample_x - ix as f32, 0.0, 1.0); + let fy = clampf(sample_y - iy as f32, 0.0, 1.0); + + let wx = fade(fx); + let wy = fade(fy); + + let v00 = grad(hash(params.seed, ix, iy), fx, fy); + let v10 = grad(hash(params.seed, ix + 1, iy), fx - 1.0, fy); + let v01 = grad(hash(params.seed, ix, iy + 1), fx, fy - 1.0); + let v11 = grad(hash(params.seed, ix + 1, iy + 1), fx - 1.0, fy - 1.0); + + let nx0 = lerp(v00, v10, wx); + let nx1 = lerp(v01, v11, wx); + let value = clampf(lerp(nx0, nx1, wy) * 0.707_106_77, -1.0, 1.0); + + let magnitude = fabsf(params.noise_magnitude); + let noise = fabsf(value) * magnitude; + let clamped = clampf(noise, 0.0, 2_147_483_647.0); + + unsafe { + *output_map.index_mut(index) = floorf(clamped) as u32; + } +} diff --git a/rust/shaders/tilemap/Cargo.toml b/rust/shaders/tilemap/Cargo.toml new file mode 100644 index 0000000..612f9ab --- /dev/null +++ b/rust/shaders/tilemap/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "tilemap" +version = "0.1.0" +edition = "2024" + +[lib] +crate-type = ["dylib"] + +[dependencies] +glam = { version = ">=0.22, <=0.30.7", default-features = false } +spirv-std = { git = "https://github.com/Rust-GPU/rust-gpu", rev = "56cc13214566af452de71daf39f7b3f2c65551c2", package = "spirv-std" } diff --git a/rust/shaders/tilemap/src/lib.rs b/rust/shaders/tilemap/src/lib.rs new file mode 100644 index 0000000..3d24c7a --- /dev/null +++ b/rust/shaders/tilemap/src/lib.rs @@ -0,0 +1,89 @@ +#![no_std] +// HACK(eddyb) can't easily see warnings otherwise from `spirv-builder` builds. +#![deny(warnings)] +#![allow(unexpected_cfgs)] + +use spirv_std::{RuntimeArray, glam::UVec3, spirv}; + +#[repr(C)] +pub struct TilemapParams { + pub out_width: u32, + pub out_height: u32, + pub tile_size: u32, + pub map_width: u32, + pub map_height: u32, + pub atlas_width: u32, + pub atlas_height: u32, +} + +// 8x8 workgroup covers 64 pixels per dispatch group +#[spirv(compute(threads(8, 8, 1)))] +pub fn main( + #[spirv(global_invocation_id)] id: UVec3, + #[spirv(storage_buffer, descriptor_set = 0, binding = 0)] params: &TilemapParams, + #[spirv(storage_buffer, descriptor_set = 0, binding = 1)] map: &RuntimeArray, + #[spirv(storage_buffer, descriptor_set = 0, binding = 2)] atlas_rgba: &RuntimeArray, + #[spirv(storage_buffer, descriptor_set = 0, binding = 3)] output_rgba: &mut RuntimeArray, +) { + let x = id.x; + let y = id.y; + + if params.tile_size == 0 || x >= params.out_width || y >= params.out_height { + return; + } + + let tile_size = params.tile_size; + let tile_x = x / tile_size; + let tile_y = y / tile_size; + + if tile_x >= params.map_width || tile_y >= params.map_height { + return; + } + + if params.atlas_width < tile_size { + return; + } + + let atlas_tiles_per_row = params.atlas_width / tile_size; + if atlas_tiles_per_row == 0 { + return; + } + + let map_index = tile_y * params.map_width + tile_x; + let map_capacity = params.map_width * params.map_height; + if map_index >= map_capacity { + return; + } + + let tile_index = unsafe { *map.index(map_index as usize) }; + + let atlas_tile_x = tile_index % atlas_tiles_per_row; + let atlas_tile_y = tile_index / atlas_tiles_per_row; + + let local_x = x % tile_size; + let local_y = y % tile_size; + + let atlas_x = atlas_tile_x * tile_size + local_x; + let atlas_y = atlas_tile_y * tile_size + local_y; + + if atlas_x >= params.atlas_width || atlas_y >= params.atlas_height { + return; + } + + let atlas_width = params.atlas_width; + let dst_width = params.out_width; + + let src_index = atlas_y * atlas_width + atlas_x; + let dst_index = y * dst_width + x; + let atlas_capacity = atlas_width * params.atlas_height; + let dst_capacity = params.out_width * params.out_height; + + if src_index >= atlas_capacity || dst_index >= dst_capacity { + return; + } + + let pixel = unsafe { *atlas_rgba.index(src_index as usize) }; + unsafe { + *output_rgba.index_mut(dst_index as usize) = pixel; + } +} diff --git a/rust/src/Mappy.rs b/rust/src/Mappy.rs deleted file mode 100644 index 2d9b327..0000000 --- a/rust/src/Mappy.rs +++ /dev/null @@ -1,194 +0,0 @@ -use std::time::{SystemTime, UNIX_EPOCH}; - -use godot::classes::base_material_3d::{ShadingMode, TextureParam}; -use godot::classes::image::Format; -use godot::classes::mesh::ArrayType; -use godot::classes::{ - BaseMaterial3D, Camera3D, CompressedTexture2D, FastNoiseLite, IMeshInstance3D, Image, ImageTexture, Input, - MeshInstance3D, QuadMesh, StandardMaterial3D, Texture2D, -}; -use godot::global::Key; -use godot::meta::ByOption; -use godot::prelude::*; - -#[derive(GodotClass)] -#[class(base=MeshInstance3D)] -struct Mappy { - #[export] - map_width: i32, - #[export] - map_height: i32, - #[export] - noise_scale: f32, - #[export] - noise_magnitude: f32, - #[export] - texture_atlas: OnEditor>, - - map: Array, - - is_generated: bool, - - // required - base: Base, -} - -#[godot_api] -impl IMeshInstance3D for Mappy { - fn init(base: Base) -> Self { - let mut standard_array: Array = Array::new(); - let width: i32 = 32; - let height: i32 = 32; - standard_array.resize((width * height) as usize, 0); - - Self { - map_width: width, - map_height: height, - noise_scale: 1.0, - noise_magnitude: 5.0, - texture_atlas: OnEditor::default(), - map: standard_array, - is_generated: false, - base, - } - } - - fn ready(&mut self) { - self.is_generated = false; - self.generateMap(); - self.createTexture(); - } - - fn process(&mut self, delta: f32) { - let input = Input::singleton(); - if (input.is_action_just_pressed("ui_accept")) { - self.generateMap(); - self.createTexture(); - } - } -} - -impl Mappy { - fn generateMap(&mut self) { - let mut new_map: Array = Array::new(); - - let mut noise = FastNoiseLite::new_gd(); - let now = SystemTime::now(); - let duration_since_epoch = now.duration_since(UNIX_EPOCH).expect("Time went backwards"); // Handle potential errors if the system clock is adjusted - - let milliseconds = duration_since_epoch.as_millis(); - noise.set_seed(milliseconds as i32); - new_map.resize((self.map_width * self.map_height) as usize, 0); - for x in 0..self.map_width { - for y in 0..self.map_height { - new_map.set( - (x + y * self.map_height) as usize, - (noise.get_noise_2d(x as f32 * self.noise_scale, y as f32 * self.noise_scale) * self.noise_magnitude).abs() - as i32, - ); - } - } - self.map = new_map; - } - - fn createTexture(&mut self) { - if (self.is_generated) { - let old_node = self.base().get_node_as::("Map Quad"); - self.base_mut().remove_child(&old_node); - old_node.free(); - } - - self.is_generated = true; - let mut quad = QuadMesh::new_gd(); - quad.set_size(Vector2::new(1.0, 1.0)); - let mut mat = StandardMaterial3D::new_gd(); - mat.set_shading_mode(ShadingMode::UNSHADED); - - let use_mipmaps = false; - let format = Format::RGBA8; // Or another desired format - - let mut image = Image::create(self.map_width * 16, self.map_height * 16, use_mipmaps, format) - .expect("Couldn't create texture for map"); - let atlas = self.texture_atlas.get_image(); - - // Example: Fill the image with a solid color - for i in 0..self.map_width { - for j in 0..self.map_height { - let map_index = self.map.at((i + j * self.map_width) as usize); - image.blit_rect( - atlas.as_ref(), - Rect2i::new( - Vector2i::new(map_index % 16 * 16, (map_index / 16) * 16), - Vector2i::new(16, 16), - ), - Vector2i::new(i * 16, j * 16), - ); - } - } - - let mut tex = ImageTexture::new_gd(); - tex.set_image(&image); - - mat.set_texture(TextureParam::ALBEDO, &tex); - quad.set_material(&mat); - - let mut mesh = MeshInstance3D::new_alloc(); - mesh.set_name("Map Quad"); - mesh.set_mesh(&quad); - self.base_mut().add_child(&mesh); - } -} - -#[derive(GodotClass)] -#[class(base=Node3D)] -struct Player { - #[export] - character_name: GString, - #[export] - velocity: Vector3, - #[export] - acceleration: Vector3, - base: Base, -} - -#[godot_api] -impl INode3D for Player { - fn init(base: Base) -> Self { - Self { - character_name: GString::from("Hello"), - velocity: Vector3::ZERO, - acceleration: Vector3::new(1.0, 1.0, 0.0), - base, - } - } - - fn process(&mut self, delta: f32) { - self.processInput(delta); - self.updatePosition(delta); - } -} - -impl Player { - fn processInput(&mut self, delta: f32) { - let input = Input::singleton(); - if (input.is_key_pressed(Key::W)) { - self.velocity.y += self.acceleration.y; - } - if (input.is_key_pressed(Key::A)) { - self.velocity.x -= self.acceleration.x; - } - if (input.is_key_pressed(Key::S)) { - self.velocity.y -= self.acceleration.y; - } - if (input.is_key_pressed(Key::D)) { - self.velocity.x += self.acceleration.x; - } - } - - fn updatePosition(&mut self, delta: f32) { - let before_move = self.base_mut().get_transform(); - let after_move = before_move.translated(self.velocity * delta); - self.base_mut().set_transform(after_move); - self.velocity *= 0.5; - } -} diff --git a/rust/src/lib.rs b/rust/src/lib.rs index e325b3e..fc6de84 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -3,6 +3,7 @@ use godot::{classes::Engine, prelude::*}; mod runtime; mod Mappy; +mod player; struct MyExtension; diff --git a/rust/src/mappy.rs b/rust/src/mappy.rs new file mode 100644 index 0000000..69dcfce --- /dev/null +++ b/rust/src/mappy.rs @@ -0,0 +1,1133 @@ +use std::time::{Instant, SystemTime, UNIX_EPOCH}; + +use bytemuck::{Pod, Zeroable, bytes_of, cast_slice}; +use godot::builtin::PackedByteArray; +use godot::classes::base_material_3d::{ShadingMode, TextureParam}; +use godot::classes::image::Format; +use godot::classes::rendering_device::{BufferCreationBits, ShaderStage, UniformType}; +use godot::classes::{ + CompressedTexture2D, FastNoiseLite, IMeshInstance3D, Image, ImageTexture, Input, MeshInstance3D, QuadMesh, + RdShaderSpirv, RdUniform, RenderingDevice, RenderingServer, StandardMaterial3D, +}; +use godot::prelude::*; + +const TILEMAP_SHADER: &[u8] = include_bytes!(env!("tilemap.spv")); +const NOISE_SHADER: &[u8] = include_bytes!(env!("noisemap.spv")); +const TILE_SIZE: u32 = 16; + +#[derive(GodotClass)] +#[class(base=MeshInstance3D)] +struct Mappy { + #[export] + map_width: i32, + #[export] + map_height: i32, + #[export] + noise_scale: f32, + #[export] + noise_magnitude: f32, + #[export] + texture_atlas: OnEditor>, + + map: Array, + + is_generated: bool, + map_mesh: Option>, + map_texture: Option>, + gpu_context: Option, + + // required + base: Base, +} + +#[godot_api] +impl IMeshInstance3D for Mappy { + fn init(base: Base) -> Self { + let mut standard_array: Array = Array::new(); + let width: i32 = 32; + let height: i32 = 32; + standard_array.resize((width * height) as usize, 0); + + Self { + map_width: width, + map_height: height, + noise_scale: 1.0, + noise_magnitude: 5.0, + texture_atlas: OnEditor::default(), + map: standard_array, + is_generated: false, + map_mesh: None, + map_texture: None, + gpu_context: None, + base, + } + } + + fn ready(&mut self) { + self.is_generated = false; + self.generate_map(); + self.create_texture(); + } + + fn process(&mut self, _delta: f32) { + let input = Input::singleton(); + if input.is_action_just_pressed("ui_accept") { + self.generate_map(); + self.create_texture(); + } + } +} + +impl Mappy { + fn generate_map(&mut self) { + let now = SystemTime::now(); + let duration_since_epoch = match now.duration_since(UNIX_EPOCH) { + Ok(duration) => duration, + Err(err) => { + godot_error!("Time went backwards during map generation: {}", err); + return; + } + }; + + let milliseconds = duration_since_epoch.as_millis(); + let seed_u32 = (milliseconds & 0xFFFF_FFFF) as u32; + let seed_i32 = milliseconds as i128; + let seed_i32 = seed_i32 as i32; + + godot_print!( + "Generating noise map {}x{} tiles (scale {:.2}, magnitude {:.2}, seed={})", + self.map_width, + self.map_height, + self.noise_scale, + self.noise_magnitude, + milliseconds + ); + + self.generate_map_cpu(seed_i32); + // if let Err(gpu_err) = self.generate_map_gpu(seed_u32) { + // godot_warn!("GPU noise generation failed: {}", gpu_err); + // self.gpu_context = None; + // self.generate_map_cpu(seed_i32); + // } + } + + fn compute_context_mut(&mut self) -> Result<&mut GpuComputeContext, String> { + if self.gpu_context.is_none() { + self.gpu_context = Some(GpuComputeContext::new()?); + } + Ok( + self + .gpu_context + .as_mut() + .expect("GPU context must exist after initialization"), + ) + } + + fn generate_map_gpu(&mut self, seed: u32) -> Result<(), String> { + let map_width = self.map_width; + let map_height = self.map_height; + let noise_scale = self.noise_scale; + let noise_magnitude = self.noise_magnitude; + + if map_width <= 0 || map_height <= 0 { + return Err("Map dimensions must be positive".to_string()); + } + + let tile_count = (map_width as usize) + .checked_mul(map_height as usize) + .ok_or_else(|| "Tile count overflow".to_string())?; + + let params = NoiseGpuParams { + map_width: map_width as u32, + map_height: map_height as u32, + seed, + _pad0: 0, + noise_scale, + noise_magnitude: noise_magnitude.abs(), + _pad1: 0.0, + _pad2: 0.0, + }; + + let gpu_start = Instant::now(); + let values = { + let context = self.compute_context_mut()?; + context.generate_noise(¶ms)? + }; + if values.len() != tile_count { + return Err(format!( + "GPU noise output length mismatch. Expected {}, got {}", + tile_count, + values.len() + )); + } + + let mut new_map: Array = Array::new(); + new_map.resize(tile_count, 0); + for (index, value) in values.iter().enumerate() { + let clamped = (*value).min(i32::MAX as u32); + new_map.set(index, clamped as i32); + } + self.map = new_map; + + let total_ms = gpu_start.elapsed().as_secs_f64() * 1000.0; + godot_print!( + "GPU noise map generation complete for {} tiles in {:.2} ms", + self.map.len(), + total_ms + ); + + Ok(()) + } + + fn generate_map_cpu(&mut self, seed: i32) { + let overall_start = Instant::now(); + let mut new_map: Array = Array::new(); + new_map.resize((self.map_width * self.map_height) as usize, 0); + + let mut noise = FastNoiseLite::new_gd(); + noise.set_seed(seed); + + let fill_start = Instant::now(); + for x in 0..self.map_width { + for y in 0..self.map_height { + new_map.set( + (x + y * self.map_height) as usize, + (noise.get_noise_2d(x as f32 * self.noise_scale, y as f32 * self.noise_scale) * self.noise_magnitude).abs() + as i32, + ); + } + } + self.map = new_map; + + let fill_ms = fill_start.elapsed().as_secs_f64() * 1000.0; + let total_ms = overall_start.elapsed().as_secs_f64() * 1000.0; + godot_print!( + "CPU noise generation complete for {} tiles in {:.2} ms (noise fill {:.2} ms)", + self.map.len(), + total_ms, + fill_ms + ); + } + + fn create_texture(&mut self) { + let overall_start = Instant::now(); + + if self.map_mesh.as_ref().is_some_and(|mesh| !mesh.is_instance_valid()) { + self.map_mesh = None; + } + + if self + .map_texture + .as_ref() + .is_some_and(|texture| !texture.is_instance_valid()) + { + self.map_texture = None; + } + + let Some(mut atlas_image) = self.texture_atlas.get_image() else { + godot_error!("Texture atlas has no readable image data"); + return; + }; + + let atlas_prepare_start = Instant::now(); + if atlas_image.get_format() != Format::RGBA8 { + atlas_image.convert(Format::RGBA8); + } + + let atlas_width = atlas_image.get_width(); + let atlas_height = atlas_image.get_height(); + godot_print!( + "Creating tilemap texture: map {}x{} tiles, tile_size {}, atlas {}x{} px", + self.map_width, + self.map_height, + TILE_SIZE, + atlas_width, + atlas_height + ); + let atlas_prepare_ms = atlas_prepare_start.elapsed().as_secs_f64() * 1000.0; + godot_print!("Atlas fetch + convert finished in {:.2} ms", atlas_prepare_ms); + + let map_clone = self.map.clone(); + let map_len = map_clone.len(); + let map_width = self.map_width; + let map_height = self.map_height; + + let gpu_start = Instant::now(); + let gpu_result = { + match self.compute_context_mut() { + Ok(context) => { + godot_print!("Attempting GPU tilemap generation for {} tiles", map_len); + Self::generate_texture_gpu(context, &map_clone, map_width, map_height, TILE_SIZE, &atlas_image) + } + Err(err) => Err(err), + } + }; + let image = match gpu_result { + Ok(image) => { + let gpu_ms = gpu_start.elapsed().as_secs_f64() * 1000.0; + let width = image.get_width(); + let height = image.get_height(); + godot_print!( + "Generated tilemap texture on GPU in {:.2} ms ({}x{} px)", + gpu_ms, + width, + height + ); + image + } + Err(gpu_err) => { + let gpu_ms = gpu_start.elapsed().as_secs_f64() * 1000.0; + godot_warn!("GPU tilemap generation failed after {:.2} ms: {}", gpu_ms, gpu_err); + godot_print!("Falling back to CPU tilemap generation path"); + self.gpu_context = None; + let cpu_start = Instant::now(); + match Self::create_texture_cpu( + &self.map, + self.map_width, + self.map_height, + TILE_SIZE, + &atlas_image, + Format::RGBA8, + ) { + Ok(image) => { + let cpu_ms = cpu_start.elapsed().as_secs_f64() * 1000.0; + let width = image.get_width(); + let height = image.get_height(); + godot_print!( + "Generated tilemap texture on CPU fallback in {:.2} ms ({}x{} px)", + cpu_ms, + width, + height + ); + image + } + Err(cpu_err) => { + let cpu_ms = cpu_start.elapsed().as_secs_f64() * 1000.0; + godot_error!("CPU tilemap generation failed after {:.2} ms: {}", cpu_ms, cpu_err); + return; + } + } + } + }; + + let texture_handle = if let Some(tex) = self.map_texture.as_mut() { + tex.update(&image); + tex.clone() + } else { + let mut tex = ImageTexture::new_gd(); + tex.set_image(&image); + let tex_clone = tex.clone(); + self.map_texture = Some(tex); + tex_clone + }; + + let mut quad = QuadMesh::new_gd(); + quad.set_size(Vector2::new(1.0, 1.0)); + let mut mat = StandardMaterial3D::new_gd(); + mat.set_shading_mode(ShadingMode::UNSHADED); + mat.set_texture(TextureParam::ALBEDO, &texture_handle); + quad.set_material(&mat); + + if let Some(mesh) = self.map_mesh.as_mut() { + mesh.set_mesh(&quad); + } else { + let mut mesh = MeshInstance3D::new_alloc(); + mesh.set_name("Map Quad"); + mesh.set_mesh(&quad); + self.base_mut().add_child(&mesh); + self.map_mesh = Some(mesh); + } + + self.is_generated = true; + + let total_ms = overall_start.elapsed().as_secs_f64() * 1000.0; + godot_print!("create_texture() finished in {:.2} ms", total_ms); + } + + fn generate_texture_gpu( + context: &mut GpuComputeContext, + map: &Array, + map_width: i32, + map_height: i32, + tile_size: u32, + atlas: &Gd, + ) -> Result, String> { + if tile_size == 0 { + return Err("Tile size must be positive".to_string()); + } + + if map_width <= 0 || map_height <= 0 { + return Err("Map dimensions must be positive".to_string()); + } + + let map_width_u32 = map_width as u32; + let map_height_u32 = map_height as u32; + let out_width = map_width_u32 + .checked_mul(tile_size) + .ok_or_else(|| "Texture width overflow".to_string())?; + let out_height = map_height_u32 + .checked_mul(tile_size) + .ok_or_else(|| "Texture height overflow".to_string())?; + + if out_width == 0 || out_height == 0 { + return Err("Texture dimensions resolve to zero".to_string()); + } + + let atlas_width = atlas.get_width(); + let atlas_height = atlas.get_height(); + if atlas_width <= 0 || atlas_height <= 0 { + return Err("Atlas has invalid dimensions".to_string()); + } + + let atlas_width_u32 = atlas_width as u32; + let atlas_height_u32 = atlas_height as u32; + + if !atlas_width_u32.is_multiple_of(tile_size) || !atlas_height_u32.is_multiple_of(tile_size) { + return Err("Atlas dimensions must be multiples of the tile size".to_string()); + } + + let atlas_bytes = atlas.get_data().to_vec(); + let expected_atlas_bytes = (atlas_width as usize) + .checked_mul(atlas_height as usize) + .and_then(|v| v.checked_mul(4)) + .ok_or_else(|| "Atlas size overflow".to_string())?; + + if atlas_bytes.len() != expected_atlas_bytes { + return Err(format!( + "Atlas data size mismatch. Expected {}, got {}", + expected_atlas_bytes, + atlas_bytes.len() + )); + } + + let map_vec = Self::map_to_vec(map, map_width_u32, map_height_u32)?; + + let params = TilemapGpuParams { + out_width, + out_height, + tile_size, + map_width: map_width_u32, + map_height: map_height_u32, + atlas_width: atlas_width as u32, + atlas_height: atlas_height as u32, + }; + + let gpu_bytes = context.run_tilemap_compute(¶ms, &map_vec, &atlas_bytes)?; + + Image::create_from_data(out_width as i32, out_height as i32, false, Format::RGBA8, &gpu_bytes) + .ok_or_else(|| "Failed to create image from GPU output".to_string()) + } + + fn create_texture_cpu( + map: &Array, + map_width: i32, + map_height: i32, + tile_size: u32, + atlas: &Gd, + format: Format, + ) -> Result, String> { + if tile_size == 0 { + return Err("Tile size must be positive".to_string()); + } + + let map_width_u32 = map_width as u32; + let map_height_u32 = map_height as u32; + + let out_width = map_width_u32 + .checked_mul(tile_size) + .ok_or_else(|| "CPU texture width overflow".to_string())?; + let out_height = map_height_u32 + .checked_mul(tile_size) + .ok_or_else(|| "CPU texture height overflow".to_string())?; + + if out_width == 0 || out_height == 0 { + return Err("CPU output dimensions resolve to zero".to_string()); + } + + let atlas_width = atlas.get_width(); + let atlas_height = atlas.get_height(); + + if atlas_width <= 0 || atlas_height <= 0 { + return Err("Atlas has invalid dimensions".to_string()); + } + + let atlas_width_u32 = atlas_width as u32; + let atlas_height_u32 = atlas_height as u32; + + if !atlas_width_u32.is_multiple_of(tile_size) || !atlas_height_u32.is_multiple_of(tile_size) { + return Err("Atlas dimensions must be multiples of the tile size".to_string()); + } + + let atlas_bytes = atlas.get_data().to_vec(); + let expected_atlas_bytes = (atlas_width as usize) + .checked_mul(atlas_height as usize) + .and_then(|v| v.checked_mul(4)) + .ok_or_else(|| "Atlas size overflow".to_string())?; + + if atlas_bytes.len() != expected_atlas_bytes { + return Err(format!( + "Atlas data size mismatch. Expected {}, got {}", + expected_atlas_bytes, + atlas_bytes.len() + )); + } + + let map_vec = Self::map_to_vec(map, map_width_u32, map_height_u32)?; + + let output_size = (out_width as usize) + .checked_mul(out_height as usize) + .and_then(|v| v.checked_mul(4)) + .ok_or_else(|| "CPU output size overflow".to_string())?; + + let mut output = vec![0u8; output_size]; + + let tile_size_usize = tile_size as usize; + let atlas_width_usize = atlas_width_u32 as usize; + let out_width_usize = out_width as usize; + let atlas_tiles_per_row = atlas_width_usize / tile_size_usize; + + if atlas_tiles_per_row == 0 { + return Err("Atlas cannot fit any tiles".to_string()); + } + + for tile_y in 0..map_height_u32 as usize { + for tile_x in 0..map_width_u32 as usize { + let tile_index = map_vec[tile_y * map_width_u32 as usize + tile_x] as usize; + + let atlas_tile_x = tile_index % atlas_tiles_per_row; + let atlas_tile_y = tile_index / atlas_tiles_per_row; + + for local_y in 0..tile_size_usize { + let dst_row = tile_y * tile_size_usize + local_y; + let src_row = atlas_tile_y * tile_size_usize + local_y; + + let dst_offset = (dst_row * out_width_usize + tile_x * tile_size_usize) * 4; + let src_offset = (src_row * atlas_width_usize + atlas_tile_x * tile_size_usize) * 4; + + let bytes_per_row = tile_size_usize * 4; + + let dst_slice = dst_offset..dst_offset + bytes_per_row; + let src_slice = src_offset..src_offset + bytes_per_row; + + if dst_slice.end > output.len() || src_slice.end > atlas_bytes.len() { + return Err("Tile copy exceeded buffer bounds".to_string()); + } + + output[dst_slice].copy_from_slice(&atlas_bytes[src_slice]); + } + } + } + + let packed = PackedByteArray::from(output); + + Image::create_from_data(out_width as i32, out_height as i32, false, format, &packed) + .ok_or_else(|| "Failed to create CPU image".to_string()) + } + + fn map_to_vec(map: &Array, map_width: u32, map_height: u32) -> Result, String> { + let expected = (map_width as usize) + .checked_mul(map_height as usize) + .ok_or_else(|| "Tilemap size overflow".to_string())?; + + if map.len() != expected { + return Err(format!("Tilemap has {} entries but expected {}", map.len(), expected)); + } + + let mut result = Vec::with_capacity(expected); + for index in 0..expected { + let value = map.at(index); + result.push(if value < 0 { 0 } else { value as u32 }); + } + + Ok(result) + } +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Pod, Zeroable)] +struct TilemapGpuParams { + out_width: u32, + out_height: u32, + tile_size: u32, + map_width: u32, + map_height: u32, + atlas_width: u32, + atlas_height: u32, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Pod, Zeroable)] +struct NoiseGpuParams { + map_width: u32, + map_height: u32, + seed: u32, + _pad0: u32, + noise_scale: f32, + noise_magnitude: f32, + _pad1: f32, + _pad2: f32, +} + +struct GpuComputeContext { + device: Gd, + tilemap_shader: Rid, + tilemap_pipeline: Rid, + noise_shader: Rid, + noise_pipeline: Rid, +} + +impl GpuComputeContext { + fn new() -> Result { + let mut device = match RenderingServer::singleton().create_local_rendering_device() { + Some(device) => device, + None => RenderingServer::singleton() + .get_rendering_device() + .ok_or_else(|| "Unable to acquire RenderingDevice".to_string())?, + }; + + let (tilemap_shader, tilemap_pipeline) = Self::create_pipeline(&mut device, TILEMAP_SHADER)?; + let (noise_shader, noise_pipeline) = Self::create_pipeline(&mut device, NOISE_SHADER)?; + + godot_print!("Initialized GPU compute context for tilemap + noise"); + + Ok(Self { + device, + tilemap_shader, + tilemap_pipeline, + noise_shader, + noise_pipeline, + }) + } + + fn create_pipeline(device: &mut Gd, spirv: &[u8]) -> Result<(Rid, Rid), String> { + if !spirv.len().is_multiple_of(4) { + return Err("SPIR-V blob size is not a multiple of 4".to_string()); + } + + let shader_bytes = PackedByteArray::from(spirv.to_vec()); + let mut shader_spirv = RdShaderSpirv::new_gd(); + shader_spirv.set_stage_bytecode(ShaderStage::COMPUTE, &shader_bytes); + + let shader_rid = device.shader_create_from_spirv(&shader_spirv); + if !shader_rid.is_valid() { + return Err("Failed to create compute shader".to_string()); + } + + let pipeline_rid = device.compute_pipeline_create(shader_rid); + if !pipeline_rid.is_valid() { + device.free_rid(shader_rid); + return Err("Failed to create compute pipeline".to_string()); + } + + Ok((shader_rid, pipeline_rid)) + } + + fn run_tilemap_compute( + &mut self, + params: &TilemapGpuParams, + map_data: &[u32], + atlas_data: &[u8], + ) -> Result { + godot_print!( + "run_tilemap_compute: output {}x{} px, tile_size {}, map {}x{} tiles, atlas {}x{} px", + params.out_width, + params.out_height, + params.tile_size, + params.map_width, + params.map_height, + params.atlas_width, + params.atlas_height + ); + + if params.tile_size == 0 { + return Err("Tile size cannot be zero".to_string()); + } + + if params.map_width == 0 || params.map_height == 0 { + return Err("Map dimensions cannot be zero".to_string()); + } + + if params.atlas_width == 0 || params.atlas_height == 0 { + return Err("Atlas dimensions cannot be zero".to_string()); + } + + let expected_map_entries = (params.map_width as usize) + .checked_mul(params.map_height as usize) + .ok_or_else(|| "Map size overflow".to_string())?; + + if map_data.len() != expected_map_entries { + return Err(format!( + "Map buffer length mismatch. Expected {}, got {}", + expected_map_entries, + map_data.len() + )); + } + + let expected_atlas_bytes = (params.atlas_width as usize) + .checked_mul(params.atlas_height as usize) + .and_then(|v| v.checked_mul(4)) + .ok_or_else(|| "Atlas byte size overflow".to_string())?; + + if atlas_data.len() != expected_atlas_bytes { + return Err(format!( + "Atlas buffer length mismatch. Expected {}, got {}", + expected_atlas_bytes, + atlas_data.len() + )); + } + + if !atlas_data.len().is_multiple_of(4) { + return Err("Atlas buffer length must be a multiple of 4".to_string()); + } + + let output_size = (params.out_width as usize) + .checked_mul(params.out_height as usize) + .and_then(|v| v.checked_mul(4)) + .ok_or_else(|| "Output texture is too large".to_string())?; + + if output_size == 0 { + return Err("Output texture is empty".to_string()); + } + + let mut device = self.device.clone(); + godot_print!("Using cached RenderingDevice for compute dispatch"); + + let mut allocated: Vec = Vec::new(); + + let result = (|| -> Result { + let setup_start = Instant::now(); + + let params_raw = bytes_of(params); + let params_size = + u32::try_from(params_raw.len()).map_err(|_| "Parameter buffer exceeds supported size".to_string())?; + let params_bytes = PackedByteArray::from(params_raw.to_vec()); + let params_buffer = device + .storage_buffer_create_ex(params_size) + .data(¶ms_bytes) + .creation_bits(BufferCreationBits::AS_STORAGE_BIT) + .done(); + if !params_buffer.is_valid() { + return Err("Failed to allocate parameter buffer".to_string()); + } + allocated.push(params_buffer); + + let map_raw: &[u8] = cast_slice(map_data); + let map_size = u32::try_from(map_raw.len()).map_err(|_| "Map buffer exceeds supported size".to_string())?; + let map_bytes = PackedByteArray::from(map_raw.to_vec()); + let map_buffer = device + .storage_buffer_create_ex(map_size) + .data(&map_bytes) + .creation_bits(BufferCreationBits::AS_STORAGE_BIT) + .done(); + if !map_buffer.is_valid() { + return Err("Failed to allocate map buffer".to_string()); + } + allocated.push(map_buffer); + + let atlas_size = + u32::try_from(atlas_data.len()).map_err(|_| "Atlas buffer exceeds supported size".to_string())?; + let atlas_bytes = PackedByteArray::from(atlas_data.to_vec()); + let atlas_buffer = device + .storage_buffer_create_ex(atlas_size) + .data(&atlas_bytes) + .creation_bits(BufferCreationBits::AS_STORAGE_BIT) + .done(); + if !atlas_buffer.is_valid() { + return Err("Failed to allocate atlas buffer".to_string()); + } + allocated.push(atlas_buffer); + + let output_size_u32 = + u32::try_from(output_size).map_err(|_| "Output buffer exceeds supported size".to_string())?; + let output_init = PackedByteArray::from(vec![0u8; output_size]); + let output_buffer = device + .storage_buffer_create_ex(output_size_u32) + .data(&output_init) + .creation_bits(BufferCreationBits::AS_STORAGE_BIT) + .done(); + if !output_buffer.is_valid() { + return Err("Failed to allocate output buffer".to_string()); + } + allocated.push(output_buffer); + + let mut uniform_nodes: Vec> = Vec::new(); + for (binding, rid) in [ + (0_i32, params_buffer), + (1_i32, map_buffer), + (2_i32, atlas_buffer), + (3_i32, output_buffer), + ] { + let mut uniform = RdUniform::new_gd(); + uniform.set_uniform_type(UniformType::STORAGE_BUFFER); + uniform.set_binding(binding); + uniform.add_id(rid); + uniform_nodes.push(uniform); + } + + let mut uniforms: Array> = Array::new(); + for uniform in &uniform_nodes { + uniforms.push(uniform); + } + + let uniform_set = device.uniform_set_create(&uniforms, self.tilemap_shader, 0); + if !uniform_set.is_valid() { + return Err("Failed to create uniform set".to_string()); + } + allocated.push(uniform_set); + + let setup_ms = setup_start.elapsed().as_secs_f64() * 1000.0; + godot_print!("GPU pipeline + buffer setup finished in {:.2} ms", setup_ms); + + let compute_list = device.compute_list_begin(); + if compute_list < 0 { + return Err("Failed to begin compute list".to_string()); + } + + device.compute_list_bind_compute_pipeline(compute_list, self.tilemap_pipeline); + device.compute_list_bind_uniform_set(compute_list, uniform_set, 0); + + let groups_x = params.out_width.saturating_add(7) / 8; + let groups_y = params.out_height.saturating_add(7) / 8; + let dispatch_x = groups_x.max(1); + let dispatch_y = groups_y.max(1); + + device.compute_list_dispatch(compute_list, dispatch_x, dispatch_y, 1); + device.compute_list_end(); + godot_print!( + "Dispatched compute shader with workgroups {}x{} (covering {}x{} px)", + dispatch_x, + dispatch_y, + params.out_width, + params.out_height + ); + + let dispatch_start = Instant::now(); + device.submit(); + device.sync(); + let dispatch_ms = dispatch_start.elapsed().as_secs_f64() * 1000.0; + godot_print!("GPU dispatch + sync finished in {:.2} ms", dispatch_ms); + + let readback_start = Instant::now(); + let output_data = device.buffer_get_data(output_buffer); + let readback_ms = readback_start.elapsed().as_secs_f64() * 1000.0; + godot_print!("GPU readback finished in {:.2} ms", readback_ms); + godot_print!("Compute shader completed; output contains {} bytes", output_data.len()); + + Ok(output_data) + })(); + + for rid in allocated.into_iter().rev() { + if rid.is_valid() { + device.free_rid(rid); + } + } + + result + } + + fn generate_noise(&mut self, params: &NoiseGpuParams) -> Result, String> { + if params.map_width == 0 || params.map_height == 0 { + return Err("Noise map dimensions cannot be zero".to_string()); + } + + let tile_count = (params.map_width as usize) + .checked_mul(params.map_height as usize) + .ok_or_else(|| "Noise tile count overflow".to_string())?; + + let output_size_bytes = tile_count + .checked_mul(std::mem::size_of::()) + .ok_or_else(|| "Noise output exceeds supported size".to_string())?; + + if output_size_bytes == 0 { + return Err("Noise output buffer is empty".to_string()); + } + + let mut device = self.device.clone(); + let mut allocated: Vec = Vec::new(); + + let result = (|| -> Result, String> { + let params_raw = bytes_of(params); + let params_size = + u32::try_from(params_raw.len()).map_err(|_| "Noise parameter buffer exceeds supported size".to_string())?; + let params_bytes = PackedByteArray::from(params_raw.to_vec()); + let params_buffer = device + .storage_buffer_create_ex(params_size) + .data(¶ms_bytes) + .creation_bits(BufferCreationBits::AS_STORAGE_BIT) + .done(); + if !params_buffer.is_valid() { + return Err("Failed to allocate noise parameter buffer".to_string()); + } + allocated.push(params_buffer); + + let output_size_u32 = + u32::try_from(output_size_bytes).map_err(|_| "Noise output buffer exceeds supported size".to_string())?; + let output_init = PackedByteArray::from(vec![0u8; output_size_bytes]); + let output_buffer = device + .storage_buffer_create_ex(output_size_u32) + .data(&output_init) + .creation_bits(BufferCreationBits::AS_STORAGE_BIT) + .done(); + if !output_buffer.is_valid() { + return Err("Failed to allocate noise output buffer".to_string()); + } + allocated.push(output_buffer); + + let mut uniform_nodes: Vec> = Vec::new(); + for (binding, rid) in [(0_i32, params_buffer), (1_i32, output_buffer)] { + let mut uniform = RdUniform::new_gd(); + uniform.set_uniform_type(UniformType::STORAGE_BUFFER); + uniform.set_binding(binding); + uniform.add_id(rid); + uniform_nodes.push(uniform); + } + + let mut uniforms: Array> = Array::new(); + for uniform in &uniform_nodes { + uniforms.push(uniform); + } + + let uniform_set = device.uniform_set_create(&uniforms, self.noise_shader, 0); + if !uniform_set.is_valid() { + return Err("Failed to create noise uniform set".to_string()); + } + allocated.push(uniform_set); + + let compute_list = device.compute_list_begin(); + if compute_list < 0 { + return Err("Failed to begin noise compute list".to_string()); + } + + device.compute_list_bind_compute_pipeline(compute_list, self.noise_pipeline); + device.compute_list_bind_uniform_set(compute_list, uniform_set, 0); + + let groups_x = params.map_width.saturating_add(15) / 16; + let groups_y = params.map_height.saturating_add(15) / 16; + let dispatch_x = groups_x.max(1); + let dispatch_y = groups_y.max(1); + + device.compute_list_dispatch(compute_list, dispatch_x, dispatch_y, 1); + device.compute_list_end(); + + device.submit(); + device.sync(); + + let output_bytes = device.buffer_get_data(output_buffer); + if !output_bytes.len().is_multiple_of(4) { + return Err("Noise output byte count is not a multiple of 4".to_string()); + } + + let raw = output_bytes.to_vec(); + let values: &[u32] = cast_slice(&raw); + Ok(values.to_vec()) + })(); + + for rid in allocated.into_iter().rev() { + if rid.is_valid() { + device.free_rid(rid); + } + } + + result + } +} + +impl Drop for GpuComputeContext { + fn drop(&mut self) { + let mut device = self.device.clone(); + if self.tilemap_pipeline.is_valid() { + device.free_rid(self.tilemap_pipeline); + } + if self.tilemap_shader.is_valid() { + device.free_rid(self.tilemap_shader); + } + if self.noise_pipeline.is_valid() { + device.free_rid(self.noise_pipeline); + } + if self.noise_shader.is_valid() { + device.free_rid(self.noise_shader); + } + } +} + +#[cfg(feature = "gd_rehearse_tests")] +mod gd_rehearse_tests { + use super::*; + use gd_rehearse::itest::*; + use std::time::Instant; + + pub fn make_test_atlas() -> (Vec, u32, u32) { + let tile_size = 2u32; + let atlas_w = tile_size * 2; // two tiles horizontally + let atlas_h = tile_size; // one row + + // Build atlas row-major across atlas_w + // Tile 0 = solid red, Tile 1 = solid green + let mut data = Vec::with_capacity((atlas_w * atlas_h * 4) as usize); + for _y in 0..atlas_h { + for x in 0..atlas_w { + if x < tile_size { + data.extend_from_slice(&[255u8, 0, 0, 255]); + } else { + data.extend_from_slice(&[0u8, 255, 0, 255]); + } + } + } + + (data, atlas_w, atlas_h) + } + + fn make_uniform_atlas(tile_size: u32, color: [u8; 4]) -> (Vec, u32, u32) { + let pixel_count = (tile_size * tile_size) as usize; + let mut data = Vec::with_capacity(pixel_count * 4); + for _ in 0..pixel_count { + data.extend_from_slice(&color); + } + + (data, tile_size, tile_size) + } + + fn run_tilemap_for_size(map_width: u32, map_height: u32, tile_size: u32) -> PackedByteArray { + godot_print!( + "Testing map {}x{} tiles at tile_size {} ({}x{} px output)", + map_width, + map_height, + tile_size, + map_width * tile_size, + map_height * tile_size + ); + + let (atlas_bytes, atlas_w, atlas_h) = make_uniform_atlas(tile_size, [0u8, 0u8, 255u8, 255u8]); + + let params = TilemapGpuParams { + out_width: map_width * tile_size, + out_height: map_height * tile_size, + tile_size, + map_width, + map_height, + atlas_width: atlas_w, + atlas_height: atlas_h, + }; + + let tile_count = (map_width as usize) + .checked_mul(map_height as usize) + .expect("Tile count overflow in benchmark"); + let map = vec![0u32; tile_count]; + let start = Instant::now(); + let mut context = GpuComputeContext::new().expect("Failed to create GPU context for benchmark"); + let result = context + .run_tilemap_compute(¶ms, &map, &atlas_bytes) + .expect("GPU tilemap compute failed during size sweep benchmark"); + let elapsed_ms = start.elapsed().as_secs_f64() * 1000.0; + godot_print!( + "Tilemap GPU compute finished in {:.2} ms for {} tiles ({} bytes output)", + elapsed_ms, + tile_count, + result.len() + ); + result + } + + fn expected_output_bytes(map_width: u32, map_height: u32, tile_size: u32) -> usize { + let out_width = map_width + .checked_mul(tile_size) + .expect("Output width overflow in expectation"); + let out_height = map_height + .checked_mul(tile_size) + .expect("Output height overflow in expectation"); + + (out_width as usize) + .checked_mul(out_height as usize) + .and_then(|v| v.checked_mul(4)) + .expect("Expected byte count overflow") + } + + #[gditest(scene_path = "res://tests/test_runner.tscn")] + fn gpu_tilemap_produces_expected_pixels() { + let (atlas_bytes, atlas_w, atlas_h) = make_test_atlas(); + + let params = TilemapGpuParams { + out_width: 4, + out_height: 2, + tile_size: 2, + map_width: 2, + map_height: 1, + atlas_width: atlas_w, + atlas_height: atlas_h, + }; + + let map = vec![0u32, 1u32]; + let start = Instant::now(); + let mut context = GpuComputeContext::new().expect("Failed to create GPU context for sanity check"); + let gpu_bytes = context + .run_tilemap_compute(¶ms, &map, &atlas_bytes) + .expect("GPU tilemap compute failed") + .to_vec(); + let elapsed_ms = start.elapsed().as_secs_f64() * 1000.0; + godot_print!("Sanity GPU tilemap test finished in {:.2} ms", elapsed_ms); + + assert_eq!(gpu_bytes.len(), atlas_bytes.len(), "GPU output size mismatch"); + assert_eq!( + gpu_bytes, atlas_bytes, + "GPU tilemap output differs from atlas expectation" + ); + } + + #[gditest(scene_path = "res://tests/test_runner.tscn")] + fn gpu_noise_generation_dimensions() { + let mut context = GpuComputeContext::new().expect("Failed to create GPU context for noise test"); + let params = NoiseGpuParams { + map_width: 64, + map_height: 32, + seed: 1, + _pad0: 0, + noise_scale: 0.75, + noise_magnitude: 12.0, + _pad1: 0.0, + _pad2: 0.0, + }; + + let values = context.generate_noise(¶ms).expect("GPU noise generation failed"); + let expected = (params.map_width as usize) + .checked_mul(params.map_height as usize) + .expect("Noise test tile count overflow"); + assert_eq!(values.len(), expected, "Noise GPU output length mismatch"); + let max_allowed = params.noise_magnitude.ceil() as u32; + assert!( + values.iter().all(|&value| value <= max_allowed), + "Noise GPU output exceeded magnitude limit" + ); + } + + #[gditest(scene_path = "res://tests/test_runner.tscn")] + fn gpu_tilemap_generation_small() { + let output = run_tilemap_for_size(128, 128, TILE_SIZE); + let expected = expected_output_bytes(128, 128, TILE_SIZE); + assert_eq!(output.len(), expected, "Small tilemap output byte size mismatch"); + godot_print!("Small tilemap test validated {} bytes", output.len()); + } + + #[gditest(scene_path = "res://tests/test_runner.tscn")] + fn gpu_tilemap_generation_medium() { + let output = run_tilemap_for_size(256, 256, TILE_SIZE); + let expected = expected_output_bytes(256, 256, TILE_SIZE); + assert_eq!(output.len(), expected, "Medium tilemap output byte size mismatch"); + godot_print!("Medium tilemap test validated {} bytes", output.len()); + } + + #[gditest(scene_path = "res://tests/test_runner.tscn")] + fn gpu_tilemap_generation_large() { + let output = run_tilemap_for_size(512, 512, TILE_SIZE); + let expected = expected_output_bytes(512, 512, TILE_SIZE); + assert_eq!(output.len(), expected, "Large tilemap output byte size mismatch"); + godot_print!("Large tilemap test validated {} bytes", output.len()); + } + + #[gditest(scene_path = "res://tests/test_runner.tscn")] + fn gpu_tilemap_generation_xlarge() { + let output = run_tilemap_for_size(1024, 1024, TILE_SIZE); + let expected = expected_output_bytes(1024, 1024, TILE_SIZE); + assert_eq!(output.len(), expected, "XL tilemap output byte size mismatch"); + godot_print!("XL tilemap test validated {} bytes", output.len()); + } +} diff --git a/rust/src/player.rs b/rust/src/player.rs new file mode 100644 index 0000000..8d7dc75 --- /dev/null +++ b/rust/src/player.rs @@ -0,0 +1,55 @@ +use godot::{classes::Input, global::Key, prelude::*}; + +#[derive(GodotClass)] +#[class(base=Node3D)] +struct Player { + #[export] + character_name: GString, + #[export] + velocity: Vector3, + #[export] + acceleration: Vector3, + base: Base, +} + +#[godot_api] +impl INode3D for Player { + fn init(base: Base) -> Self { + Self { + character_name: GString::from("Hello"), + velocity: Vector3::ZERO, + acceleration: Vector3::new(1.0, 1.0, 0.0), + base, + } + } + + fn process(&mut self, delta: f32) { + self.process_input(delta); + self.update_position(delta); + } +} + +impl Player { + fn process_input(&mut self, _delta: f32) { + let input = Input::singleton(); + if input.is_key_pressed(Key::W) { + self.velocity.y += self.acceleration.y; + } + if input.is_key_pressed(Key::A) { + self.velocity.x -= self.acceleration.x; + } + if input.is_key_pressed(Key::S) { + self.velocity.y -= self.acceleration.y; + } + if input.is_key_pressed(Key::D) { + self.velocity.x += self.acceleration.x; + } + } + + fn update_position(&mut self, delta: f32) { + let before_move = self.base_mut().get_transform(); + let after_move = before_move.translated(self.velocity * delta); + self.base_mut().set_transform(after_move); + self.velocity *= 0.5; + } +}