# ############################################################################## # scratch/get_info.gd has grown into a monster. # This is my attempt to tame that monster into a re-usable thing so get_info.gd # doesn't keep getting bigger with each new thing I try to explore. # ############################################################################## class_name ObjectInspector var _strutils = load('res://addons/gut/strutils.gd').new() var OneToMany = load('res://addons/gut/one_to_many.gd') const DEFAULT_ARGS = 'default_args' const NAME = 'name' const ARGS = 'args' var METHOD_FLAGS = { "METHOD_FLAG_NORMAL" : METHOD_FLAG_NORMAL, "METHOD_FLAG_EDITOR" : METHOD_FLAG_EDITOR, "METHOD_FLAG_CONST" : METHOD_FLAG_CONST, "METHOD_FLAG_VIRTUAL" : METHOD_FLAG_VIRTUAL, "METHOD_FLAG_VARARG" : METHOD_FLAG_VARARG, "METHOD_FLAG_STATIC" : METHOD_FLAG_STATIC, "METHOD_FLAG_OBJECT_CORE" : METHOD_FLAG_OBJECT_CORE, "METHOD_FLAG_VIRTUAL_REQUIRED" : METHOD_FLAG_VIRTUAL_REQUIRED, "METHOD_FLAGS_DEFAULT" : METHOD_FLAGS_DEFAULT, } var PROPERTY_USAGES = { 'PROPERTY_USAGE_NONE' : PROPERTY_USAGE_NONE, 'PROPERTY_USAGE_STORAGE' : PROPERTY_USAGE_STORAGE, 'PROPERTY_USAGE_EDITOR' : PROPERTY_USAGE_EDITOR, 'PROPERTY_USAGE_INTERNAL' : PROPERTY_USAGE_INTERNAL, 'PROPERTY_USAGE_CHECKABLE' : PROPERTY_USAGE_CHECKABLE, 'PROPERTY_USAGE_CHECKED' : PROPERTY_USAGE_CHECKED, 'PROPERTY_USAGE_GROUP' : PROPERTY_USAGE_GROUP, 'PROPERTY_USAGE_CATEGORY' : PROPERTY_USAGE_CATEGORY, 'PROPERTY_USAGE_SUBGROUP' : PROPERTY_USAGE_SUBGROUP, 'PROPERTY_USAGE_CLASS_IS_BITFIELD' : PROPERTY_USAGE_CLASS_IS_BITFIELD, 'PROPERTY_USAGE_NO_INSTANCE_STATE' : PROPERTY_USAGE_NO_INSTANCE_STATE, 'PROPERTY_USAGE_RESTART_IF_CHANGED' : PROPERTY_USAGE_RESTART_IF_CHANGED, 'PROPERTY_USAGE_SCRIPT_VARIABLE' : PROPERTY_USAGE_SCRIPT_VARIABLE, 'PROPERTY_USAGE_STORE_IF_NULL' : PROPERTY_USAGE_STORE_IF_NULL, 'PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED' : PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED, 'PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE' : PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE, 'PROPERTY_USAGE_CLASS_IS_ENUM' : PROPERTY_USAGE_CLASS_IS_ENUM, 'PROPERTY_USAGE_NIL_IS_VARIANT' : PROPERTY_USAGE_NIL_IS_VARIANT, 'PROPERTY_USAGE_ARRAY' : PROPERTY_USAGE_ARRAY, 'PROPERTY_USAGE_ALWAYS_DUPLICATE' : PROPERTY_USAGE_ALWAYS_DUPLICATE, 'PROPERTY_USAGE_NEVER_DUPLICATE' : PROPERTY_USAGE_NEVER_DUPLICATE, 'PROPERTY_USAGE_HIGH_END_GFX' : PROPERTY_USAGE_HIGH_END_GFX, 'PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT' : PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT, 'PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT' : PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT, 'PROPERTY_USAGE_KEYING_INCREMENTS' : PROPERTY_USAGE_KEYING_INCREMENTS, 'PROPERTY_USAGE_DEFERRED_SET_RESOURCE' : PROPERTY_USAGE_DEFERRED_SET_RESOURCE, 'PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT' : PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT, 'PROPERTY_USAGE_EDITOR_BASIC_SETTING' : PROPERTY_USAGE_EDITOR_BASIC_SETTING, 'PROPERTY_USAGE_READ_ONLY' : PROPERTY_USAGE_READ_ONLY, 'PROPERTY_USAGE_SECRET' : PROPERTY_USAGE_SECRET, 'PROPERTY_USAGE_DEFAULT' : PROPERTY_USAGE_DEFAULT, 'PROPERTY_USAGE_NO_EDITOR' : PROPERTY_USAGE_NO_EDITOR, } var VARIANT_TYPE = { TYPE_NIL : 'TYPE_NIL', TYPE_BOOL : 'TYPE_BOOL', TYPE_INT : 'TYPE_INT', TYPE_FLOAT : 'TYPE_FLOAT', TYPE_STRING : 'TYPE_STRING', TYPE_VECTOR2 : 'TYPE_VECTOR2', TYPE_VECTOR2I : 'TYPE_VECTOR2I', TYPE_RECT2 : 'TYPE_RECT2', TYPE_RECT2I : 'TYPE_RECT2I', TYPE_VECTOR3 : 'TYPE_VECTOR3', TYPE_VECTOR3I : 'TYPE_VECTOR3I', TYPE_TRANSFORM2D : 'TYPE_TRANSFORM2D', TYPE_VECTOR4 : 'TYPE_VECTOR4', TYPE_VECTOR4I : 'TYPE_VECTOR4I', TYPE_PLANE : 'TYPE_PLANE', TYPE_QUATERNION : 'TYPE_QUATERNION', TYPE_AABB : 'TYPE_AABB', TYPE_BASIS : 'TYPE_BASIS', TYPE_TRANSFORM3D : 'TYPE_TRANSFORM3D', TYPE_PROJECTION : 'TYPE_PROJECTION', TYPE_COLOR : 'TYPE_COLOR', TYPE_STRING_NAME : 'TYPE_STRING_NAME', TYPE_NODE_PATH : 'TYPE_NODE_PATH', TYPE_RID : 'TYPE_RID', TYPE_OBJECT : 'TYPE_OBJECT', TYPE_CALLABLE : 'TYPE_CALLABLE', TYPE_SIGNAL : 'TYPE_SIGNAL', TYPE_DICTIONARY : 'TYPE_DICTIONARY', TYPE_ARRAY : 'TYPE_ARRAY', TYPE_PACKED_BYTE_ARRAY : 'TYPE_PACKED_BYTE_ARRAY', TYPE_PACKED_INT32_ARRAY : 'TYPE_PACKED_INT32_ARRAY', TYPE_PACKED_INT64_ARRAY : 'TYPE_PACKED_INT64_ARRAY', TYPE_PACKED_FLOAT32_ARRAY : 'TYPE_PACKED_FLOAT32_ARRAY', TYPE_PACKED_FLOAT64_ARRAY : 'TYPE_PACKED_FLOAT64_ARRAY', TYPE_PACKED_STRING_ARRAY : 'TYPE_PACKED_STRING_ARRAY', TYPE_PACKED_VECTOR2_ARRAY : 'TYPE_PACKED_VECTOR2_ARRAY', TYPE_PACKED_VECTOR3_ARRAY : 'TYPE_PACKED_VECTOR3_ARRAY', TYPE_PACKED_COLOR_ARRAY : 'TYPE_PACKED_COLOR_ARRAY', TYPE_PACKED_VECTOR4_ARRAY : 'TYPE_PACKED_VECTOR4_ARRAY', TYPE_MAX : 'TYPE_MAX', } # func get_methods_by_flag(obj): # var methods_by_flags = {} # var methods = obj.get_method_list() # for i in range(methods.size()): # var flag = methods[i]['flags'] # var name = methods[i]['name'] # if(methods_by_flags.has(flag)): # methods_by_flags[flag].append(name) # else: # methods_by_flags[flag] = [name] # return methods_by_flags # func print_methods_by_flags(methods_by_flags): # for flag in methods_by_flags: # for i in range(methods_by_flags[flag].size()): # print(flag, ": ", methods_by_flags[flag][i]) # var total = 0 # for flag in methods_by_flags: # if(methods_by_flags[flag].size() > 0): # print("-- ", flag, " (", methods_by_flags[flag].size(), ") --") # total += methods_by_flags[flag].size() # print("Total: ", total) # func print_methods_with_defaults(thing): # print('------------------------------------------------------------------') # print('--- Methods (object) ---') # print('------------------------------------------------------------------') # var methods = thing.get_method_list() # for m in methods: # if(m.default_args.size() > 0): # print(m.name) # pp(m, ' ') # print('------------------------------------------------------------------') # print('--- Methods (script) ---') # print('------------------------------------------------------------------') # methods = thing.get_script_method_list() # for m in methods: # print(m.name) # pp(m, ' ') # func print_methods_with_flags(obj, flags, print_all = true): # var methods = obj.get_method_list() # for i in range(methods.size()): # var mflags = methods[i]['flags'] # if(is_flagged(mflags, flags)): # print(methods[i]['name'], ':', mflags) # print_method_flags(mflags, print_all) # func print_methods_named(obj, name): # var methods = obj.get_method_list() # for i in range(methods.size()): # if(methods[i]['name'] == name): # print(methods[i]['name'], ':') # print_method_flags(methods[i]['flags'], false) # func subtract_dictionary(sub_this, from_this): # var result = {} # for key in sub_this: # if(from_this.has(key)): # result[key] = [] # for value in from_this[key]: # var index = sub_this[key].find(value) # if(index == -1): # result[key].append(value) # return result # func is_flagged(mask, index): # return mask & index != 0 # func print_flag(name, flags, flag, print_all=true): # var is_set = is_flagged(flags, flag) # if(print_all or is_set): # print(name,'(', flag, ') = ', is_set) # func print_method_flags(flags, print_all=true): # print_flag(' normal', flags, METHOD_FLAG_NORMAL, print_all) # print_flag(' editor', flags, METHOD_FLAG_EDITOR, print_all) # print_flag(' const', flags, METHOD_FLAG_CONST, print_all) # print_flag(' virtual', flags, METHOD_FLAG_VIRTUAL, print_all) # print_flag(' vararg', flags, METHOD_FLAG_VARARG, print_all) # print_flag(' static', flags, METHOD_FLAG_STATIC, print_all) # print_flag(' core', flags, METHOD_FLAG_OBJECT_CORE, print_all) # print_flag(' default', flags, METHOD_FLAGS_DEFAULT, print_all) # func print_method_info(obj): # var methods = obj.get_method_list() # for i in range(methods.size()): # print(methods[i]['name'], ' ', methods[i]['flags']) # # if(methods[i]['default_args'].size() > 0): # # print(" *** here be defaults ***") # print_method_flags(methods[i]['flags'], false) # # if(methods[i]['flags'] == 65): # # for key in methods[i]: # # if(key == 'args'): # # print(' args:') # # for argname in range(methods[i][key].size()): # # print(' ', methods[i][key][argname]['name'], ': ', methods[i][key][argname]) # # else: # # print(' ', key, ': ', methods[i][key]) # func get_defaults_and_types(method_meta): # var text = "" # text += method_meta[NAME] + "\n" # for i in range(method_meta[DEFAULT_ARGS].size()): # var arg_index = method_meta[ARGS].size() - (method_meta[DEFAULT_ARGS].size() - i) # text += str(' ', method_meta[ARGS][arg_index][NAME]) # text += str('(type=', method_meta[ARGS][arg_index]['type'], ")") # text += str(' = ', method_meta[DEFAULT_ARGS][i], "\n") # # text += str(' ', method_meta[ARGS][arg_index]['usage'], "\n") # return text # func class_db_stuff(): # print(ClassDB.class_exists('Node2D')) # # print('category = ', ClassDB.('Node2D')) # # print(str(JSON.print(ClassDB.class_get_method_list('Node2D'), ' '))) # # print(ClassDB.class_get_integer_constant_list('Node2D')) # print(ClassDB.get_class_list()) # func does_inherit_from_test(thing): # var base_script = thing.get_base_script() # var to_return = false # print(' *base_script = ', base_script) # if(base_script != null): # var base_path = base_script.get_path() # print(' *base_path = ', base_path) # if(base_path == 'res://addons/gut/test.gd'): # to_return = true # else: # to_return = does_inherit_from_test(base_script) # return to_return # func print_inner_test_classes(loaded, from=null): # # print('path = ', loaded.get_path()) # # if(loaded.get_base_script() != null): # # print('base = ', loaded.get_base_script().get_path()) # # else: # # print('base = ') # var const_map = loaded.get_script_constant_map() # for key in const_map: # var thing = const_map[key] # if(typeof(thing) == TYPE_OBJECT): # print('Class ', key, ':') # if(does_inherit_from_test(thing)): # print(' is a test class') # else: # print(' noooooooooope') # var next_from # if(from == null): # next_from = key # else: # next_from = str(from, '/', key) # print_inner_test_classes(thing, next_from) # else: # print('CONST ', key, ' = ', thing) # func print_script_methods(): # var script = load('res://tests_4_0/test_print.gd') # var methods = script.get_script_method_list() # for i in range(methods.size()): # print(methods[i]['name']) # pp(methods[i]) # func print_methods(methods, print_all_meta = false): # var methods_by_name = {} # var method_names = [] # for method in methods: # methods_by_name[method.name] = method # method_names.append(method.name) # method_names.sort() # for m_name in method_names: # print(m_name) # if(print_all_meta): # pp(methods_by_name[m_name], ' ') # func print_script_info(thing): # print('path = ', thing.get_path()) # print('--- Methods (script) ---') # print_methods(thing.get_script_method_list(), true) # print('--- Properties (script) ---') # var props = thing.get_script_property_list() # print_properties(props, thing, true) # print('--- Constants ---') # pp(thing.get_script_constant_map()) # print('--- Signals ---') # var sigs = thing.get_signal_list() # for sig in sigs: # print(sig['name']) # print(' ', sig) # func print_all_info(thing): # print('path = ', thing.get_path()) # print('--- Methods (object) ---') # print_methods(thing.get_method_list(), true) # print('--- Methods (script) ---') # print_methods(thing.get_script_method_list(), true) # print('--- Properties (object) ---') # var props = thing.get_property_list() # print_properties(props, thing) # print('--- Properties (script) ---') # props = thing.get_script_property_list() # print_properties(props, thing, true) # print('--- Constants ---') # print_inner_test_classes(thing) # print('--- Signals ---') # var sigs = thing.get_signal_list() # for sig in sigs: # print(sig['name']) # print(' ', sig) # func pp(dict, indent=''): # var text = json.stringify(dict, ' ') # text = _strutils.indent_text(text, 1, indent) # print(text) # # func has_script_method(Class): # # var methods = Class.get_script_method_list() # func print_inner_classes(loaded, parent=''): # var const_map = loaded.get_script_constant_map() # for key in const_map: # var thing = const_map[key] # if(typeof(thing) == TYPE_OBJECT): # print(parent, key, ': ', thing) # print_inner_classes(thing, key + '.') # func print_inner_class_path(loaded): # pass # func print_scene_info(scene): # pp(scene._bundled) # var state = scene.get_state() # print('state = ', state) # print('nodes = ', state.get_node_count()) # for i in range(state.get_node_count()): # print(i, '. ', state.get_node_name(i)) # print(' type ', state.get_node_type(i)) # print(' node index ', state.get_node_index(i)) # print(' #props ', state.get_node_property_count(i)) # print(' is placehodler ', state.is_node_instance_placeholder(i)) # print(' node path ', state.get_node_path(i)) # print(' groups ', state.get_node_groups(i)) # print(" properties:") # for j in range(state.get_node_property_count(i)): # var n = state.get_node_property_name(i, j) # var v = state.get_node_property_value(i, j) # print(' - ', n, ' = ', v) # func get_scene_script_object(scene): # return GutUtils.get_scene_script_object(scene) var include_native = false var include_method_flags = false var include_property_usage = false var include_meta = false var pretty_meta = false var lgr = load("res://addons/gut/logger.gd").new() func _print_meta(meta): if(include_meta): if(pretty_meta): var text = JSON.stringify(meta, ' ') lgr.p(text) else: lgr.p(meta) func _print_bit_mask(mask_name, mask_value, flags): lgr.p(mask_name, '(', mask_value, ')') lgr.inc_indent() for key in flags: var flag = flags[key] if(mask_value & flag): lgr.p('- ', key, ' ', flag) lgr.dec_indent() func print_class_db_class_list(): var list = ClassDB.get_class_list() list.sort() print("\n".join(list)) func print_script_constants(loaded): if(!loaded.has_method("get_script_constant_map")): print(loaded, ' does not have get_script_constant_map') return var const_map = loaded.get_script_constant_map() for key in const_map: var thing = const_map[key] lgr.p(key, ' = ', thing) if(typeof(thing) == TYPE_OBJECT): pass func print_properties(props, thing): for i in range(props.size()): var prop_name = props[i].name var prop_value = thing.get(props[i].name) var print_value = str(prop_value) if(print_value.length() > 100): print_value = print_value.substr(0, 97) + '...' elif(print_value == ''): print_value = 'EMPTY' lgr.p('* ', prop_name, ' = ', print_value) if(include_property_usage): lgr.inc_indent() _print_bit_mask('usage', props[i].usage, PROPERTY_USAGES) lgr.dec_indent() _print_meta(props[i]) func print_method_signature(meta): var s = str(meta.name, '(') var args = [] for arg in meta.args: args.append(arg.name) var return_text = "" if(meta["return"]["type"] != TYPE_NIL): return_text = str(" -> ", VARIANT_TYPE[meta["return"]["type"]]) s += ", ".join(args) s += ")" s += return_text lgr.p("* ", s) if(include_method_flags): lgr.inc_indent() _print_bit_mask('flags', meta.flags, METHOD_FLAGS) lgr.dec_indent() _print_meta(meta) func print_method_signatures(thing): var meta = thing if(typeof(thing) != TYPE_ARRAY): meta = thing.get_method_list() if(thing.has_method('get_script_method_list')): meta.append_array(thing.get_script_method_list()) var methods = OneToMany.new() methods.ignore_many_dupes = false for entry in meta: methods.add(entry.name, entry) var sorted = methods.items.keys() sorted.sort() for key in sorted: for entry in methods.items[key]: print_method_signature(entry) if(typeof(thing) != TYPE_ARRAY): if(thing.has_method('get_script_method_list')): print_method_signatures(thing.get_script_method_list()) func print_script_info(loaded): lgr.p('to_string ', loaded.to_string()) if(!is_singleton(loaded)): lgr.p('resource_name ', loaded.resource_name) lgr.p("resource_path ", loaded.resource_path) lgr.p('base_script ', loaded.get_base_script()) lgr.p('global_name ', loaded.get_global_name()) lgr.p('is_abstract ', loaded.is_abstract()) lgr.p('is_tool ', loaded.is_tool()) lgr.p('has_source_code ', loaded.has_source_code()) lgr.p("is_built_in ", loaded.is_built_in()) lgr.p('class ', loaded.get_class()) lgr.p('script ', loaded.get_script()) func print_native_class(which): lgr.p("Native Methods"); lgr.inc_indent() print_method_signatures(which.get_method_list()) lgr.dec_indent() func print_script(loaded, title =''): if(title != ''): lgr.p("---------------------") lgr.p(title) lgr.p("---------------------") if(GutUtils.is_native_class(loaded)): print_native_class(loaded) return lgr.p("- General Info");lgr.inc_indent() print_script_info(loaded) lgr.dec_indent() if(include_native): lgr.p("Native Methods"); lgr.inc_indent() print_method_signatures(loaded.get_method_list()) lgr.dec_indent() lgr.p("- Methods"); lgr.inc_indent() print_method_signatures(loaded.get_script_method_list()) lgr.dec_indent() if(include_native): lgr.p("- Native Properties"); lgr.inc_indent() print_properties(loaded.get_property_list(), loaded) lgr.dec_indent() lgr.p("- Properties");lgr.inc_indent() print_properties(loaded.get_script_property_list(), loaded) lgr.dec_indent() lgr.p("- Constants");lgr.inc_indent() print_script_constants(loaded) lgr.dec_indent() func print_script_verbose(loaded): lgr.p("Methods"); lgr.inc_indent() GutUtils.pretty_print(loaded.get_script_method_list()) lgr.dec_indent() lgr.p("Properties");lgr.inc_indent() GutUtils.pretty_print(loaded.get_script_property_list()) lgr.dec_indent() func is_singleton(thing): # return true # print(thing.has_method('get_base_script')) # print(ClassDB.can_instantiate(thing.get_class())) return thing.get_script() == null and !thing.has_method('get_base_script') class ClassDBInspector: extends ObjectInspector func print_properties(props, thing): for i in range(props.size()): var prop_name = props[i].name var prop_value = ClassDB.class_get_property(thing, props[i].name) var print_value = str(prop_value) if(print_value.length() > 100): print_value = print_value.substr(0, 97) + '...' elif(print_value == ''): print_value = 'EMPTY' lgr.p('* ', prop_name, ' = ', print_value) if(include_property_usage): lgr.inc_indent() _print_bit_mask('usage', props[i].usage, PROPERTY_USAGES) lgr.dec_indent() _print_meta(props[i]) func print_method_signatures(sname): super.print_method_signatures(ClassDB.class_get_method_list(sname, true))