Skip to content

Commit 325f270

Browse files
authored
Refactor: move shared StateTree helpers into StateTreeHelpers namespace (#3)
Fixes C2084 duplicate-definition errors that surface under unity builds by consolidating ResolveSchemaClass and the four enum parsers into the existing StateTreeHelpers namespace. Also adds the TryFollowTransitions case to ParseSelectionBehavior.
1 parent f2ac694 commit 325f270

4 files changed

Lines changed: 203 additions & 365 deletions

File tree

Source/UnrealMCPBridge/Private/Commands/StateTree/StateTreeCreateOps.cpp

Lines changed: 5 additions & 184 deletions
Original file line numberDiff line numberDiff line change
@@ -186,185 +186,6 @@ static TSharedPtr<FJsonObject> NodeToJsonResult(const FStateTreeEditorNode& Node
186186
return Obj;
187187
}
188188

189-
/**
190-
* Resolve a UStateTreeSchema subclass by short name or full path.
191-
*/
192-
static UClass* ResolveSchemaClass(const FString& SchemaName, FString& OutError)
193-
{
194-
if (SchemaName.IsEmpty())
195-
{
196-
OutError = TEXT("Empty schema_class");
197-
return nullptr;
198-
}
199-
200-
// Try full path
201-
UClass* Found = FindObject<UClass>(nullptr, *SchemaName);
202-
if (Found && Found->IsChildOf(UStateTreeSchema::StaticClass()))
203-
{
204-
return Found;
205-
}
206-
207-
// Search by short name
208-
TArray<UClass*> Derived;
209-
GetDerivedClasses(UStateTreeSchema::StaticClass(), Derived, true);
210-
for (UClass* C : Derived)
211-
{
212-
if (!C || C->HasAnyClassFlags(CLASS_Abstract))
213-
{
214-
continue;
215-
}
216-
217-
const FString Name = C->GetName();
218-
if (Name == SchemaName ||
219-
Name == (TEXT("U") + SchemaName) ||
220-
(SchemaName.StartsWith(TEXT("U")) && Name == SchemaName.RightChop(1)))
221-
{
222-
return C;
223-
}
224-
}
225-
226-
OutError = FString::Printf(TEXT("Schema class not found: '%s'"), *SchemaName);
227-
return nullptr;
228-
}
229-
230-
/**
231-
* Parse an EStateTreeStateType from a string.
232-
*/
233-
static bool ParseStateType(const FString& Str, EStateTreeStateType& OutType)
234-
{
235-
if (Str.IsEmpty() || Str.Equals(TEXT("State"), ESearchCase::IgnoreCase))
236-
{
237-
OutType = EStateTreeStateType::State;
238-
return true;
239-
}
240-
if (Str.Equals(TEXT("Group"), ESearchCase::IgnoreCase))
241-
{
242-
OutType = EStateTreeStateType::Group;
243-
return true;
244-
}
245-
if (Str.Equals(TEXT("Linked"), ESearchCase::IgnoreCase))
246-
{
247-
OutType = EStateTreeStateType::Linked;
248-
return true;
249-
}
250-
if (Str.Equals(TEXT("LinkedAsset"), ESearchCase::IgnoreCase))
251-
{
252-
OutType = EStateTreeStateType::LinkedAsset;
253-
return true;
254-
}
255-
if (Str.Equals(TEXT("Subtree"), ESearchCase::IgnoreCase))
256-
{
257-
OutType = EStateTreeStateType::Subtree;
258-
return true;
259-
}
260-
return false;
261-
}
262-
263-
/**
264-
* Parse an EStateTreeStateSelectionBehavior from a string.
265-
*/
266-
static bool ParseSelectionBehavior(const FString& Str, EStateTreeStateSelectionBehavior& OutBehavior)
267-
{
268-
if (Str.Equals(TEXT("None"), ESearchCase::IgnoreCase))
269-
{
270-
OutBehavior = EStateTreeStateSelectionBehavior::None;
271-
return true;
272-
}
273-
if (Str.Equals(TEXT("TryEnterState"), ESearchCase::IgnoreCase) ||
274-
Str.Equals(TEXT("TryEnter"), ESearchCase::IgnoreCase))
275-
{
276-
OutBehavior = EStateTreeStateSelectionBehavior::TryEnterState;
277-
return true;
278-
}
279-
if (Str.Equals(TEXT("TrySelectChildrenInOrder"), ESearchCase::IgnoreCase))
280-
{
281-
OutBehavior = EStateTreeStateSelectionBehavior::TrySelectChildrenInOrder;
282-
return true;
283-
}
284-
if (Str.Equals(TEXT("TrySelectChildrenAtRandom"), ESearchCase::IgnoreCase))
285-
{
286-
OutBehavior = EStateTreeStateSelectionBehavior::TrySelectChildrenAtRandom;
287-
return true;
288-
}
289-
if (Str.Equals(TEXT("TrySelectChildrenWithHighestUtility"), ESearchCase::IgnoreCase))
290-
{
291-
OutBehavior = EStateTreeStateSelectionBehavior::TrySelectChildrenWithHighestUtility;
292-
return true;
293-
}
294-
if (Str.Equals(TEXT("TrySelectChildrenAtRandomWeightedByUtility"), ESearchCase::IgnoreCase))
295-
{
296-
OutBehavior = EStateTreeStateSelectionBehavior::TrySelectChildrenAtRandomWeightedByUtility;
297-
return true;
298-
}
299-
return false;
300-
}
301-
302-
/**
303-
* Parse an EStateTreeTransitionTrigger from a string.
304-
*/
305-
static bool ParseTransitionTrigger(const FString& Str, EStateTreeTransitionTrigger& OutTrigger)
306-
{
307-
if (Str.Equals(TEXT("OnStateCompleted"), ESearchCase::IgnoreCase))
308-
{
309-
OutTrigger = EStateTreeTransitionTrigger::OnStateCompleted;
310-
return true;
311-
}
312-
if (Str.Equals(TEXT("OnStateSucceeded"), ESearchCase::IgnoreCase))
313-
{
314-
OutTrigger = EStateTreeTransitionTrigger::OnStateSucceeded;
315-
return true;
316-
}
317-
if (Str.Equals(TEXT("OnStateFailed"), ESearchCase::IgnoreCase))
318-
{
319-
OutTrigger = EStateTreeTransitionTrigger::OnStateFailed;
320-
return true;
321-
}
322-
if (Str.Equals(TEXT("OnTick"), ESearchCase::IgnoreCase))
323-
{
324-
OutTrigger = EStateTreeTransitionTrigger::OnTick;
325-
return true;
326-
}
327-
if (Str.Equals(TEXT("OnEvent"), ESearchCase::IgnoreCase))
328-
{
329-
OutTrigger = EStateTreeTransitionTrigger::OnEvent;
330-
return true;
331-
}
332-
return false;
333-
}
334-
335-
/**
336-
* Parse an EStateTreeTransitionPriority from a string.
337-
*/
338-
static bool ParseTransitionPriority(const FString& Str, EStateTreeTransitionPriority& OutPriority)
339-
{
340-
if (Str.IsEmpty() || Str.Equals(TEXT("Normal"), ESearchCase::IgnoreCase))
341-
{
342-
OutPriority = EStateTreeTransitionPriority::Normal;
343-
return true;
344-
}
345-
if (Str.Equals(TEXT("Low"), ESearchCase::IgnoreCase))
346-
{
347-
OutPriority = EStateTreeTransitionPriority::Low;
348-
return true;
349-
}
350-
if (Str.Equals(TEXT("Medium"), ESearchCase::IgnoreCase))
351-
{
352-
OutPriority = EStateTreeTransitionPriority::Medium;
353-
return true;
354-
}
355-
if (Str.Equals(TEXT("High"), ESearchCase::IgnoreCase))
356-
{
357-
OutPriority = EStateTreeTransitionPriority::High;
358-
return true;
359-
}
360-
if (Str.Equals(TEXT("Critical"), ESearchCase::IgnoreCase))
361-
{
362-
OutPriority = EStateTreeTransitionPriority::Critical;
363-
return true;
364-
}
365-
return false;
366-
}
367-
368189
/**
369190
* Parse an EPropertyBagPropertyType from a user-facing type string.
370191
* Returns None on unknown types. Also outputs a UScriptStruct* for struct types.
@@ -491,7 +312,7 @@ TSharedPtr<FJsonObject> FEpicUnrealMCPStateTreeCommands::HandleCreateStateTree(
491312

492313
// Resolve schema class
493314
FString SchemaError;
494-
UClass* SchemaClass = ResolveSchemaClass(SchemaClassName, SchemaError);
315+
UClass* SchemaClass = StateTreeHelpers::ResolveSchemaClass(SchemaClassName, SchemaError);
495316
if (!SchemaClass)
496317
{
497318
return FEpicUnrealMCPCommonUtils::CreateErrorResponse(SchemaError);
@@ -571,7 +392,7 @@ TSharedPtr<FJsonObject> FEpicUnrealMCPStateTreeCommands::HandleAddStateTreeState
571392
FString StateTypeStr;
572393
Params->TryGetStringField(TEXT("state_type"), StateTypeStr);
573394
EStateTreeStateType StateType = EStateTreeStateType::State;
574-
if (!StateTypeStr.IsEmpty() && !ParseStateType(StateTypeStr, StateType))
395+
if (!StateTypeStr.IsEmpty() && !StateTreeHelpers::ParseStateType(StateTypeStr, StateType))
575396
{
576397
return FEpicUnrealMCPCommonUtils::CreateErrorResponse(
577398
FString::Printf(TEXT("Invalid state_type: '%s'"), *StateTypeStr));
@@ -643,7 +464,7 @@ TSharedPtr<FJsonObject> FEpicUnrealMCPStateTreeCommands::HandleAddStateTreeState
643464
if (Params->TryGetStringField(TEXT("selection_behavior"), SelectionStr))
644465
{
645466
EStateTreeStateSelectionBehavior Behavior;
646-
if (ParseSelectionBehavior(SelectionStr, Behavior))
467+
if (StateTreeHelpers::ParseSelectionBehavior(SelectionStr, Behavior))
647468
{
648469
NewState->SelectionBehavior = Behavior;
649470
}
@@ -1058,7 +879,7 @@ TSharedPtr<FJsonObject> FEpicUnrealMCPStateTreeCommands::HandleAddStateTreeTrans
1058879

1059880
// Parse trigger
1060881
EStateTreeTransitionTrigger Trigger;
1061-
if (!ParseTransitionTrigger(TriggerStr, Trigger))
882+
if (!StateTreeHelpers::ParseTransitionTrigger(TriggerStr, Trigger))
1062883
{
1063884
return FEpicUnrealMCPCommonUtils::CreateErrorResponse(
1064885
FString::Printf(TEXT("Invalid trigger: '%s'"), *TriggerStr));
@@ -1068,7 +889,7 @@ TSharedPtr<FJsonObject> FEpicUnrealMCPStateTreeCommands::HandleAddStateTreeTrans
1068889
FString PriorityStr;
1069890
Params->TryGetStringField(TEXT("priority"), PriorityStr);
1070891
EStateTreeTransitionPriority Priority = EStateTreeTransitionPriority::Normal;
1071-
if (!PriorityStr.IsEmpty() && !ParseTransitionPriority(PriorityStr, Priority))
892+
if (!PriorityStr.IsEmpty() && !StateTreeHelpers::ParseTransitionPriority(PriorityStr, Priority))
1072893
{
1073894
return FEpicUnrealMCPCommonUtils::CreateErrorResponse(
1074895
FString::Printf(TEXT("Invalid priority: '%s'"), *PriorityStr));

0 commit comments

Comments
 (0)