gdharness 0.10.2 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -52,12 +52,20 @@ func get_tree(params: Dictionary) -> Dictionary:
52
52
  ## rebuilds between them, which any HUD following a clock does, hands back paths that are gone by
53
53
  ## the time they are asked about. A node without that property says so rather than answering null,
54
54
  ## because null is what a node holding null answers.
55
+ ##
56
+ ## `include_hidden` defaults to true, because a find is a question about the tree and a caller
57
+ ## naming a class or a group means the node whether or not it is on screen. Passing false asks the
58
+ ## other question, the one a screen is checked against: a panel that keeps a label for every line
59
+ ## that might apply and hides the ones that do not answers with what the player is reading, rather
60
+ ## than with every line it is holding in case. How many matches that left out is counted and said,
61
+ ## because "none" and "four, all hidden" are different answers and used to read the same.
55
62
  func find_nodes(params: Dictionary) -> Dictionary:
56
63
  var root_path: String = str(params.get("root", "/root"))
57
64
  var wanted: Dictionary[String, String] = {}
58
65
  for filter: String in FILTERS:
59
66
  wanted[filter] = str(params.get(filter, ""))
60
67
  var wanted_property: String = str(params.get("property", ""))
68
+ var include_hidden: bool = bool(params.get("include_hidden", true))
61
69
  var limit: int = clampi(int(params.get("limit", FIND_LIMIT)), 1, FIND_LIMIT_CEILING)
62
70
 
63
71
  if not _anything_asked(wanted):
@@ -77,14 +85,18 @@ func find_nodes(params: Dictionary) -> Dictionary:
77
85
  # find would have matched if the name had been read the way it was probably meant.
78
86
  var literal: bool = _is_literal(wanted["name"])
79
87
  var nearly: int = 0
88
+ var hidden: int = 0
80
89
  while not pending.is_empty():
81
90
  var node: Node = pending.pop_front()
82
91
  var rest: bool = _matches_apart_from_name(node, wanted)
83
92
  if rest and _named(node, wanted["name"]):
84
- if found.size() >= limit:
93
+ if not include_hidden and not _shown(node):
94
+ hidden += 1
95
+ elif found.size() >= limit:
85
96
  truncated = true
86
97
  break
87
- found.append(_found(node, wanted_property))
98
+ else:
99
+ found.append(_found(node, wanted_property))
88
100
  elif rest and literal and str(node.name).containsn(wanted["name"]):
89
101
  nearly += 1
90
102
  # Internal children included, which they were not. A ConfirmationDialog builds its Yes and
@@ -98,18 +110,49 @@ func find_nodes(params: Dictionary) -> Dictionary:
98
110
  pending.push_front(children[index])
99
111
 
100
112
  var answer: Dictionary = {"type": "nodes", "count": found.size(), "truncated": truncated, "nodes": found}
113
+ var notes: PackedStringArray = []
101
114
  # Nothing found is the one answer that cannot be told apart from having asked the wrong
102
115
  # question, and a name written without a wildcard is the way an agent writes "contains".
103
116
  # Said only when it changes the answer, so a genuine nothing stays a plain nothing.
104
117
  if found.is_empty() and nearly > 0:
105
118
  var holding: String = "names contain" if nearly > 1 else "name contains"
106
- answer["note"] = (
107
- 'name is matched as a glob against the whole name; %d node %s "%s", which "*%s*" would find'
108
- % [nearly, holding, wanted["name"], wanted["name"]]
119
+ notes.append(
120
+ (
121
+ 'name is matched as a glob against the whole name; %d node %s "%s", which "*%s*" would find'
122
+ % [nearly, holding, wanted["name"], wanted["name"]]
123
+ )
124
+ )
125
+ # How many the filter took out, so a short answer is not read as a small screen. Left out
126
+ # entirely when nothing was hidden, which keeps a plain answer plain.
127
+ if hidden > 0:
128
+ answer["hidden"] = hidden
129
+ notes.append(
130
+ (
131
+ "%d matching node%s hidden and left out; includeHidden true answers with them too"
132
+ % [hidden, "" if hidden == 1 else "s"]
133
+ )
109
134
  )
135
+ if not notes.is_empty():
136
+ answer["note"] = " ".join(notes)
110
137
  return answer
111
138
 
112
139
 
140
+ ## Whether the player can see [param node], its ancestors counted.
141
+ ##
142
+ ## Not [method CanvasItem.is_visible_in_tree] on its own, because only the nodes that draw have it:
143
+ ## a plain Node sitting between a hidden panel and a label has no visibility to ask about, and the
144
+ ## label answers that it is visible while nothing of it is on screen. Walking up is what makes a
145
+ ## row hidden because the panel holding it is hidden, which is what somebody checking a screen is
146
+ ## asking about.
147
+ static func _shown(node: Node) -> bool:
148
+ var walk: Node = node
149
+ while walk != null:
150
+ if not _drawn(walk):
151
+ return false
152
+ walk = walk.get_parent()
153
+ return true
154
+
155
+
113
156
  ## One match, with the named property on it when one was named.
114
157
  ##
115
158
  ## `has_property` alongside the value, because a node that has not got it and a node holding null
@@ -262,11 +305,18 @@ func _read_into(node: Node, include_hidden: bool, most: int, into: PackedStringA
262
305
  _read_into(child, include_hidden, most, into)
263
306
 
264
307
 
265
- ## Whether [param node] is on the screen at all, for the two kinds of thing that can be hidden.
308
+ ## Whether [param node] is on the screen at all, for the three kinds of thing that can be hidden.
309
+ ##
310
+ ## A Node3D among them because a hidden one draws nothing, Label3D included: reading a screen or
311
+ ## finding what is on it counted a hidden 3D subtree as showing, which is the one answer neither
312
+ ## question wants.
266
313
  static func _drawn(node: Node) -> bool:
267
314
  var control: CanvasItem = node as CanvasItem
268
315
  if control != null:
269
316
  return control.visible
317
+ var spatial: Node3D = node as Node3D
318
+ if spatial != null:
319
+ return spatial.visible
270
320
  var window: Window = node as Window
271
321
  return window == null or window.visible
272
322