utils.notest.gd 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. @warning_ignore_start("unsafe_call_argument")
  2. class_name Utils
  3. # `assert()` is not evaluated in non-debug builds. Do not use `assert()`
  4. # for anything other than testing the `assert()` itself.
  5. static func check(condition: Variant) -> void:
  6. if condition:
  7. return
  8. printerr("Check failed. Backtrace (most recent call first):")
  9. for stack: ScriptBacktrace in Engine.capture_script_backtraces():
  10. if stack.get_language_name() == "GDScript":
  11. var dir: String
  12. for i: int in stack.get_frame_count():
  13. if i == 0:
  14. dir = stack.get_frame_file(i).trim_suffix("utils.notest.gd")
  15. else:
  16. printerr(" %s:%d @ %s()" % [
  17. stack.get_frame_file(i).trim_prefix(dir),
  18. stack.get_frame_line(i),
  19. stack.get_frame_function(i),
  20. ])
  21. break
  22. static func get_type(property: Dictionary, is_return: bool = false) -> String:
  23. match property.type:
  24. TYPE_NIL:
  25. if property.usage & PROPERTY_USAGE_NIL_IS_VARIANT:
  26. return "Variant"
  27. return "void" if is_return else "null"
  28. TYPE_INT:
  29. if property.usage & PROPERTY_USAGE_CLASS_IS_ENUM:
  30. if property.class_name == &"":
  31. return "<unknown enum>"
  32. return property.class_name
  33. TYPE_ARRAY:
  34. if property.hint == PROPERTY_HINT_ARRAY_TYPE:
  35. if str(property.hint_string).is_empty():
  36. return "Array[<unknown type>]"
  37. return "Array[%s]" % property.hint_string
  38. TYPE_DICTIONARY:
  39. if property.hint == PROPERTY_HINT_DICTIONARY_TYPE:
  40. if str(property.hint_string).is_empty():
  41. return "Dictionary[<unknown type>, <unknown type>]"
  42. return "Dictionary[%s]" % str(property.hint_string).replace(";", ", ")
  43. TYPE_OBJECT:
  44. if not str(property.class_name).is_empty():
  45. return property.class_name
  46. return type_string(property.type)
  47. static func get_property_signature(
  48. property: Dictionary,
  49. base: Object = null,
  50. is_static: bool = false,
  51. ) -> String:
  52. if property.usage & PROPERTY_USAGE_CATEGORY:
  53. return '@export_category("%s")' % str(property.name).c_escape()
  54. if property.usage & PROPERTY_USAGE_GROUP:
  55. return '@export_group("%s")' % str(property.name).c_escape()
  56. if property.usage & PROPERTY_USAGE_SUBGROUP:
  57. return '@export_subgroup("%s")' % str(property.name).c_escape()
  58. var result: String = ""
  59. if not (property.usage & PROPERTY_USAGE_SCRIPT_VARIABLE):
  60. printerr("Missing `PROPERTY_USAGE_SCRIPT_VARIABLE` flag.")
  61. if is_static:
  62. result += "static "
  63. result += "var " + property.name + ": " + get_type(property)
  64. if is_instance_valid(base):
  65. result += " = " + var_to_str(base.get(property.name))
  66. return result
  67. static func get_human_readable_hint_string(property: Dictionary) -> String:
  68. if property.type >= TYPE_ARRAY and property.hint == PROPERTY_HINT_TYPE_STRING:
  69. var type_hint_prefixes: String = ""
  70. var hint_string: String = property.hint_string
  71. while true:
  72. if not hint_string.contains(":"):
  73. printerr("Invalid PROPERTY_HINT_TYPE_STRING format.")
  74. var elem_type_hint: String = hint_string.get_slice(":", 0)
  75. hint_string = hint_string.substr(elem_type_hint.length() + 1)
  76. var elem_type: int
  77. var elem_hint: int
  78. if elem_type_hint.is_valid_int():
  79. elem_type = elem_type_hint.to_int()
  80. type_hint_prefixes += "<%s>:" % type_string(elem_type)
  81. else:
  82. if elem_type_hint.count("/") != 1:
  83. printerr("Invalid PROPERTY_HINT_TYPE_STRING format.")
  84. elem_type = elem_type_hint.get_slice("/", 0).to_int()
  85. elem_hint = elem_type_hint.get_slice("/", 1).to_int()
  86. type_hint_prefixes += "<%s>/<%s>:" % [
  87. type_string(elem_type),
  88. get_property_hint_name(elem_hint).trim_prefix("PROPERTY_HINT_"),
  89. ]
  90. if elem_type < TYPE_ARRAY or hint_string.is_empty():
  91. break
  92. return type_hint_prefixes + hint_string
  93. return property.hint_string
  94. static func print_property_extended_info(
  95. property: Dictionary,
  96. base: Object = null,
  97. is_static: bool = false,
  98. ) -> void:
  99. print(get_property_signature(property, base, is_static))
  100. print(' hint=%s hint_string="%s" usage=%s class_name=&"%s"' % [
  101. get_property_hint_name(property.hint).trim_prefix("PROPERTY_HINT_"),
  102. get_human_readable_hint_string(property).c_escape(),
  103. get_property_usage_string(property.usage).replace("PROPERTY_USAGE_", ""),
  104. str(property.class_name).c_escape(),
  105. ])
  106. static func get_method_signature(method: Dictionary, is_signal: bool = false) -> String:
  107. var result: String = ""
  108. if method.flags & METHOD_FLAG_STATIC:
  109. result += "static "
  110. result += ("signal " if is_signal else "func ") + method.name + "("
  111. var args: Array[Dictionary] = method.args
  112. var default_args: Array = method.default_args
  113. var mandatory_argc: int = args.size() - default_args.size()
  114. for i: int in args.size():
  115. if i > 0:
  116. result += ", "
  117. var arg: Dictionary = args[i]
  118. result += arg.name + ": " + get_type(arg)
  119. if i >= mandatory_argc:
  120. result += " = " + var_to_str(default_args[i - mandatory_argc])
  121. result += ")"
  122. if is_signal:
  123. if get_type(method.return, true) != "void":
  124. printerr("Signal return type must be `void`.")
  125. else:
  126. result += " -> " + get_type(method.return, true)
  127. return result
  128. static func get_property_hint_name(hint: PropertyHint) -> String:
  129. match hint:
  130. PROPERTY_HINT_NONE:
  131. return "PROPERTY_HINT_NONE"
  132. PROPERTY_HINT_RANGE:
  133. return "PROPERTY_HINT_RANGE"
  134. PROPERTY_HINT_ENUM:
  135. return "PROPERTY_HINT_ENUM"
  136. PROPERTY_HINT_ENUM_SUGGESTION:
  137. return "PROPERTY_HINT_ENUM_SUGGESTION"
  138. PROPERTY_HINT_EXP_EASING:
  139. return "PROPERTY_HINT_EXP_EASING"
  140. PROPERTY_HINT_LINK:
  141. return "PROPERTY_HINT_LINK"
  142. PROPERTY_HINT_FLAGS:
  143. return "PROPERTY_HINT_FLAGS"
  144. PROPERTY_HINT_LAYERS_2D_RENDER:
  145. return "PROPERTY_HINT_LAYERS_2D_RENDER"
  146. PROPERTY_HINT_LAYERS_2D_PHYSICS:
  147. return "PROPERTY_HINT_LAYERS_2D_PHYSICS"
  148. PROPERTY_HINT_LAYERS_2D_NAVIGATION:
  149. return "PROPERTY_HINT_LAYERS_2D_NAVIGATION"
  150. PROPERTY_HINT_LAYERS_3D_RENDER:
  151. return "PROPERTY_HINT_LAYERS_3D_RENDER"
  152. PROPERTY_HINT_LAYERS_3D_PHYSICS:
  153. return "PROPERTY_HINT_LAYERS_3D_PHYSICS"
  154. PROPERTY_HINT_LAYERS_3D_NAVIGATION:
  155. return "PROPERTY_HINT_LAYERS_3D_NAVIGATION"
  156. PROPERTY_HINT_LAYERS_AVOIDANCE:
  157. return "PROPERTY_HINT_LAYERS_AVOIDANCE"
  158. PROPERTY_HINT_FILE:
  159. return "PROPERTY_HINT_FILE"
  160. PROPERTY_HINT_DIR:
  161. return "PROPERTY_HINT_DIR"
  162. PROPERTY_HINT_GLOBAL_FILE:
  163. return "PROPERTY_HINT_GLOBAL_FILE"
  164. PROPERTY_HINT_GLOBAL_DIR:
  165. return "PROPERTY_HINT_GLOBAL_DIR"
  166. PROPERTY_HINT_RESOURCE_TYPE:
  167. return "PROPERTY_HINT_RESOURCE_TYPE"
  168. PROPERTY_HINT_MULTILINE_TEXT:
  169. return "PROPERTY_HINT_MULTILINE_TEXT"
  170. PROPERTY_HINT_EXPRESSION:
  171. return "PROPERTY_HINT_EXPRESSION"
  172. PROPERTY_HINT_PLACEHOLDER_TEXT:
  173. return "PROPERTY_HINT_PLACEHOLDER_TEXT"
  174. PROPERTY_HINT_COLOR_NO_ALPHA:
  175. return "PROPERTY_HINT_COLOR_NO_ALPHA"
  176. PROPERTY_HINT_OBJECT_ID:
  177. return "PROPERTY_HINT_OBJECT_ID"
  178. PROPERTY_HINT_TYPE_STRING:
  179. return "PROPERTY_HINT_TYPE_STRING"
  180. PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE:
  181. return "PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE"
  182. PROPERTY_HINT_OBJECT_TOO_BIG:
  183. return "PROPERTY_HINT_OBJECT_TOO_BIG"
  184. PROPERTY_HINT_NODE_PATH_VALID_TYPES:
  185. return "PROPERTY_HINT_NODE_PATH_VALID_TYPES"
  186. PROPERTY_HINT_SAVE_FILE:
  187. return "PROPERTY_HINT_SAVE_FILE"
  188. PROPERTY_HINT_GLOBAL_SAVE_FILE:
  189. return "PROPERTY_HINT_GLOBAL_SAVE_FILE"
  190. PROPERTY_HINT_INT_IS_OBJECTID:
  191. return "PROPERTY_HINT_INT_IS_OBJECTID"
  192. PROPERTY_HINT_INT_IS_POINTER:
  193. return "PROPERTY_HINT_INT_IS_POINTER"
  194. PROPERTY_HINT_ARRAY_TYPE:
  195. return "PROPERTY_HINT_ARRAY_TYPE"
  196. PROPERTY_HINT_DICTIONARY_TYPE:
  197. return "PROPERTY_HINT_DICTIONARY_TYPE"
  198. PROPERTY_HINT_LOCALE_ID:
  199. return "PROPERTY_HINT_LOCALE_ID"
  200. PROPERTY_HINT_LOCALIZABLE_STRING:
  201. return "PROPERTY_HINT_LOCALIZABLE_STRING"
  202. PROPERTY_HINT_NODE_TYPE:
  203. return "PROPERTY_HINT_NODE_TYPE"
  204. PROPERTY_HINT_HIDE_QUATERNION_EDIT:
  205. return "PROPERTY_HINT_HIDE_QUATERNION_EDIT"
  206. PROPERTY_HINT_PASSWORD:
  207. return "PROPERTY_HINT_PASSWORD"
  208. PROPERTY_HINT_TOOL_BUTTON:
  209. return "PROPERTY_HINT_TOOL_BUTTON"
  210. printerr("Argument `hint` is invalid. Use `PROPERTY_HINT_*` constants.")
  211. return "<invalid hint>"
  212. static func get_property_usage_string(usage: int) -> String:
  213. if usage == PROPERTY_USAGE_NONE:
  214. return "PROPERTY_USAGE_NONE"
  215. const FLAGS: Array[Array] = [
  216. [PROPERTY_USAGE_STORAGE, "PROPERTY_USAGE_STORAGE"],
  217. [PROPERTY_USAGE_EDITOR, "PROPERTY_USAGE_EDITOR"],
  218. [PROPERTY_USAGE_INTERNAL, "PROPERTY_USAGE_INTERNAL"],
  219. [PROPERTY_USAGE_CHECKABLE, "PROPERTY_USAGE_CHECKABLE"],
  220. [PROPERTY_USAGE_CHECKED, "PROPERTY_USAGE_CHECKED"],
  221. [PROPERTY_USAGE_GROUP, "PROPERTY_USAGE_GROUP"],
  222. [PROPERTY_USAGE_CATEGORY, "PROPERTY_USAGE_CATEGORY"],
  223. [PROPERTY_USAGE_SUBGROUP, "PROPERTY_USAGE_SUBGROUP"],
  224. [PROPERTY_USAGE_CLASS_IS_BITFIELD, "PROPERTY_USAGE_CLASS_IS_BITFIELD"],
  225. [PROPERTY_USAGE_NO_INSTANCE_STATE, "PROPERTY_USAGE_NO_INSTANCE_STATE"],
  226. [PROPERTY_USAGE_RESTART_IF_CHANGED, "PROPERTY_USAGE_RESTART_IF_CHANGED"],
  227. [PROPERTY_USAGE_SCRIPT_VARIABLE, "PROPERTY_USAGE_SCRIPT_VARIABLE"],
  228. [PROPERTY_USAGE_STORE_IF_NULL, "PROPERTY_USAGE_STORE_IF_NULL"],
  229. [PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED, "PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED"],
  230. [PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE, "PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE"],
  231. [PROPERTY_USAGE_CLASS_IS_ENUM, "PROPERTY_USAGE_CLASS_IS_ENUM"],
  232. [PROPERTY_USAGE_NIL_IS_VARIANT, "PROPERTY_USAGE_NIL_IS_VARIANT"],
  233. [PROPERTY_USAGE_ARRAY, "PROPERTY_USAGE_ARRAY"],
  234. [PROPERTY_USAGE_ALWAYS_DUPLICATE, "PROPERTY_USAGE_ALWAYS_DUPLICATE"],
  235. [PROPERTY_USAGE_NEVER_DUPLICATE, "PROPERTY_USAGE_NEVER_DUPLICATE"],
  236. [PROPERTY_USAGE_HIGH_END_GFX, "PROPERTY_USAGE_HIGH_END_GFX"],
  237. [PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT, "PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT"],
  238. [PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT, "PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT"],
  239. [PROPERTY_USAGE_KEYING_INCREMENTS, "PROPERTY_USAGE_KEYING_INCREMENTS"],
  240. [PROPERTY_USAGE_DEFERRED_SET_RESOURCE, "PROPERTY_USAGE_DEFERRED_SET_RESOURCE"],
  241. [PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT, "PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT"],
  242. [PROPERTY_USAGE_EDITOR_BASIC_SETTING, "PROPERTY_USAGE_EDITOR_BASIC_SETTING"],
  243. [PROPERTY_USAGE_READ_ONLY, "PROPERTY_USAGE_READ_ONLY"],
  244. [PROPERTY_USAGE_SECRET, "PROPERTY_USAGE_SECRET"],
  245. ]
  246. var result: String = ""
  247. if (usage & PROPERTY_USAGE_DEFAULT) == PROPERTY_USAGE_DEFAULT:
  248. result += "PROPERTY_USAGE_DEFAULT|"
  249. usage &= ~PROPERTY_USAGE_DEFAULT
  250. for flag: Array in FLAGS:
  251. if usage & flag[0]:
  252. result += flag[1] + "|"
  253. usage &= ~flag[0]
  254. if usage != PROPERTY_USAGE_NONE:
  255. printerr("Argument `usage` is invalid. Use `PROPERTY_USAGE_*` constants.")
  256. return "<invalid usage flags>"
  257. return result.left(-1)