Last active
August 29, 2022 19:12
-
-
Save cenullum/0f0d98f595f4dea04301bd6a771eedac to your computer and use it in GitHub Desktop.
To make console commands and show stats in Godot Engine projects
This file contains 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
extends Node | |
#You need to set "console" and "stats" keys to input map | |
#The video about how to implement to your project https://youtu.be/klaxiaQ94Zc | |
#UI | |
var canvaslayer | |
var color_rect#black background | |
var debug_output | |
var debug_tween | |
var left_label | |
var right_label | |
var debug_input | |
#To add new stat Debug.add_stat("Informatife name: ",self,"exact_variable_name",false) | |
var left_stats = [] | |
var right_stats = [] | |
#You can set a font if you want | |
onready var regular_font = load("res://regular_font.tres") | |
var show_parametre_type=false | |
var commands | |
var command_history =[] | |
var command_history_line=0 | |
var v_box_container | |
var buttons_scroll_container | |
var command_suggestions =[] | |
var command_suggestions_line=0 | |
enum { | |
ARG_INT, | |
ARG_STRING, | |
ARG_BOOL, | |
ARG_FLOAT | |
} | |
var valid_commands = [[self,"clear_output",[] ],[self,"clear_history",[]]] | |
#to add new command Debug.add_command(self,"func_name") | |
#or if func have parametre Debug.add_command(self,"func_name",[Debug.ARG_INT]) | |
enum {DEFAULT,SUGGESTION_MODE,HISTORY_MODE,} | |
var console_mode=DEFAULT | |
var last_manually_changed_input_text="" | |
func _ready(): | |
debug_tween= Tween.new() | |
add_child(debug_tween) | |
create_ui() | |
func create_ui(): | |
canvaslayer=CanvasLayer.new() | |
canvaslayer.layer=99 | |
add_child(canvaslayer) | |
color_rect=ColorRect.new() | |
color_rect.color=Color(0.160784, 0.160784, 0.160784, 0.466667) | |
canvaslayer.add_child(color_rect) | |
color_rect.anchor_bottom=1 | |
color_rect.anchor_right=1 | |
color_rect.anchor_top=0 | |
color_rect.anchor_left=0 | |
color_rect.margin_bottom=0 | |
color_rect.margin_left=0 | |
color_rect.margin_right=0 | |
color_rect.margin_top=0 | |
color_rect.visible=false | |
left_label=Label.new() | |
left_label.anchor_bottom=1 | |
left_label.anchor_right=1 | |
left_label.anchor_top=0 | |
left_label.anchor_left=0 | |
left_label.margin_bottom=0 | |
left_label.margin_left=0 | |
left_label.margin_right=0 | |
left_label.margin_top=0 | |
if regular_font!=null: | |
left_label.set("custom_fonts/font",regular_font) | |
canvaslayer.add_child(left_label) | |
left_label.visible=false | |
right_label=Label.new() | |
right_label.anchor_bottom=1 | |
right_label.anchor_right=1 | |
right_label.anchor_top=0 | |
right_label.anchor_left=0 | |
right_label.margin_bottom=0 | |
right_label.margin_left=0 | |
right_label.margin_right=0 | |
right_label.margin_top=0 | |
if regular_font!=null: | |
right_label.set("custom_fonts/font",regular_font) | |
canvaslayer.add_child(right_label) | |
right_label.align=right_label.ALIGN_RIGHT | |
right_label.visible=false | |
debug_output=RichTextLabel.new() | |
debug_output.selection_enabled=true | |
if regular_font!=null: | |
debug_output.set("custom_fonts/normal_font",regular_font) | |
debug_output.anchor_bottom=1 | |
debug_output.anchor_right=1 | |
debug_output.anchor_top=0 | |
debug_output.anchor_left=0 | |
debug_output.margin_bottom=-32 | |
debug_output.margin_left=0 | |
debug_output.margin_right=0 | |
debug_output.margin_top=0 | |
canvaslayer.add_child(debug_output) | |
debug_output.visible=false | |
debug_output.scroll_following=true; | |
debug_input= LineEdit.new() | |
debug_input.connect("text_changed",self,"debug_input_changed") | |
debug_input.connect("text_entered",self,"debug_input_entered") | |
var screen_height= get_viewport().get_visible_rect().size.y | |
debug_input.anchor_bottom=0#burdaki 16 input uzunluğu bundan sonra output başlıyor | |
debug_input.anchor_right=1 | |
debug_input.anchor_top=(screen_height-32)/screen_height | |
debug_input.anchor_left=0 | |
debug_input.margin_bottom=0 | |
debug_input.margin_left=0 | |
debug_input.margin_right=0 | |
debug_input.margin_top=0 | |
debug_input.visible=false | |
debug_input.caret_blink=true | |
debug_input.focus_mode=Control.FOCUS_CLICK | |
if regular_font!=null: | |
debug_input.set("custom_fonts/font",regular_font) | |
canvaslayer.add_child(debug_input) | |
#suggestion panel | |
buttons_scroll_container=ScrollContainer.new() | |
buttons_scroll_container.scroll_horizontal_enabled=false | |
buttons_scroll_container.follow_focus=true | |
buttons_scroll_container.anchor_bottom=1 | |
buttons_scroll_container.anchor_right=1 | |
buttons_scroll_container.anchor_top=0 | |
buttons_scroll_container.anchor_left=0 | |
buttons_scroll_container.margin_bottom=-32 | |
buttons_scroll_container.margin_left=0 | |
buttons_scroll_container.margin_right=0 | |
buttons_scroll_container.margin_top=0 | |
canvaslayer.add_child(buttons_scroll_container) | |
v_box_container=VBoxContainer.new() | |
v_box_container.alignment=BoxContainer.ALIGN_END | |
v_box_container.size_flags_vertical=Control.SIZE_EXPAND_FILL | |
buttons_scroll_container.add_child(v_box_container) | |
buttons_scroll_container.visible=false | |
func debug_input_entered(text): | |
if console_mode==HISTORY_MODE and text=="" and command_history_line < command_history.size() and command_history.size() > 0: | |
debug_input.text=command_history[command_history_line] | |
else: | |
debug_input.text="" | |
process_command(text) | |
console_mode=DEFAULT | |
command_history_line = command_history.size() | |
buttons_scroll_container.visible=false | |
if debug_input.text=="": | |
show_history() | |
func debug_input_changed(text): | |
if text=="": | |
console_mode=DEFAULT | |
buttons_scroll_container.visible=false | |
show_history() | |
elif last_manually_changed_input_text ==text: | |
console_mode=console_mode | |
else: | |
console_mode=DEFAULT | |
if console_mode==DEFAULT and text!="" : | |
suggest_command(text) | |
func is_debug_console_opened(): | |
return debug_output.visible | |
func _input(event): | |
if Input.is_action_just_pressed("console"): | |
debug_output.visible=!debug_output.visible | |
debug_input.visible=debug_output.visible | |
color_rect.visible=debug_output.visible | |
if debug_output.visible:#görsel efekt | |
debug_input.grab_focus() | |
debug_input.text="" | |
else: | |
buttons_scroll_container.visible=false | |
if Input.is_action_just_pressed("stats"): | |
left_label.visible=!left_label.visible | |
right_label.visible=left_label.visible | |
if debug_input.visible==false: | |
return | |
if event is InputEventKey and event.is_pressed(): | |
if debug_input.has_focus() : | |
if event.scancode == KEY_UP: | |
if (console_mode==DEFAULT and debug_input.text!="") or console_mode==SUGGESTION_MODE: | |
goto_suggestions(-1) | |
elif console_mode==HISTORY_MODE or (console_mode==DEFAULT and debug_input.text==""): | |
goto_command_history(-1) | |
if event.scancode == KEY_DOWN: | |
if (console_mode==DEFAULT and debug_input.text!="") or console_mode==SUGGESTION_MODE: | |
goto_suggestions(1) | |
elif console_mode==HISTORY_MODE or (console_mode==DEFAULT and debug_input.text==""): | |
goto_command_history(1) | |
func add_stat(stat_name, object, stat_ref, is_method,is_left=true): | |
#stat_name is for information | |
#stat_ref is need to be exact name of variable or function | |
if is_left: | |
left_stats.append([stat_name, object, stat_ref, is_method]) | |
else: | |
right_stats.append([stat_name, object, stat_ref, is_method]) | |
func _physics_process(delta): | |
if left_label.visible==false: | |
return | |
calc_stats(left_label,left_stats) | |
calc_stats(right_label,right_stats) | |
func calc_stats(_label,_stats): | |
var label_text = "" | |
if _label==left_label: | |
var fps = Engine.get_frames_per_second() | |
label_text += str("FPS: ", fps) | |
label_text += "\n" | |
var mem = OS.get_static_memory_usage() | |
label_text += str("Static Memory: ", String.humanize_size(mem)) | |
label_text += "\n" | |
for index in range(_stats.size()): | |
var value = null | |
var s=_stats[index] | |
if is_instance_valid(s[1]): | |
if s[3]: | |
value = s[1].call(s[2]) | |
else: | |
value = s[1].get(s[2]) | |
else: | |
plog("object is deleted") | |
_stats.remove(index) | |
return | |
label_text += str(s[0], ": ",value ) | |
label_text += "\n" | |
_label.text = label_text | |
func plog(new_log):#prints log | |
debug_output.text+="\n\n"+str(new_log) | |
print(new_log) | |
func goto_command_history(offset): | |
command_history_line += offset | |
command_history_line = clamp(command_history_line, 0, command_history.size()) | |
if command_history_line < command_history.size() and command_history.size() > 0: | |
console_mode=HISTORY_MODE | |
var button = v_box_container.get_child(command_history_line) | |
button.grab_focus() | |
change_input(command_history[command_history_line]) | |
func goto_suggestions(offset): | |
command_suggestions_line += offset | |
command_suggestions_line = clamp(command_suggestions_line, 0, command_suggestions.size()) | |
if command_suggestions_line < command_suggestions.size() and command_suggestions.size() > 0: | |
console_mode=SUGGESTION_MODE | |
var button = v_box_container.get_child(command_suggestions_line) | |
button.grab_focus() | |
change_input(button.text) | |
func process_command(text): | |
var words = text.split(" ",false) | |
words = Array(words) | |
for i in range(words.count("")): | |
words.erase("") | |
if words.size() == 0: | |
return | |
command_history.append(text) | |
var command_word = words.pop_front() | |
for c in valid_commands: | |
if c[1] == command_word: | |
if words.size() != c[2].size(): | |
plog(str('Failure executing command "', command_word, '", expected ', c[2].size(), ' parameters')) | |
return | |
words = cast_items_of_array(words,c) | |
if (words is bool):#error | |
return | |
c[0].callv(command_word, words) | |
return | |
plog(str('Command "', command_word, '" does not exist.')) | |
func check_type(string, type): | |
if type == ARG_INT: | |
return string.is_valid_integer() | |
if type == ARG_FLOAT: | |
return string.is_valid_float() | |
if type == ARG_STRING: | |
return true | |
if type == ARG_BOOL: | |
return (string == "true" or string == "false") | |
return false | |
func get_type_name(type): | |
if type == ARG_INT: | |
return "int" | |
if type == ARG_FLOAT: | |
return "float" | |
if type == ARG_STRING: | |
return "string" | |
if type == ARG_BOOL: | |
return "bool" | |
else: | |
return "WRONG_TYPE" | |
func cast_type(string,type): | |
if type == ARG_INT: | |
return string as int | |
if type == ARG_FLOAT: | |
return string as float | |
if type == ARG_STRING: | |
return string as String | |
if type == ARG_BOOL: | |
return string as bool | |
else: | |
return "WRONG_TYPE" | |
func cast_items_of_array(words,command): | |
var casted_words=[] | |
for i in range(words.size()): | |
if not check_type(words[i], command[2][i]): | |
plog(str('Failure executing command "', command[1], '", parameter ', (i + 1), | |
' ("', words[i], '") is of the wrong type')) | |
return false | |
else: | |
casted_words.append(cast_type(words[i], command[2][i])) | |
return casted_words; | |
func add_command(_object,_command_name,_args=[]): | |
if not _object.has_method(_command_name): | |
printerr(_object.name," has not command: ", _command_name) | |
var new_command = [_object,_command_name,_args] | |
valid_commands.append(new_command) | |
func clear_output(): | |
debug_output.text="" | |
func clear_history(): | |
command_history.clear() | |
command_history_line=0 | |
func suggest_command(text): | |
command_suggestions.clear() | |
command_suggestions_line=0 | |
for n in v_box_container.get_children(): | |
v_box_container.remove_child(n) | |
n.queue_free() | |
buttons_scroll_container.visible=true | |
for command in valid_commands: | |
if text in command[1]: | |
command_suggestions.append(text) | |
var button = Button.new() | |
button.align=Button.ALIGN_LEFT | |
button.modulate=Color(1,1,1,0.5) | |
button.connect("button_up",self,"change_input",[command[1]]) | |
var button_text = command[1] | |
if show_parametre_type: | |
for arg in command[2]: | |
button_text+=" "+get_type_name(arg) | |
button.text=button_text | |
v_box_container.add_child(button) | |
if v_box_container.get_children().size()==0: | |
buttons_scroll_container.visible=false | |
func show_history(): | |
command_history_line=0 | |
for n in v_box_container.get_children(): | |
v_box_container.remove_child(n) | |
n.queue_free() | |
buttons_scroll_container.visible=true | |
var last_button | |
for command in command_history: | |
var button = Button.new() | |
button.align=Button.ALIGN_LEFT | |
button.modulate=Color(1,1,1,0.5) | |
button.connect("button_up",self,"change_input",[command]) | |
button.text=command | |
v_box_container.add_child(button) | |
last_button=button | |
if v_box_container.get_children().size()==0: | |
buttons_scroll_container.visible=false | |
else: | |
command_history_line= v_box_container.get_children().size() | |
if is_instance_valid(last_button): | |
last_button.call_deferred("grab_focus") | |
debug_input.call_deferred("grab_focus") | |
func change_input(text): | |
last_manually_changed_input_text=text | |
debug_input.text=text | |
debug_input.grab_focus() | |
debug_input.call_deferred("set_cursor_position", debug_input.text.length()) |
Author
cenullum
commented
Aug 29, 2022
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment