2021-10-19 05:10:13 +00:00
|
|
|
extends Control
|
|
|
|
|
2021-11-28 11:45:05 +00:00
|
|
|
# Hello, god class. Though, as an optional module, it's not the worst it could be.
|
|
|
|
# Smells of feature creep, because it absolutely is one.
|
2021-10-20 07:26:32 +00:00
|
|
|
|
2021-10-20 03:14:30 +00:00
|
|
|
var debug_canvas
|
2021-10-19 05:10:13 +00:00
|
|
|
|
2021-10-20 03:14:30 +00:00
|
|
|
var debug_active = false
|
2021-11-08 18:17:13 +00:00
|
|
|
var menu_moving = false
|
2021-10-20 03:14:30 +00:00
|
|
|
var menu_position = 0.0
|
2021-10-20 06:05:39 +00:00
|
|
|
var menu_velocity = 4
|
2021-10-19 05:10:13 +00:00
|
|
|
|
2021-11-08 19:43:11 +00:00
|
|
|
var history : Array = []
|
2021-10-22 06:53:04 +00:00
|
|
|
var history_pos = 0
|
|
|
|
|
2021-11-14 13:13:53 +00:00
|
|
|
# Controls whether to print to the screen
|
|
|
|
var echo = true
|
|
|
|
|
2021-11-28 11:45:05 +00:00
|
|
|
# Controls whether the player is allowed to cheat:
|
|
|
|
var cheats = false
|
|
|
|
var cheat_code = "989172bdaff124fc237b3f904a1886b91dc3ae718da15a6055ff416284f39a58"
|
|
|
|
|
2021-11-08 17:50:14 +00:00
|
|
|
onready var expression = Expression.new()
|
|
|
|
|
2021-11-28 11:45:05 +00:00
|
|
|
# metadata: args list, help blurb, and cheatmap accessed by function name
|
|
|
|
enum {ARGS, HELPTEXT, IS_CHEAT}
|
|
|
|
var command_metadata = {
|
|
|
|
# command_id [args "Help text" is cheat]
|
|
|
|
"command_help": [" [command]", "Print information about command.\n", false],
|
|
|
|
"command_history": ["", "Print the history log.\n", false],
|
|
|
|
"command_perf": [" stat", "Print performance info (fps, nodes, proctime, ... )\n", false],
|
2021-11-08 17:50:14 +00:00
|
|
|
|
2021-11-28 11:45:05 +00:00
|
|
|
"command_list": [" [path]", "List children of path, or of present working node.\n", false],
|
|
|
|
"command_start": [" filename", "Load PackedScene filename.tscn as child.\n", true ],
|
|
|
|
"command_kill": [" name", "Kill child node with matching name.\n", true ],
|
2021-11-08 17:50:14 +00:00
|
|
|
|
2021-11-28 11:45:05 +00:00
|
|
|
"command_pwd": ["", "Print the Present Working Node.\n", false],
|
|
|
|
"command_cd": [" path", "Change the Present Working Node to path.\n", false],
|
2021-11-08 17:50:14 +00:00
|
|
|
|
2021-11-28 11:45:05 +00:00
|
|
|
"command_print": [" string", "Print string to the in-game debug console.\n", false],
|
|
|
|
"command_clear": ["", "Clear the debug output.\n", false],
|
2021-11-08 17:50:14 +00:00
|
|
|
# !EXTREMELY DANGER {
|
2021-11-28 11:45:05 +00:00
|
|
|
"command_emit": [" signal [message]", "Emit a message on MessageBus.signal without validation.\n", true ],
|
|
|
|
"command_call": [" func [args ...]", "Call func(...) with arguments args.\n", true ],
|
|
|
|
"command_exec": [" expression ...", "Evaluate an arbitrary expression, and print the result.\n", true ],
|
2021-11-08 17:50:14 +00:00
|
|
|
# }
|
2021-11-28 11:45:05 +00:00
|
|
|
"command_listprops": ["", "List properties of the Present Working Node\n", true ],
|
|
|
|
"command_getprop": [" prop", "Get the value of property prop\n", true ],
|
|
|
|
"command_setprop": [" prop value", "Set the property prop to value.\n", true ],
|
|
|
|
|
|
|
|
"command_script": [" path", "Load and execute a script at user://scripts/<name>\n", false],
|
|
|
|
"command_echo": [" on/off", "Controls whether lines should be printed to the screen\n", true ],
|
|
|
|
"command_cheat": [" [password]", "Controls whether cheats are enabled, using a fun code\n", false],
|
2021-11-08 17:50:14 +00:00
|
|
|
|
2021-11-28 11:45:05 +00:00
|
|
|
"command_restart": ["", "Kill the current scene tree and plant a new Root.\n", true ],
|
|
|
|
"command_exit": ["", "Quits the program.\n", false],
|
2021-11-08 17:50:14 +00:00
|
|
|
|
2021-11-28 11:45:05 +00:00
|
|
|
"command_empty": ["", "No Operation.\n", false],
|
2021-10-22 06:53:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# List of debug commands accessed by alias
|
|
|
|
# The first alias is the canonical alias, aka command name
|
|
|
|
var commands = {
|
|
|
|
# [alias array]: "func_name"
|
|
|
|
["help", "h"]: "command_help",
|
|
|
|
["hist", "history"]: "command_history",
|
|
|
|
["perf", "performance"]: "command_perf",
|
2021-11-01 00:57:47 +00:00
|
|
|
|
2021-10-22 06:53:04 +00:00
|
|
|
["list", "ls", "l"]: "command_list",
|
|
|
|
["start", "open", "o"]: "command_start",
|
|
|
|
["kill", "stop", "k"]: "command_kill",
|
2021-11-01 00:57:47 +00:00
|
|
|
|
2021-10-22 06:53:04 +00:00
|
|
|
["pwd", "pwn"]: "command_pwd",
|
|
|
|
["cd", "cn"]: "command_cd",
|
2021-11-01 00:57:47 +00:00
|
|
|
|
2021-10-22 06:53:04 +00:00
|
|
|
["print", "p"]: "command_print",
|
|
|
|
["clear","cls"]: "command_clear",
|
2021-11-01 00:57:47 +00:00
|
|
|
|
2021-10-22 06:53:04 +00:00
|
|
|
["emit", "e"]: "command_emit",
|
|
|
|
["call", "func"]: "command_call",
|
2021-11-08 17:50:14 +00:00
|
|
|
["exec", "_", "$", ">"]: "command_exec",
|
|
|
|
|
|
|
|
["listprops", "lsp"]: "command_listprops",
|
|
|
|
["getprop","get", "g"]: "command_getprop",
|
|
|
|
["setprop","set", "s"]: "command_setprop",
|
2021-11-01 00:57:47 +00:00
|
|
|
|
2021-11-14 12:32:46 +00:00
|
|
|
["script", "sh"]: "command_script",
|
2021-11-14 13:13:53 +00:00
|
|
|
["@echo"]: "command_echo",
|
2021-11-28 11:45:05 +00:00
|
|
|
["cheat", "*"]: "command_cheat",
|
|
|
|
|
2021-10-22 06:53:04 +00:00
|
|
|
["restart", "killall"]: "command_restart",
|
|
|
|
["exit", "quit"]: "command_exit",
|
2021-11-01 00:57:47 +00:00
|
|
|
|
2021-11-14 13:36:30 +00:00
|
|
|
["", "#"]: "command_empty"
|
2021-11-01 00:57:47 +00:00
|
|
|
}
|
2021-10-22 06:53:04 +00:00
|
|
|
|
2021-11-08 17:50:14 +00:00
|
|
|
#List of all of Godot's builtin types
|
2021-11-08 19:43:11 +00:00
|
|
|
const types:Array = [
|
|
|
|
"nil", "bool","int","float","String","Vector2","Rect2",
|
|
|
|
"Vector3","Transform2D","Plane","Quat","AABB","Basis","Transform",
|
|
|
|
"Color","NodePath","RID","Object","Dictionary","Array","PoolByteArray",
|
|
|
|
"PoolIntArray","PoolRealArray","PoolStringArray","PoolVector2Array",
|
|
|
|
"PoolVector3Array","PoolColorAray"
|
|
|
|
]
|
2021-11-08 17:50:14 +00:00
|
|
|
|
2021-10-21 10:22:42 +00:00
|
|
|
onready var present_working_node = get_node("/root/Main")
|
2021-10-21 08:18:31 +00:00
|
|
|
|
2021-10-20 03:14:30 +00:00
|
|
|
# positions when the menu is hidden/active
|
2021-10-20 07:26:32 +00:00
|
|
|
var menu_hidden = Transform2D(Vector2(1,0), Vector2(0,1), Vector2(0,-170))
|
2021-10-20 03:14:30 +00:00
|
|
|
var menu_active = Transform2D(Vector2(1,0), Vector2(0,1), Vector2(0, 0))
|
2021-10-19 05:10:13 +00:00
|
|
|
|
2021-10-20 08:18:06 +00:00
|
|
|
# signals
|
2021-10-22 06:53:04 +00:00
|
|
|
# clear_in: clear the debug input
|
|
|
|
signal clear_in
|
|
|
|
# clear_out: clear the debug output
|
|
|
|
signal clear_out
|
|
|
|
# print_text(text): Send text to the Out buffer
|
|
|
|
signal print_text(text)
|
|
|
|
# history_event(text): Send text to the In buffer
|
|
|
|
signal history_event(text)
|
2021-10-20 08:18:06 +00:00
|
|
|
|
2021-10-22 06:53:04 +00:00
|
|
|
# Inherited functions:
|
|
|
|
# _ready: Called when the node enters the scene tree for the first time.
|
|
|
|
# params: none
|
|
|
|
# returns: void
|
2021-10-19 05:10:13 +00:00
|
|
|
func _ready():
|
2021-10-20 03:14:30 +00:00
|
|
|
debug_canvas = get_node("debug_canvas")
|
2021-11-08 18:17:13 +00:00
|
|
|
debug_canvas.set_transform(menu_hidden) #initialize the debug menu as hidden
|
2021-10-20 11:00:09 +00:00
|
|
|
command_help([""])
|
2021-10-21 10:22:42 +00:00
|
|
|
debug_print_line("> ")
|
2021-10-19 05:10:13 +00:00
|
|
|
|
2021-10-22 06:53:04 +00:00
|
|
|
# _process: Called every frame. Controls slide-in animation and focus-grabbing
|
|
|
|
# params: delta: elapsed time
|
|
|
|
# returns: void
|
2021-10-20 03:14:30 +00:00
|
|
|
func _process(delta):
|
|
|
|
if (debug_active && menu_position < 1):
|
2021-10-20 11:00:09 +00:00
|
|
|
# Move the menu down
|
2021-10-20 03:14:30 +00:00
|
|
|
menu_position += menu_velocity * delta;
|
2021-11-08 18:17:13 +00:00
|
|
|
menu_moving = true
|
2021-10-20 11:00:09 +00:00
|
|
|
$debug_canvas/VBoxContainer/LineEdit.grab_focus()
|
2021-10-20 03:14:30 +00:00
|
|
|
elif (!debug_active && menu_position > 0):
|
2021-10-20 11:00:09 +00:00
|
|
|
# Move the menu up
|
2021-10-20 03:14:30 +00:00
|
|
|
menu_position -= menu_velocity * delta;
|
2021-11-08 18:17:13 +00:00
|
|
|
menu_moving = true
|
2021-10-20 11:00:09 +00:00
|
|
|
# Clear the input box
|
|
|
|
emit_signal("clear_in")
|
2021-11-08 18:17:13 +00:00
|
|
|
elif (menu_position < 0 || menu_position > 1):
|
2021-10-20 03:14:30 +00:00
|
|
|
menu_position = round(menu_position)
|
2021-11-08 18:17:13 +00:00
|
|
|
menu_moving = true
|
|
|
|
else:
|
|
|
|
menu_moving = false
|
|
|
|
if menu_moving:
|
|
|
|
debug_canvas.set_transform(menu_hidden.interpolate_with(menu_active, menu_position))
|
2021-10-20 03:14:30 +00:00
|
|
|
|
2021-10-22 06:53:04 +00:00
|
|
|
# _input: Process user input related to the debug menu
|
|
|
|
# params: event: The input event which triggered _input call
|
|
|
|
# returns: void
|
2021-10-20 08:18:06 +00:00
|
|
|
func _input(event):
|
2021-10-22 06:53:04 +00:00
|
|
|
if event.is_action_pressed("ui_debug_open"):
|
2021-10-20 03:14:30 +00:00
|
|
|
# open debug menu
|
|
|
|
debug_active = !debug_active;
|
2021-10-20 11:00:09 +00:00
|
|
|
# Hand the keyboard focus to the next valid focus
|
2021-10-21 06:24:27 +00:00
|
|
|
if (!debug_active) && find_next_valid_focus(): find_next_valid_focus().grab_focus()
|
2021-10-22 06:53:04 +00:00
|
|
|
if event.is_action_pressed("ui_debug_up") and debug_active:
|
|
|
|
#traverse history up
|
|
|
|
history_move(-1)
|
|
|
|
pass
|
|
|
|
if event.is_action_pressed("ui_debug_down") and debug_active:
|
|
|
|
#traverse history down
|
|
|
|
history_move(+1)
|
2021-10-20 05:40:31 +00:00
|
|
|
|
2021-11-14 20:06:56 +00:00
|
|
|
# Command-processing functions:
|
2021-10-22 06:53:04 +00:00
|
|
|
# _on_LineEdit_text_entered: process incoming text line
|
|
|
|
# params: line: Line of text entered by user
|
|
|
|
# returns: void
|
2021-10-20 07:26:32 +00:00
|
|
|
func _on_LineEdit_text_entered(line):
|
2021-10-20 10:13:24 +00:00
|
|
|
emit_signal("clear_in")
|
2021-10-21 10:22:42 +00:00
|
|
|
debug_print_line(line + "\n")
|
2021-10-20 07:26:32 +00:00
|
|
|
var command = line.split(' ', true, 1)
|
2021-11-14 20:06:56 +00:00
|
|
|
if execute_command(command):
|
2021-11-14 13:13:53 +00:00
|
|
|
history_append(line)
|
2021-10-22 06:53:04 +00:00
|
|
|
else:
|
|
|
|
debug_print_line("dbg: command not found: " + command[0] + "\n")
|
2021-10-21 10:22:42 +00:00
|
|
|
debug_print_line("> ")
|
2021-10-20 05:40:31 +00:00
|
|
|
|
2021-11-14 20:06:56 +00:00
|
|
|
# execute_command: execute a line of text as a command
|
|
|
|
# params: command: partially tokenized PoolStringArray ["command_alias", "parameters ..."]
|
|
|
|
# returns: name of executed function, or null if nothing executed
|
|
|
|
func execute_command(command):
|
|
|
|
var command_func = parse(command[0])
|
2021-11-28 11:45:05 +00:00
|
|
|
if command_func and is_command_allowed(command_func):
|
2021-11-14 20:06:56 +00:00
|
|
|
call(command_func, command)
|
2021-11-28 11:45:05 +00:00
|
|
|
else:
|
|
|
|
command_func = null
|
2021-11-14 20:06:56 +00:00
|
|
|
return command_func
|
|
|
|
|
2021-11-28 11:45:05 +00:00
|
|
|
# is_command_allowed: Test if the command is allowed (not cheating, or cheating is on)
|
|
|
|
# params: command_func: the name of the function to be executed
|
|
|
|
# returns: true if command is valid, or false if command is cheat and cheating is disabled
|
|
|
|
func is_command_allowed(command_func):
|
|
|
|
# return true if cheats or on, or command is not cheat
|
|
|
|
return cheats or not command_metadata[command_func][IS_CHEAT]
|
|
|
|
|
2021-10-22 06:53:04 +00:00
|
|
|
# History_related helper functions:
|
2021-10-29 22:39:46 +00:00
|
|
|
# history_append: add a line of text to the history
|
|
|
|
# params: text: line of text (unparsed command) to add to history
|
|
|
|
# returns: void
|
2021-10-22 06:53:04 +00:00
|
|
|
func history_append(text):
|
|
|
|
history.resize(history_pos + 2)
|
|
|
|
history[history_pos] = text
|
2021-11-01 00:57:47 +00:00
|
|
|
history[history_pos + 1] = ""
|
2021-10-22 06:53:04 +00:00
|
|
|
history_pos += 1
|
|
|
|
|
2021-10-29 22:39:46 +00:00
|
|
|
# history_move: Traverse the history and update the user input box
|
|
|
|
# params: rel_pos: amount to move, relative to the current history_pos
|
|
|
|
# returns: void
|
|
|
|
func history_move(rel_pos):
|
|
|
|
var new_pos = history_pos + rel_pos
|
|
|
|
if new_pos >= 0 and new_pos < history.size():
|
|
|
|
history_pos = new_pos;
|
2021-10-22 06:53:04 +00:00
|
|
|
if history[history_pos]:
|
|
|
|
emit_signal("history_event", history[history_pos])
|
|
|
|
else:
|
|
|
|
emit_signal("clear_in")
|
|
|
|
|
|
|
|
# Debug-related helper functions:
|
|
|
|
# debug_print_line: request printing of c-escaped text to debug output
|
|
|
|
# params: string: Text string to print
|
|
|
|
# returns: void
|
2021-10-20 07:26:32 +00:00
|
|
|
func debug_print_line(string):
|
2021-11-14 13:13:53 +00:00
|
|
|
if echo:
|
|
|
|
emit_signal("print_text", string.c_unescape())
|
2021-10-20 10:13:24 +00:00
|
|
|
|
2021-11-11 21:08:09 +00:00
|
|
|
# get_pwn: get the present working node if valid, otherwise cd to root
|
|
|
|
func get_pwn():
|
|
|
|
if !is_instance_valid(present_working_node):
|
|
|
|
debug_print_line("Node freed, traversing to /root/\n")
|
|
|
|
present_working_node = get_node("/root/")
|
|
|
|
return present_working_node
|
|
|
|
|
|
|
|
|
2021-10-22 06:53:04 +00:00
|
|
|
# complete_path: complete a relative or absolute path, and returns the node it refers to
|
|
|
|
# params: path: relative or absolute path to a node
|
|
|
|
# returns: void
|
|
|
|
func complete_path(path):
|
|
|
|
if path.is_rel_path(): # convert to absolute path
|
2021-11-11 21:08:09 +00:00
|
|
|
path = String(get_pwn().get_path()) + "/" + path
|
2021-10-22 06:53:04 +00:00
|
|
|
var node = get_node(path)
|
|
|
|
if node:
|
|
|
|
return node
|
|
|
|
return null
|
|
|
|
|
|
|
|
# Command-lookup functions:
|
|
|
|
# parse: parse command name and return associated func name
|
|
|
|
# params: alias: alias of a command
|
|
|
|
# returns: name of command function
|
|
|
|
func parse(alias):
|
|
|
|
var key = lookup(alias)
|
|
|
|
if key:
|
|
|
|
return commands[key]
|
|
|
|
return null
|
|
|
|
|
|
|
|
# name_lookup: find key associated with function name
|
|
|
|
# params: command_name: alias of a command
|
|
|
|
# returns: key: Array containing all aliases of the given command
|
|
|
|
func lookup(alias):
|
|
|
|
for key in commands.keys():
|
|
|
|
if alias in key:
|
|
|
|
return key
|
|
|
|
return null
|
|
|
|
|
|
|
|
# get_canonical: find the canonical name for a command
|
|
|
|
# params: alias: alias of a command
|
|
|
|
# returns: name: canonical name for a command
|
|
|
|
func get_canonical(alias):
|
|
|
|
var names = lookup(alias)
|
|
|
|
if names:
|
|
|
|
return names[0]
|
|
|
|
return null
|
|
|
|
|
|
|
|
# get_usage: Construct the usage string for a command
|
2021-10-29 22:39:46 +00:00
|
|
|
# params: alias: alias of a command
|
|
|
|
# returns: usage string for the command, formatted for printing
|
2021-10-22 06:53:04 +00:00
|
|
|
func get_usage(alias):
|
2021-11-28 11:45:05 +00:00
|
|
|
return "Usage: " + alias + command_metadata[parse(alias)][0] + "\n"
|
2021-10-20 10:13:24 +00:00
|
|
|
|
2021-11-08 17:50:14 +00:00
|
|
|
# String casting functions
|
|
|
|
# variant_to_string: Cast arbitrary GDScript Variant to String
|
|
|
|
# params: variant: variant to cast
|
|
|
|
# returns: String representing the Variant as closely as possible
|
|
|
|
func variant_to_string(variant):
|
|
|
|
var res
|
|
|
|
match typeof(variant):
|
|
|
|
TYPE_NIL:
|
|
|
|
res = "null"
|
|
|
|
TYPE_OBJECT: #No conversion from object to string; a unique case.
|
|
|
|
if (variant):
|
|
|
|
res = variant.to_string()
|
|
|
|
else:
|
|
|
|
res = "Object = null"
|
|
|
|
_:
|
|
|
|
res = String(variant)
|
|
|
|
return res
|
|
|
|
|
|
|
|
# string_to_variant: Cast a string to a specified GDScript type
|
|
|
|
# params: string: string to be cast
|
|
|
|
# type: type to cast string to
|
|
|
|
# returns: GDScript Variant of given type
|
|
|
|
func string_to_variant(string, type):
|
|
|
|
var res = null
|
|
|
|
var list = listify_string(string)
|
|
|
|
match type:
|
|
|
|
TYPE_NIL:
|
|
|
|
res = null
|
|
|
|
TYPE_BOOL:
|
|
|
|
match string.to_lower():
|
2021-11-14 13:13:53 +00:00
|
|
|
"true", "1", "ok", "on":
|
2021-11-08 17:50:14 +00:00
|
|
|
res = true
|
|
|
|
_:
|
|
|
|
res = false
|
|
|
|
TYPE_INT:
|
|
|
|
res = int(string)
|
|
|
|
TYPE_REAL:
|
|
|
|
res = float(string)
|
|
|
|
TYPE_STRING:
|
|
|
|
res = string
|
|
|
|
TYPE_COLOR:
|
|
|
|
res = Color(string)
|
|
|
|
TYPE_NODE_PATH:
|
|
|
|
res = NodePath(string)
|
|
|
|
TYPE_ARRAY:
|
|
|
|
res = list
|
|
|
|
TYPE_RAW_ARRAY:
|
|
|
|
res = PoolByteArray(list)
|
|
|
|
TYPE_INT_ARRAY:
|
|
|
|
res = PoolIntArray(list)
|
|
|
|
TYPE_REAL_ARRAY:
|
|
|
|
res = PoolRealArray(list)
|
|
|
|
TYPE_STRING_ARRAY:
|
|
|
|
res = list
|
|
|
|
TYPE_COLOR_ARRAY:
|
|
|
|
res = PoolColorArray(list)
|
|
|
|
_:
|
2021-11-28 11:45:05 +00:00
|
|
|
debug_print_line("No cast from String to %s\n" % types[typeof(type)])
|
2021-11-08 17:50:14 +00:00
|
|
|
return res
|
|
|
|
|
|
|
|
# listify_string: takes a string and turns it into a list, by splitting on commas and/or spaces
|
|
|
|
# params: string: string to be made into a list
|
|
|
|
# returns: PoolStringArray containing substrings of the list
|
|
|
|
func listify_string(string):
|
|
|
|
var res = []
|
|
|
|
if string.findn(', ') > -1:
|
|
|
|
res = string.split(', ', true, 0)
|
|
|
|
elif string.findn(',') > -1:
|
|
|
|
res = string.split(',', true, 0)
|
|
|
|
else:
|
|
|
|
res = string.split(' ', true, 0)
|
|
|
|
return res
|
|
|
|
|
2021-12-06 19:02:11 +00:00
|
|
|
# file_exists: checks if a file exists at path
|
|
|
|
# params: path: string denoting the path to a file
|
|
|
|
# returns: bool denoting file's presence at path
|
|
|
|
func file_exists(path):
|
|
|
|
var D = Directory.new()
|
|
|
|
return D.file_exists(path)
|
|
|
|
|
|
|
|
|
2021-10-22 06:53:04 +00:00
|
|
|
# Commands. All commands take in a parameter called command,
|
|
|
|
# which contains a partially tokenized command
|
2021-10-20 10:13:24 +00:00
|
|
|
# start: Loads scene from res://scenes/*.tscn by filename, and starts it
|
|
|
|
func command_start (command):
|
|
|
|
if command.size() > 1:
|
2021-12-06 19:02:11 +00:00
|
|
|
var path = "res://scenes/%s.tscn" % command[1]
|
|
|
|
var pack = load(path) if file_exists(path) else null
|
|
|
|
# Check if the resource was opened
|
|
|
|
if pack:
|
|
|
|
get_pwn().add_child(pack.instance());
|
|
|
|
debug_print_line("started '%s'\n" % command[1])
|
|
|
|
else:
|
|
|
|
debug_print_line("Path not found: %s\n" % "res://scenes/%s.tscn" % command[1])
|
2021-10-20 10:13:24 +00:00
|
|
|
else:
|
2021-10-22 06:53:04 +00:00
|
|
|
debug_print_line(get_usage(command[0]))
|
2021-10-20 10:13:24 +00:00
|
|
|
|
2021-10-21 10:22:42 +00:00
|
|
|
# stop: kills a child of current working node
|
2021-10-22 06:53:04 +00:00
|
|
|
func command_kill (command):
|
2021-10-20 11:00:09 +00:00
|
|
|
if command.size() > 1:
|
2021-11-11 21:08:09 +00:00
|
|
|
var node = get_pwn().find_node(command[1], false, false)
|
2021-10-21 10:22:42 +00:00
|
|
|
if node:
|
|
|
|
if String(node.get_path()).match("*Debug*"):
|
2021-12-06 19:02:11 +00:00
|
|
|
debug_print_line("I'm sorry, Dave. I'm afraid I can't do that.\n")
|
2021-10-21 10:22:42 +00:00
|
|
|
else:
|
|
|
|
node.queue_free()
|
2021-11-28 11:45:05 +00:00
|
|
|
debug_print_line("%s killed\n" % command[1])
|
2021-10-20 11:00:09 +00:00
|
|
|
else:
|
2021-11-28 11:45:05 +00:00
|
|
|
debug_print_line("%s: %s not found.\n" % [command[0], command[1]])
|
2021-10-20 10:13:24 +00:00
|
|
|
else:
|
2021-10-22 06:53:04 +00:00
|
|
|
debug_print_line(get_usage(command[0]))
|
2021-10-21 10:22:42 +00:00
|
|
|
|
|
|
|
# list: Lists children of node
|
|
|
|
func command_list (command):
|
|
|
|
var node = null
|
|
|
|
if (command.size() > 1):
|
|
|
|
node = complete_path(command[1])
|
|
|
|
if (!node):
|
2021-11-11 21:08:09 +00:00
|
|
|
node = get_pwn()
|
2021-10-21 10:22:42 +00:00
|
|
|
var children = node.get_children()
|
2021-10-21 08:18:31 +00:00
|
|
|
var names = []
|
|
|
|
for i in range (children.size()):
|
|
|
|
names.append(children[i].name)
|
|
|
|
debug_print_line(String(names) + "\n")
|
2021-10-20 10:13:24 +00:00
|
|
|
|
|
|
|
# restart: Kills the current tree and replants Root
|
2021-10-20 11:00:09 +00:00
|
|
|
func command_restart (_command):
|
2021-10-20 10:13:24 +00:00
|
|
|
MessageBus.emit_signal("return_to_title")
|
|
|
|
|
|
|
|
# print: prints a message to the in-game debug console
|
|
|
|
func command_print(command):
|
|
|
|
if command.size() > 1:
|
2021-11-14 20:06:56 +00:00
|
|
|
debug_print_line(command[1])
|
2021-10-21 10:22:42 +00:00
|
|
|
else:
|
|
|
|
debug_print_line("\n")
|
2021-10-20 10:13:24 +00:00
|
|
|
|
2021-10-21 10:22:42 +00:00
|
|
|
# emit: emits a message onto the MessageBus
|
2021-10-20 10:13:24 +00:00
|
|
|
func command_emit (command):
|
2021-10-22 06:53:04 +00:00
|
|
|
if command.size() > 1:
|
|
|
|
var mbus_signal = command[1].split(' ', true, 1)
|
|
|
|
match mbus_signal.size():
|
|
|
|
2:
|
2021-11-28 11:45:05 +00:00
|
|
|
debug_print_line("Message: %s (%s)" % mbus_signal)
|
2021-10-22 06:53:04 +00:00
|
|
|
MessageBus.emit_signal(mbus_signal[0], mbus_signal[1])
|
|
|
|
1:
|
2021-11-28 11:45:05 +00:00
|
|
|
debug_print_line("Message: %s" % mbus_signal)
|
2021-10-22 06:53:04 +00:00
|
|
|
MessageBus.emit_signal(mbus_signal[0])
|
|
|
|
0: debug_print_line(get_usage(command[0]))
|
|
|
|
else:
|
|
|
|
debug_print_line(get_usage(command[0]))
|
2021-10-20 10:13:24 +00:00
|
|
|
|
|
|
|
# clear: clears the debug output
|
2021-10-20 11:00:09 +00:00
|
|
|
func command_clear (_command):
|
2021-10-20 10:13:24 +00:00
|
|
|
emit_signal("clear_out");
|
|
|
|
|
2021-10-22 06:53:04 +00:00
|
|
|
# pwd: print the present working node's path
|
2021-10-21 08:18:31 +00:00
|
|
|
func command_pwd (_command):
|
2021-11-11 21:08:09 +00:00
|
|
|
debug_print_line(String(get_pwn().get_path()) + "\n")
|
2021-10-22 06:53:04 +00:00
|
|
|
|
|
|
|
# cd: change the present working node
|
2021-10-21 08:18:31 +00:00
|
|
|
func command_cd (command):
|
|
|
|
if command.size() > 1:
|
2021-10-21 10:22:42 +00:00
|
|
|
var node = complete_path(command[1])
|
2021-10-21 08:18:31 +00:00
|
|
|
if node:
|
|
|
|
present_working_node = node
|
|
|
|
else:
|
2021-10-22 06:53:04 +00:00
|
|
|
debug_print_line (get_canonical(command[0]) + ': no such node: ' + command[1] + '\n')
|
2021-10-21 08:18:31 +00:00
|
|
|
else:
|
2021-10-22 06:53:04 +00:00
|
|
|
debug_print_line(get_usage(command[0]))
|
2021-10-20 11:00:09 +00:00
|
|
|
|
2021-10-20 10:13:24 +00:00
|
|
|
# help: Prints help dialogue
|
|
|
|
func command_help (command):
|
|
|
|
if (command.size() == 1):
|
2021-10-22 06:53:04 +00:00
|
|
|
debug_print_line("Valid commands:\n")
|
|
|
|
for key in commands:
|
2021-11-28 11:45:05 +00:00
|
|
|
# if command is allowed in current context, print it
|
|
|
|
if is_command_allowed(commands[key]):
|
|
|
|
debug_print_line(key[0] + " ")
|
2021-10-22 06:53:04 +00:00
|
|
|
debug_print_line("\n")
|
2021-10-20 10:13:24 +00:00
|
|
|
else:
|
2021-10-22 06:53:04 +00:00
|
|
|
var command_func = parse(command[1])
|
2021-11-28 11:45:05 +00:00
|
|
|
if command_func in command_metadata and is_command_allowed(command_func):
|
|
|
|
var text = command_metadata[command_func]
|
|
|
|
var aliases = String(lookup(command[1]))
|
|
|
|
debug_print_line("%s%s:\n Aliases: %s\n %s" % [command[1], text[ARGS], aliases, text[HELPTEXT]])
|
2021-10-22 06:53:04 +00:00
|
|
|
else:
|
2021-11-28 11:45:05 +00:00
|
|
|
debug_print_line("%s: command not found: %s\n" % [command[0], command[1]])
|
2021-10-22 06:53:04 +00:00
|
|
|
|
|
|
|
# exit: request program exit
|
|
|
|
func command_exit(_command):
|
|
|
|
MessageBus.emit_signal("quit")
|
|
|
|
|
|
|
|
# call: call arbitrary member function of present working node
|
|
|
|
func command_call(command):
|
|
|
|
if command.size() > 1:
|
|
|
|
var call_ret = null
|
|
|
|
var call_args = []
|
|
|
|
var call_cmd = command[1].split(' ', true, 1)
|
|
|
|
if call_cmd.size() > 1:
|
|
|
|
call_args = call_cmd[1].split(' ', false, 0)
|
2021-11-11 21:08:09 +00:00
|
|
|
if get_pwn().has_method(call_cmd[0]):
|
|
|
|
call_ret = get_pwn().callv(call_cmd[0], call_args)
|
2021-10-22 06:53:04 +00:00
|
|
|
else:
|
|
|
|
debug_print_line("We're sorry, but your call could not be completed as dialed.\n"
|
|
|
|
+ "Please hang up and try your call again.\n")
|
|
|
|
return
|
2021-11-28 11:45:05 +00:00
|
|
|
debug_print_line("%s\n" % variant_to_string(call_ret))
|
2021-11-08 17:50:14 +00:00
|
|
|
else:
|
|
|
|
debug_print_line(get_usage(command[0]))
|
|
|
|
|
|
|
|
# exec: execute an arbitrary GDScript expression as present working node
|
|
|
|
func command_exec(command):
|
|
|
|
if command.size() > 1:
|
|
|
|
var res
|
|
|
|
var err = expression.parse(command[1])
|
|
|
|
if err == OK:
|
2021-11-11 21:08:09 +00:00
|
|
|
res = expression.execute([], get_pwn(), false);
|
2021-11-08 17:50:14 +00:00
|
|
|
if expression.has_execute_failed():
|
2021-11-28 11:45:05 +00:00
|
|
|
debug_print_line("%s: command not found: %s " % [command[0], command[1]])
|
2021-11-08 17:50:14 +00:00
|
|
|
res = ""
|
2021-10-22 06:53:04 +00:00
|
|
|
else:
|
2021-11-08 17:50:14 +00:00
|
|
|
res = expression.get_error_text()
|
2021-11-28 11:45:05 +00:00
|
|
|
debug_print_line("%s\n" % variant_to_string(res))
|
2021-11-08 17:50:14 +00:00
|
|
|
else:
|
|
|
|
debug_print_line(get_usage(command[0]))
|
|
|
|
|
|
|
|
# listprops: list properties (variables) of present working node
|
|
|
|
func command_listprops(_command):
|
2021-11-08 19:43:11 +00:00
|
|
|
var props = ""
|
2021-11-11 21:08:09 +00:00
|
|
|
var proplist = get_pwn().get_property_list()
|
2021-11-08 19:43:11 +00:00
|
|
|
proplist.sort_custom(self, "propSort")
|
|
|
|
for prop in proplist:
|
|
|
|
if prop["name"]:
|
2021-11-28 11:45:05 +00:00
|
|
|
props += "%s %s\n" % [types[prop["type"]], prop["name"]]
|
2021-11-08 19:43:11 +00:00
|
|
|
pass
|
|
|
|
debug_print_line(props)
|
2021-11-08 17:50:14 +00:00
|
|
|
pass
|
2021-11-28 11:45:05 +00:00
|
|
|
# propsort: sort props by type, alphabetically
|
2021-11-08 19:43:11 +00:00
|
|
|
func propSort(a, b):
|
|
|
|
if a["type"] == b["type"]:
|
|
|
|
return a["name"] < b["name"]
|
|
|
|
return types[a["type"]].to_lower() < types[b["type"]].to_lower()
|
2021-11-08 17:50:14 +00:00
|
|
|
|
|
|
|
# getprop: get the value of a named property of the present working node
|
|
|
|
func command_getprop(command):
|
2021-11-08 19:43:11 +00:00
|
|
|
if command.size() > 1:
|
2021-11-11 21:08:09 +00:00
|
|
|
var res = get_pwn().get(command[1])
|
2021-11-08 17:50:14 +00:00
|
|
|
debug_print_line(variant_to_string(res) + "\n")
|
|
|
|
else:
|
|
|
|
debug_print_line(get_usage(command[0]))
|
|
|
|
|
|
|
|
# setprop: set the value of a named property of the present working node
|
|
|
|
func command_setprop(command):
|
|
|
|
if command.size() > 1:
|
|
|
|
var prop = command[1].split(' ', true, 1)
|
|
|
|
if prop.size() > 1 && prop[0].is_valid_identifier():
|
2021-11-11 21:08:09 +00:00
|
|
|
var type = typeof(get_pwn().get(prop[0]))
|
2021-11-08 17:50:14 +00:00
|
|
|
var variant = string_to_variant(prop[1], type)
|
|
|
|
if typeof(variant) > TYPE_NIL:
|
2021-11-11 21:08:09 +00:00
|
|
|
get_pwn().set(prop[0], string_to_variant(prop[1], type))
|
2021-10-22 06:53:04 +00:00
|
|
|
else:
|
|
|
|
debug_print_line(get_usage(command[0]))
|
|
|
|
|
2021-10-29 22:39:46 +00:00
|
|
|
# history: print the command history
|
2021-10-22 06:53:04 +00:00
|
|
|
func command_history(_command):
|
|
|
|
var lnum = 0
|
|
|
|
for line in history:
|
|
|
|
if line:
|
2021-11-28 11:45:05 +00:00
|
|
|
debug_print_line("%2d: %s\n" % [lnum, line])
|
2021-10-22 06:53:04 +00:00
|
|
|
lnum += 1
|
2021-11-01 00:57:47 +00:00
|
|
|
#debug_print_line("history_pos = " + String(history_pos) + "\n")
|
2021-10-22 06:53:04 +00:00
|
|
|
|
2021-10-29 22:39:46 +00:00
|
|
|
# perf: Print the value of a Godot Engine performance counter
|
2021-10-22 06:53:04 +00:00
|
|
|
func command_perf(command):
|
|
|
|
if command.size() > 1:
|
|
|
|
var stat = perf(command[1])
|
|
|
|
if stat:
|
2021-11-28 11:45:05 +00:00
|
|
|
debug_print_line("%s\n" % String(stat))
|
2021-10-22 06:53:04 +00:00
|
|
|
else:
|
|
|
|
debug_print_line("null\n")
|
|
|
|
else:
|
|
|
|
debug_print_line(get_usage(command[0]))
|
|
|
|
|
2021-11-14 13:36:30 +00:00
|
|
|
# script: run a script from user://scripts/
|
2021-11-14 12:32:46 +00:00
|
|
|
func command_script(command):
|
|
|
|
var script = []
|
|
|
|
if (command.size() > 1):
|
2021-11-14 13:36:30 +00:00
|
|
|
var path = "user://scripts/" + command[1]
|
2021-11-14 12:32:46 +00:00
|
|
|
var f = File.new()
|
|
|
|
var err = f.open(path, File.READ)
|
|
|
|
if err == OK:
|
2021-11-14 13:36:30 +00:00
|
|
|
# Read the file
|
2021-11-14 12:32:46 +00:00
|
|
|
while not f.eof_reached():
|
|
|
|
script.push_back(f.get_line())
|
|
|
|
f.close()
|
2021-11-14 13:36:30 +00:00
|
|
|
# Save state and turn off echo
|
2021-11-28 11:45:05 +00:00
|
|
|
var state = {"echo": echo,
|
|
|
|
"pwn": present_working_node,
|
2021-11-14 14:00:56 +00:00
|
|
|
"history_pos": history_pos,
|
|
|
|
"history": history,
|
2021-11-28 11:45:05 +00:00
|
|
|
"expression": expression,
|
|
|
|
"cheats": cheats}
|
2021-11-14 13:13:53 +00:00
|
|
|
echo = false
|
2021-11-14 13:36:30 +00:00
|
|
|
# Execute the script
|
2021-11-14 12:32:46 +00:00
|
|
|
for cmd in script:
|
2021-11-14 20:06:56 +00:00
|
|
|
cmd = cmd.split(' ', true, 1)
|
|
|
|
execute_command(cmd)
|
2021-11-14 14:00:56 +00:00
|
|
|
# Restore state
|
|
|
|
echo = state["echo"]
|
|
|
|
present_working_node = state["pwn"]
|
|
|
|
history_pos = state["history_pos"]
|
|
|
|
history = state["history"]
|
|
|
|
expression = state["expression"]
|
2021-11-28 11:45:05 +00:00
|
|
|
cheats = state["cheats"]
|
2021-11-14 12:32:46 +00:00
|
|
|
else:
|
|
|
|
debug_print_line("File not found: " + command[1] + "\n")
|
|
|
|
else:
|
|
|
|
debug_print_line(get_usage(command[0]))
|
|
|
|
|
2021-11-28 11:45:05 +00:00
|
|
|
# echo: enable and disable echoing commands and their outputs to the terminal
|
2021-11-14 13:13:53 +00:00
|
|
|
func command_echo(command):
|
|
|
|
if command.size() > 1:
|
|
|
|
echo = string_to_variant(command[1], TYPE_BOOL)
|
|
|
|
else:
|
|
|
|
debug_print_line(get_usage(command[0]))
|
|
|
|
|
2021-11-28 11:45:05 +00:00
|
|
|
# cheat: Disable cheats, or enable them if you say the magic word
|
|
|
|
func command_cheat(command):
|
|
|
|
# check if there's more than one input to the command:
|
|
|
|
if command.size() > 1:
|
|
|
|
# hash the password
|
|
|
|
var code = command[1].sha256_text()
|
|
|
|
if code == cheat_code:
|
|
|
|
debug_print_line("Cheats enabled.\n")
|
|
|
|
cheats = true
|
|
|
|
return
|
|
|
|
debug_print_line("Ah ah ah, you didn't say the magic word!\n")
|
|
|
|
cheats = false
|
|
|
|
debug_print_line("Cheats disabled.\n")
|
|
|
|
pass
|
|
|
|
|
|
|
|
# look-up table for performance monitor -> index pairs
|
|
|
|
# See https://docs.godotengine.org/en/stable/classes/class_performance.html
|
|
|
|
const monitor_lookup = {
|
|
|
|
# Time
|
|
|
|
"time:fps": 0,
|
|
|
|
"time:process": 1,
|
|
|
|
"time:physics process": 2,
|
|
|
|
# Memory
|
|
|
|
"memory:static": 3,
|
|
|
|
"memory:dynamic": 4,
|
|
|
|
"memory:static max": 5,
|
|
|
|
"memory:dynamic max": 6,
|
|
|
|
"memory:message buffer max": 7,
|
|
|
|
# Objects
|
|
|
|
"object:count": 8,
|
|
|
|
"object:resource count": 9,
|
|
|
|
"object:node count": 10,
|
|
|
|
"object:orphan node count": 11,
|
|
|
|
# Render
|
|
|
|
"render:objects in frame": 12,
|
|
|
|
"render:vertices in frame": 13,
|
|
|
|
"render:material changes in frame": 14,
|
|
|
|
"render:shader changes in frame": 15,
|
|
|
|
"render:surface changes in frame": 16,
|
|
|
|
"render:draw calls in frame": 17,
|
|
|
|
"render:2d items in frame": 18,
|
|
|
|
"render:2d draw calls in frame": 19,
|
|
|
|
"render:video memory used": 20,
|
|
|
|
"render:texture memory used": 21,
|
|
|
|
"render:vertex memory used": 22,
|
|
|
|
"render:total video memory used": 23,
|
|
|
|
# Physics2D
|
|
|
|
"physics2d:active objects": 24,
|
|
|
|
"physics2d:collision pairs": 25,
|
|
|
|
"physics2d:island count":26,
|
|
|
|
# Physics3D
|
|
|
|
"physics3d:active objects": 27,
|
|
|
|
"physics3d:collision pairs": 28,
|
|
|
|
"physics3d:island count": 29,
|
|
|
|
# Audio
|
|
|
|
"audio:output latency": 30
|
|
|
|
}
|
|
|
|
|
|
|
|
# Get a performance counter given a string
|
2021-10-22 06:53:04 +00:00
|
|
|
func perf(attribute):
|
|
|
|
if attribute.is_valid_integer():
|
|
|
|
return Performance.get_monitor(int(attribute))
|
2021-11-28 11:45:05 +00:00
|
|
|
if attribute in monitor_lookup:
|
|
|
|
return Performance.get_monitor(monitor_lookup[attribute.to_lower()])
|
|
|
|
# Shortcut to popular counters
|
|
|
|
match attribute.to_lower():
|
2021-10-22 06:53:04 +00:00
|
|
|
"fps":
|
|
|
|
return Performance.get_monitor(Performance.TIME_FPS)
|
|
|
|
"proctime":
|
|
|
|
return Performance.get_monitor(Performance.TIME_PROCESS)
|
|
|
|
"objects":
|
|
|
|
return Performance.get_monitor(Performance.OBJECT_COUNT)
|
|
|
|
"nodes":
|
|
|
|
return Performance.get_monitor(Performance.OBJECT_NODE_COUNT)
|
|
|
|
"resources":
|
|
|
|
return Performance.get_monitor(Performance.OBJECT_RESOURCE_COUNT)
|
|
|
|
return ""
|
2021-11-01 00:57:47 +00:00
|
|
|
|
|
|
|
# empty: No command
|
|
|
|
func command_empty(_command):
|
|
|
|
pass
|