├── .gitignore ├── Screenshot1.PNG ├── LICENSE ├── Console.tscn ├── README.md └── Console.gd /.gitignore: -------------------------------------------------------------------------------- 1 | *.import 2 | -------------------------------------------------------------------------------- /Screenshot1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rootKot/godot4-dev-console/HEAD/Screenshot1.PNG -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Aram Petrosyan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Console.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=3 uid="uid://dmj78c4r6bd8"] 2 | 3 | [ext_resource type="Script" path="res://godot4-dev-console/Console.gd" id="1_k87r0"] 4 | 5 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_5tn8s"] 6 | content_margin_left = 4.0 7 | content_margin_top = 4.0 8 | content_margin_right = 4.0 9 | content_margin_bottom = 4.0 10 | bg_color = Color(0, 0, 0, 0.470588) 11 | corner_radius_bottom_right = 4 12 | corner_radius_bottom_left = 4 13 | 14 | [node name="Console" type="CanvasLayer"] 15 | layer = 128 16 | script = ExtResource("1_k87r0") 17 | 18 | [node name="Container" type="PanelContainer" parent="."] 19 | offset_right = 525.0 20 | offset_bottom = 295.0 21 | theme_override_styles/panel = SubResource("StyleBoxFlat_5tn8s") 22 | 23 | [node name="VBoxContainer" type="VBoxContainer" parent="Container"] 24 | layout_mode = 2 25 | 26 | [node name="ConsoleRt" type="RichTextLabel" parent="Container/VBoxContainer"] 27 | custom_minimum_size = Vector2(400, 250) 28 | layout_mode = 2 29 | focus_mode = 2 30 | theme_override_font_sizes/normal_font_size = 12 31 | bbcode_enabled = true 32 | text = " = Console = 33 | " 34 | scroll_following = true 35 | selection_enabled = true 36 | 37 | [node name="HSeparator" type="HSeparator" parent="Container/VBoxContainer"] 38 | layout_mode = 2 39 | 40 | [node name="Cmd" type="LineEdit" parent="Container/VBoxContainer"] 41 | layout_mode = 2 42 | theme_override_font_sizes/font_size = 12 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dev Console for Godot 4.2.x 2 | 3 | Hey there! Check out this handy in-game dev console I made for Godot. It's super easy to set up and perfect for debugging multiplayer games. 4 | 5 | You know how the built-in console kinda jumbles everything together? Well, mine separates the console outputs for each instance, making multiplayer debugging way easier. 6 | 7 | Give it a try and see how much smoother your development process can be! 8 | 9 | ![Screenshot1](Screenshot1.PNG) 10 | 11 | 12 | ## Features 13 | 14 | - Simple setup and usage 15 | - Print anything in console using Console.print() 16 | - Define custom commands for your game 17 | - Navigate previous commands with ease using the arrow keys 18 | - Toggle the console with the press of the `~` key 19 | 20 | ## Installation 21 | 22 | * Add the repo as a submodule anywhere in your project 23 | 24 | ```bash 25 | git submodule add git@github.com:rootKot/godot4-dev-console.git 26 | ``` 27 | Now you will have `Console.tscn` in that `godot4-dev-console` folder 28 | * Drag and drop the `Console.tscn` inside your scene node. 29 | From the inspector you can set is the console should be visible by default when runing the project 30 | 31 | ## Usage 32 | 33 | * Use `~` key to open/close the console (It is actually ` key) 34 | * Type `help` and press Enter, to see available commands 35 | * For printing something in the console use Console.print() instead of print() 36 | ```gdscript 37 | Console.print('Hello world') 38 | Console.print('This is my variable', my_variable) 39 | Console.print('I', 'can', 'pass', 'up', 'to', 12, 'params') 40 | ``` 41 | 42 | ## Add custom commands 43 | ```gdscript 44 | Console.add_command( 45 | command_name: String, 46 | function: Callable, 47 | function_arguments_if_needed: Array[String], 48 | description_to_show_in_help: String 49 | ) 50 | ``` 51 | ### Examples 52 | ```gdscript 53 | Console.add_command( 54 | 'set_player_pos', 55 | _set_player_pos, 56 | ['float', 'float'], 57 | 'Set player pos. Ex. set_player_pos 100 50' 58 | ) 59 | func _set_player_pos(x: float, y: float): 60 | position = Vector2(x, y) 61 | ``` 62 | ```gdscript 63 | Console.add_command( 64 | 'is_player_can_move', 65 | func(val: bool): _is_player_can_move = val, 66 | ['bool'], 67 | 'set if player can move. Ex. is_player_can_move false' 68 | ) 69 | ``` 70 | ### Remove command 71 | ```gdscript 72 | Console.remove_command('is_player_can_move') 73 | ``` 74 | 75 | ## Future plans 76 | * Implement Autocomplete functionality 77 | * Add checkbox to select if the console should be available in release build 78 | 79 | ## License 80 | ### MIT License 81 | Copyright © 2024 rootKot 82 | -------------------------------------------------------------------------------- /Console.gd: -------------------------------------------------------------------------------- 1 | extends CanvasLayer 2 | 3 | class_name Console 4 | 5 | @export var is_console_visible: bool = true 6 | 7 | static var consoleRt: RichTextLabel 8 | var cmd_input: LineEdit 9 | 10 | static var _commands: Dictionary 11 | 12 | var _command_history: Array[String] = [] 13 | var _command_from_history_index = -1 14 | 15 | func _ready(): 16 | consoleRt = get_node('Container/VBoxContainer/ConsoleRt') 17 | cmd_input = get_node('Container/VBoxContainer/Cmd') 18 | show() if is_console_visible else hide() 19 | _create_toggle_key() 20 | 21 | _commands = { 22 | 'help': { 23 | 'description': 'Show all the commands', 24 | 'exec': _help, 25 | 'param_types': [] 26 | }, 27 | 'clear': { 28 | 'description': 'Clear the console', 29 | 'exec': _clear, 30 | 'param_types': [] 31 | } 32 | } 33 | 34 | func _create_toggle_key(): 35 | var input_event = InputEventKey.new() 36 | input_event.set_keycode(KEY_QUOTELEFT) 37 | InputMap.add_action('toggle_console') 38 | InputMap.action_add_event('toggle_console', input_event) 39 | 40 | func _process(delta): 41 | if Input.is_action_just_pressed('toggle_console'): 42 | if visible: 43 | hide() 44 | else: 45 | show() 46 | cmd_input.set_text('') 47 | cmd_input.grab_focus.call_deferred() 48 | 49 | 50 | if cmd_input.has_focus(): 51 | if Input.is_action_just_pressed('ui_text_completion_accept'): 52 | _exec() 53 | elif Input.is_action_just_pressed('ui_up'): 54 | _get_command_from_history(1) 55 | elif Input.is_action_just_pressed('ui_down'): 56 | _get_command_from_history(-1) 57 | 58 | static func add_command(_name: String, exec: Callable, param_types: Array[String]=[], description: String = ''): 59 | _commands[_name] = { 60 | 'description': description, 61 | 'exec': exec, 62 | 'param_types': param_types 63 | } 64 | 65 | static func remove_command(_name: String): 66 | _commands.erase(_name) 67 | 68 | static func print( 69 | arg0 = null, arg1 = null, arg2 = null, arg3 = null, 70 | arg4 = null, arg5 = null, arg6 = null, arg7 = null, 71 | arg8 = null, arg9 = null, arg10 = null, arg11 = null 72 | ): 73 | var args = [arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11] 74 | var _text:String = '\n' 75 | for arg in args: 76 | if arg == null: 77 | break 78 | _text += str(arg) + ' ' 79 | consoleRt.append_text(_text) 80 | 81 | func _exec(): 82 | var command: String = cmd_input.get_text() 83 | cmd_input.set_text('') 84 | _command_from_history_index = -1 85 | 86 | var cmdArr: PackedStringArray = command.split(' ') 87 | 88 | if cmdArr.size() and _commands.has(cmdArr[0]): 89 | var cmdParams = [] 90 | for param_i in range(1, cmdArr.size()): 91 | # param is string by default 92 | var param = cmdArr[param_i] 93 | if _commands[cmdArr[0]].param_types.size() > 0: 94 | match _commands[cmdArr[0]].param_types[param_i - 1]: 95 | 'int': 96 | param = int(cmdArr[param_i]) 97 | 'float': 98 | param = float(cmdArr[param_i]) 99 | 'bool': 100 | param = true if ['1', 'true', 'TRUE', 'True'].has(cmdArr[param_i]) else false 101 | cmdParams.append(param) 102 | 103 | Console.print('>', command) 104 | (_commands[cmdArr[0]].exec as Callable).callv(cmdParams) 105 | 106 | elif cmdArr[0] != '': 107 | Console.print('>', command, '[color=#d15d5d]', 'command not found.', '[/color]') 108 | 109 | if command != '' and (_command_history.size() == 0 or command != _command_history[0]): 110 | _command_history.push_front(command) 111 | 112 | func _get_command_from_history(direction: int): 113 | var history_size: int = _command_history.size() 114 | if _command_from_history_index >= -1 and _command_from_history_index < history_size: 115 | _command_from_history_index = clampi(_command_from_history_index + direction, -1, history_size - 1) 116 | if _command_from_history_index == -1: 117 | cmd_input.set_text('') 118 | else: 119 | cmd_input.set_text(_command_history[_command_from_history_index]) 120 | 121 | 122 | func _help(): 123 | Console.print('---------------------') 124 | for command in _commands: 125 | var params = '' 126 | for param: String in _commands[command].param_types as Array[String]: 127 | params += '['+param+'] ' 128 | Console.print('[color=#62b769]', command, params, '[/color]', '-', _commands[command].description) 129 | Console.print('---------------------') 130 | 131 | func _clear(): 132 | consoleRt.clear() 133 | --------------------------------------------------------------------------------