-
Notifications
You must be signed in to change notification settings - Fork 47
Rework variable tracker module #153
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
160 changes: 117 additions & 43 deletions
160
addons/panku_console/modules/variable_tracker/module.gd
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,54 +1,128 @@ | ||
| 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]" | ||
|
|
||
| # The current scene root node, which will be updated automatically when the scene changes. | ||
| # current scene node was determined by node tree index at the beginning. | ||
| var _current_scene_root:Node | ||
| var _current_scene_index := 0 | ||
| var _user_singleton_files := [] | ||
| var _tween_loop:Tween | ||
| var _loop_call_back:CallbackTweener | ||
|
|
||
|
|
||
| func init_module(): | ||
| _current_scene_index = core.get_tree().root.get_child_count() - 1 | ||
| await core.get_tree().process_frame | ||
| setup_scene_root_tracker() | ||
| setup_autoload_tracker() | ||
| print_to_interactive_shell_window() | ||
|
|
||
| # always register the current scene root as `current` | ||
| func setup_scene_root_tracker(): | ||
| _current_scene_root = get_scene_root() | ||
| core.gd_exprenv.register_env("current", _current_scene_root) | ||
| get_module_opt().tracking_delay = load_module_data("tracking_delay", DEFAULT_TRACKING_DELAY) | ||
| await core.get_tree().process_frame # not sure if it is necessary | ||
|
|
||
| _update_project_singleton_files() | ||
| _setup_scene_root_tracker() | ||
| _check_autoloads() | ||
|
|
||
|
|
||
| # 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() | ||
| _tween_loop.set_loops().tween_callback( | ||
| func(): | ||
| var r = get_scene_root() | ||
| if r != _current_scene_root: | ||
| _current_scene_root = r | ||
| core.gd_exprenv.register_env("current", _current_scene_root) | ||
| ).set_delay(0.1) | ||
| _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]) | ||
|
|
||
| func get_scene_root() -> Node: | ||
| var r := core.get_tree().root | ||
| if r.get_child_count() > _current_scene_index: | ||
| return r.get_child(_current_scene_index) | ||
| else: | ||
| return null | ||
|
|
||
| func setup_autoload_tracker(): | ||
| # read root children, the last child is considered as scene node while others are autoloads. | ||
| var root:Node = core.get_tree().root | ||
| for i in range(root.get_child_count() - 1): | ||
| if root.get_child(i).name == core.SingletonName: | ||
| # skip the plugin singleton | ||
| 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 core.get_tree().root.get_children(): | ||
| if not _is_singleton(node): | ||
| return node | ||
|
|
||
| return null | ||
|
|
||
|
|
||
| # Find all autoload singletons and bind its to environment vars. | ||
| func _check_autoloads() -> void: | ||
| var _user_singleton_names := [] | ||
|
|
||
| for node in core.get_tree().root.get_children(): | ||
| if node.name == core.SingletonName: | ||
| # skip panku plugin itself | ||
| continue | ||
| # register user singletons | ||
| var user_singleton:Node = root.get_child(i) | ||
| core.gd_exprenv.register_env(user_singleton.name, user_singleton) | ||
|
|
||
| func print_to_interactive_shell_window(): | ||
| # print a tip to interacvite_shell module | ||
| # modules load order matters | ||
| var tip:String = "\n[tip] you can always access current scene by [b]current[/b]" | ||
| if core.module_manager.has_module("interactive_shell"): | ||
| var ishell = core.module_manager.get_module("interactive_shell") | ||
| ishell.interactive_shell.output(tip) | ||
|
|
||
| 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) | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. print something to dev console should be improved later in 1.9.0 to avoid unnecessary setup. |
||
|
|
||
| func quit_module(): | ||
| _tween_loop.kill() | ||
| super.quit_module() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| extends ModuleOptions | ||
|
|
||
| @export_group("variable_tracker") | ||
|
|
||
|
|
||
| @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) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, there's actually no elegant way to get a list of running autoload singletons...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, I just can't find anything better so far.