Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
NodeSearchPalette.cpp
Go to the documentation of this file.
1/**
2 * @file NodeSearchPalette.cpp
3 * @brief Fuzzy-search palette implementation (Phase 7).
4 * @author Olympe Engine
5 * @date 2026-03-10
6 */
7
8#include "NodeSearchPalette.h"
9
10#include <algorithm>
11#include <cctype>
12
13#include "../system/system_utils.h"
14
15namespace Olympe {
16
17// ============================================================================
18// Singleton
19// ============================================================================
20
22{
23 static NodeSearchPalette s_Instance;
24 return s_Instance;
25}
26
27// ============================================================================
28// Construction
29// ============================================================================
30
36
37// ============================================================================
38// Open / close
39// ============================================================================
40
42{
43 m_IsOpen = true;
44}
45
47{
48 m_IsOpen = false;
49}
50
52{
53 return m_IsOpen;
54}
55
56// ============================================================================
57// Catalog initialisation
58// ============================================================================
59
61{
62 m_NodeCatalog.clear();
63
64 // ---- Control Flow nodes ----
65 auto addCF = [this](const std::string& type, const std::string& display) {
67 r.typeName = type;
68 r.displayName = display;
70 r.score = 0;
71 m_NodeCatalog.push_back(r);
72 };
73
74 addCF("Sequence", "Sequence");
75 addCF("Selector", "Selector");
76 addCF("Branch", "Branch");
77 addCF("EntryPoint", "Entry Point");
78 addCF("SubGraph", "Sub Graph");
79 addCF("Repeat", "Repeat");
80 addCF("Wait", "Wait");
81
82 // ---- Action nodes ----
83 auto addAction = [this](const std::string& type, const std::string& display) {
85 r.typeName = type;
86 r.displayName = display;
88 r.score = 0;
89 m_NodeCatalog.push_back(r);
90 };
91
92 addAction("MoveToLocation", "Move To Location");
93 addAction("Attack", "Attack");
94 addAction("Flee", "Flee");
95 addAction("Patrol", "Patrol");
96 addAction("SetVariable", "Set Variable");
97 addAction("LogMessage", "Log Message");
98
99 // ---- Data nodes ----
100 auto addData = [this](const std::string& type, const std::string& display) {
102 r.typeName = type;
103 r.displayName = display;
104 r.category = NodeSearchCategory::Data;
105 r.score = 0;
106 m_NodeCatalog.push_back(r);
107 };
108
109 addData("GetVariable", "Get Variable");
110 addData("SetBlackboardKey", "Set Blackboard Key");
111
112 SYSTEM_LOG << "[NodeSearchPalette] Catalog initialised with "
113 << static_cast<int>(m_NodeCatalog.size()) << " node types."
114 << std::endl;
115}
116
117// ============================================================================
118// FuzzySearch
119// ============================================================================
120
121std::vector<NodeSearchResult> NodeSearchPalette::FuzzySearch(
122 const std::string& query,
124{
125 std::vector<NodeSearchResult> results;
126
127 for (size_t i = 0; i < m_NodeCatalog.size(); ++i)
128 {
130
131 if (filter != NodeSearchCategory::All && entry.category != filter)
132 continue;
133
134 int score = 0;
135
136 if (query.empty())
137 {
138 // Empty query — return everything with equal score
139 score = 1;
140 }
141 else
142 {
143 // Score against both typeName and displayName; take the higher
144 int s1 = ComputeFuzzyScore(query, entry.typeName);
145 int s2 = ComputeFuzzyScore(query, entry.displayName);
146 score = (s1 > s2) ? s1 : s2;
147 }
148
149 if (score > 0)
150 {
152 r.score = score;
153 results.push_back(r);
154 }
155 }
156
157 // Sort by score descending, then displayName ascending for stable order
158 std::sort(results.begin(), results.end(),
159 [](const NodeSearchResult& a, const NodeSearchResult& b) {
160 if (a.score != b.score)
161 return a.score > b.score;
162 return a.displayName < b.displayName;
163 });
164
165 return results;
166}
167
168// ============================================================================
169// ComputeFuzzyScore
170// ============================================================================
171
172static std::string ToLower(const std::string& s)
173{
174 std::string out = s;
175 for (size_t i = 0; i < out.size(); ++i)
176 out[i] = static_cast<char>(std::tolower(static_cast<unsigned char>(out[i])));
177 return out;
178}
179
181 const std::string& candidate)
182{
183 if (query.empty())
184 return 1;
185
186 const std::string q = ToLower(query);
187 const std::string c = ToLower(candidate);
188
189 if (c.empty())
190 return 0;
191
192 // Exact match
193 if (c == q)
194 return 1000;
195
196 // Prefix match
197 if (c.substr(0, q.size()) == q)
198 return 800;
199
200 // Substring match
201 if (c.find(q) != std::string::npos)
202 return 600;
203
204 // Scattered character match: every character in query appears in candidate
205 // in order. Score based on how close together the characters are.
206 size_t qi = 0;
207 size_t ci = 0;
208 int gaps = 0;
209
210 while (qi < q.size() && ci < c.size())
211 {
212 if (q[qi] == c[ci])
213 {
214 ++qi;
215 }
216 else
217 {
218 ++gaps;
219 }
220 ++ci;
221 }
222
223 if (qi == q.size())
224 {
225 // All characters matched; penalise by gap count
226 int score = 400 - gaps * 5;
227 return (score > 1) ? score : 1;
228 }
229
230 return 0;
231}
232
233// ============================================================================
234// GetAllNodes
235// ============================================================================
236
237const std::vector<NodeSearchResult>& NodeSearchPalette::GetAllNodes() const
238{
239 return m_NodeCatalog;
240}
241
242} // namespace Olympe
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
Fuzzy-search palette for VS node types (Phase 7).
Singleton fuzzy-search palette for VS node types.
std::vector< NodeSearchResult > m_NodeCatalog
static int ComputeFuzzyScore(const std::string &query, const std::string &candidate)
Computes a fuzzy match score between query and candidate.
std::vector< NodeSearchResult > FuzzySearch(const std::string &query, NodeSearchCategory filter=NodeSearchCategory::All)
Fuzzy-searches the node catalog.
static NodeSearchPalette & Get()
Returns the single shared instance.
const std::vector< NodeSearchResult > & GetAllNodes() const
Returns all node types in the catalog (unfiltered).
< Provides AssetID and INVALID_ASSET_ID
NodeSearchCategory
Broad category for filtering node search results.
static std::string ToLower(const std::string &s)
A single match returned by NodeSearchPalette::FuzzySearch().
std::string typeName
Internal type identifier (e.g. "Sequence")
int score
Fuzzy match score; higher = better.
#define SYSTEM_LOG