Features: - Fuzzy search for finding destination rooms - Lists all TransitionPieces in selected room as arrival points - Bidirectional wiring - updates return transition automatically - Auto-reloads destination scene in editor - UndoRedo support for source scene changes Files added: - addons/transition_configurator/plugin.cfg - addons/transition_configurator/transition_configurator.gd - addons/transition_configurator/transition_inspector_plugin.gd - addons/transition_configurator/config_dialog.gd - addons/transition_configurator/fuzzy_search.gd - addons/transition_configurator/README.md
65 lines
1.8 KiB
GDScript
65 lines
1.8 KiB
GDScript
extends RefCounted
|
|
class_name FuzzySearch
|
|
|
|
## Simple fuzzy matching algorithm for text search
|
|
## Returns a score between 0 (no match) and 1 (perfect match)
|
|
|
|
static func match(query: String, target: String) -> float:
|
|
if query.is_empty():
|
|
return 1.0
|
|
|
|
query = query.to_lower()
|
|
target = target.to_lower()
|
|
|
|
# Exact match
|
|
if target == query:
|
|
return 1.0
|
|
|
|
# Contains query as substring
|
|
if target.find(query) != -1:
|
|
return 0.9
|
|
|
|
# Fuzzy match - all characters in query must appear in order in target
|
|
var query_idx: int = 0
|
|
var target_idx: int = 0
|
|
var matches: int = 0
|
|
var consecutive_bonus: float = 0.0
|
|
var last_match_idx: int = -1
|
|
|
|
while query_idx < query.length() and target_idx < target.length():
|
|
if query[query_idx] == target[target_idx]:
|
|
matches += 1
|
|
if last_match_idx != -1 and target_idx == last_match_idx + 1:
|
|
consecutive_bonus += 0.1
|
|
last_match_idx = target_idx
|
|
query_idx += 1
|
|
target_idx += 1
|
|
|
|
# All characters matched
|
|
if query_idx == query.length():
|
|
var base_score: float = float(matches) / float(query.length())
|
|
var bonus: float = min(consecutive_bonus, 0.3) # Cap bonus at 0.3
|
|
return base_score * 0.7 + bonus
|
|
|
|
return 0.0
|
|
|
|
## Sort an array of items by fuzzy match score
|
|
## items should be Dictionary with at least a "name" or specified key field
|
|
static func sort_by_match(query: String, items: Array, key: String = "name") -> Array:
|
|
if query.is_empty():
|
|
return items.duplicate()
|
|
|
|
var scored: Array[Dictionary] = []
|
|
for item in items:
|
|
var item_name: String = item.get(key, "")
|
|
var score: float = match(query, item_name)
|
|
if score > 0:
|
|
scored.append({"item": item, "score": score})
|
|
|
|
# Sort by score descending
|
|
scored.sort_custom(func(a: Dictionary, b: Dictionary) -> bool:
|
|
return a["score"] > b["score"]
|
|
)
|
|
|
|
return scored.map(func(s): return s["item"])
|