Replace delimiters with unicode shapes
This commit is contained in:
@@ -56,17 +56,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for duplicate component names
|
// Check for duplicate component names
|
||||||
const TArray<USCS_Node*>& ExistingNodes = SCS->GetAllNodes();
|
const TArray<USCS_Node*>& Existing = SCS->GetAllNodes();
|
||||||
for (USCS_Node* Existing : ExistingNodes)
|
if (!WingUtils::FindExactlyNoneNamed(Component, Existing))
|
||||||
{
|
return;
|
||||||
if (Existing && Existing->ComponentTemplate &&
|
|
||||||
WingUtils::Identifies(Component, Existing->ComponentTemplate))
|
|
||||||
{
|
|
||||||
UWingServer::Printf(TEXT("ERROR: A component named '%s' already exists in Blueprint '%s'\n"),
|
|
||||||
*Component, *WingUtils::FormatName(BP));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve the component class by name
|
// Resolve the component class by name
|
||||||
UClass* ComponentClassObj = UWingTypes::TextToOneObjectType(ComponentClass);
|
UClass* ComponentClassObj = UWingTypes::TextToOneObjectType(ComponentClass);
|
||||||
@@ -81,7 +73,7 @@ public:
|
|||||||
USCS_Node* ParentSCSNode = nullptr;
|
USCS_Node* ParentSCSNode = nullptr;
|
||||||
if (!ParentComponent.IsEmpty())
|
if (!ParentComponent.IsEmpty())
|
||||||
{
|
{
|
||||||
for (USCS_Node* Node : ExistingNodes)
|
for (USCS_Node* Node : Existing)
|
||||||
{
|
{
|
||||||
if (Node && Node->ComponentTemplate &&
|
if (Node && Node->ComponentTemplate &&
|
||||||
WingUtils::Identifies(ParentComponent, Node->ComponentTemplate))
|
WingUtils::Identifies(ParentComponent, Node->ComponentTemplate))
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public:
|
|||||||
UPROPERTY(meta=(Description="Path to a graph node (function entry, function result, custom event, or tunnel)"))
|
UPROPERTY(meta=(Description="Path to a graph node (function entry, function result, custom event, or tunnel)"))
|
||||||
FString Node;
|
FString Node;
|
||||||
|
|
||||||
UPROPERTY(meta=(Description="Comma-separated args, e.g. 'int x, float y'"))
|
UPROPERTY(meta=(Description="Args e.g. 'int◦x│float◦y'"))
|
||||||
FString Args;
|
FString Args;
|
||||||
|
|
||||||
virtual FString GetDescription() const override
|
virtual FString GetDescription() const override
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ public:
|
|||||||
"\n PATHS:"
|
"\n PATHS:"
|
||||||
"\n"
|
"\n"
|
||||||
"\n Most commands require you to specify a path. A path starts"
|
"\n Most commands require you to specify a path. A path starts"
|
||||||
"\n with an asset name, followed by comma-separated steps that"
|
"\n with an asset name, followed by steps separated by │"
|
||||||
"\n navigate into the asset. Example:"
|
"\n that navigate into the asset. Example:"
|
||||||
"\n"
|
"\n"
|
||||||
"\n /Game/Widgets/WB_Hotkeys,graph:EventGraph,node:Self03,pin:Result"
|
"\n /Game/Widgets/WB_Hotkeys│graph:EventGraph│node:Self03│pin:Result"
|
||||||
"\n"
|
"\n"
|
||||||
"\n The navigation steps supported are:"
|
"\n The navigation steps supported are:"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -38,30 +38,30 @@ public:
|
|||||||
"\n Steps do not always require a parameter. For example, materials"
|
"\n Steps do not always require a parameter. For example, materials"
|
||||||
"\n only have one graph, so you can just say:"
|
"\n only have one graph, so you can just say:"
|
||||||
"\n"
|
"\n"
|
||||||
"\n /Game/Materials/MyMaterial,graph"
|
"\n /Game/Materials/MyMaterial│graph"
|
||||||
"\n"
|
"\n"
|
||||||
"\n TYPES:"
|
"\n TYPES:"
|
||||||
"\n"
|
"\n"
|
||||||
"\n To change variable types, or function prototypes, you will"
|
"\n To change variable types, or function prototypes, you will"
|
||||||
"\n use our syntax for types. Here are some simple examples:"
|
"\n use our syntax for types. Here are some simple examples:"
|
||||||
"\n"
|
"\n"
|
||||||
"\n boolean, int64, double, string, etc"
|
"\n boolean, int64, double, string, etc."
|
||||||
"\n vector, rotator, hitresult, etc"
|
"\n vector, rotator, hitresult, etc."
|
||||||
"\n actor, character, playercontroller, etc"
|
"\n actor, character, playercontroller, etc."
|
||||||
"\n eblendmode, emovementmode, etc"
|
"\n eblendmode, emovementmode, etc."
|
||||||
"\n"
|
"\n"
|
||||||
"\n Notice that it's 'actor', not 'AActor'."
|
"\n Notice that it's 'actor', not 'AActor'."
|
||||||
"\n You can use the following notations for complex types:"
|
"\n You can use the following notations for complex types:"
|
||||||
"\n"
|
"\n"
|
||||||
"\n soft<abp_manny>, class<pawn>, softclass<pawn>"
|
"\n Soft◂abp_manny▸, Class◂pawn▸, SoftClass◂pawn▸"
|
||||||
"\n array<int>, set<string>, map<int, string>"
|
"\n Array◂int▸, Set◂string▸, Map◂int◆string▸"
|
||||||
"\n"
|
"\n"
|
||||||
"\n FUNCTION ARGUMENTS AND RETURN VALUES:"
|
"\n FUNCTION ARGUMENTS AND RETURN VALUES:"
|
||||||
"\n"
|
"\n"
|
||||||
"\n Function argument lists are expressed as comma-separated"
|
"\n Function argument lists are expressed as │-separated"
|
||||||
"\n lists containing type and variable name:"
|
"\n lists of type◦name pairs:"
|
||||||
"\n"
|
"\n"
|
||||||
"\n double D, PlayerController P, array<int> A"
|
"\n double◦D│PlayerController◦P│Array◂int▸◦A"
|
||||||
"\n"
|
"\n"
|
||||||
"\n To change the arguments or return values of a function, edit the"
|
"\n To change the arguments or return values of a function, edit the"
|
||||||
"\n entry or exit node of the graph using GraphNode_SetArgs."
|
"\n entry or exit node of the graph using GraphNode_SetArgs."
|
||||||
@@ -70,6 +70,14 @@ public:
|
|||||||
"\n before you can set return values. Custom event nodes also have"
|
"\n before you can set return values. Custom event nodes also have"
|
||||||
"\n editable arguments."
|
"\n editable arguments."
|
||||||
"\n"
|
"\n"
|
||||||
|
"\n ABOUT UNICODE AND WHITESPACE:"
|
||||||
|
"\n"
|
||||||
|
"\n We use unicode geometric shapes as delimiters in"
|
||||||
|
"\n some places, such as in typenames, function arguments, and"
|
||||||
|
"\n paths (see above). This is intentional, you really"
|
||||||
|
"\n do have to use those delimiters. Do not put excess"
|
||||||
|
"\n whitespace into paths or typenames."
|
||||||
|
"\n"
|
||||||
"\n MATERIAL EDITING:"
|
"\n MATERIAL EDITING:"
|
||||||
"\n"
|
"\n"
|
||||||
"\n We do not expose material expressions directly. Instead, you"
|
"\n We do not expose material expressions directly. Instead, you"
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ WingFetcher& WingFetcher::Walk(const FString& Path)
|
|||||||
if (bError) return *this;
|
if (bError) return *this;
|
||||||
|
|
||||||
TArray<FString> Segments;
|
TArray<FString> Segments;
|
||||||
Path.ParseIntoArray(Segments, TEXT(","));
|
Path.ParseIntoArray(Segments, TEXT("│"));
|
||||||
if (Segments.Num() == 0)
|
if (Segments.Num() == 0)
|
||||||
{
|
{
|
||||||
UWingServer::Print(TEXT("ERROR: Empty path\n"));
|
UWingServer::Print(TEXT("ERROR: Empty path\n"));
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ FString WingFunctionArgs::GetArgs(UEdGraphNode* Node)
|
|||||||
TStringBuilder<256> SB;
|
TStringBuilder<256> SB;
|
||||||
for (const TSharedPtr<FUserPinInfo>& Pin : Editable->UserDefinedPins)
|
for (const TSharedPtr<FUserPinInfo>& Pin : Editable->UserDefinedPins)
|
||||||
{
|
{
|
||||||
if (SB.Len() > 0) SB << TEXT(", ");
|
if (SB.Len() > 0) SB << TEXT("│");
|
||||||
SB << UWingTypes::TypeToText(Pin->PinType) << TEXT(" ") << Pin->PinName.ToString();
|
SB << UWingTypes::TypeToText(Pin->PinType) << TEXT("◦") << Pin->PinName.ToString();
|
||||||
}
|
}
|
||||||
return FString(SB);
|
return FString(SB);
|
||||||
}
|
}
|
||||||
@@ -42,23 +42,23 @@ bool WingFunctionArgs::ParseArgs(const FString& Args, TArray<FParsedArg>& OutArg
|
|||||||
if (Trimmed.IsEmpty()) return true;
|
if (Trimmed.IsEmpty()) return true;
|
||||||
|
|
||||||
TArray<FString> Parts;
|
TArray<FString> Parts;
|
||||||
Trimmed.ParseIntoArray(Parts, TEXT(","));
|
Trimmed.ParseIntoArray(Parts, TEXT("│"));
|
||||||
|
|
||||||
for (const FString& Part : Parts)
|
for (const FString& Part : Parts)
|
||||||
{
|
{
|
||||||
FString Token = Part.TrimStartAndEnd();
|
FString Token = Part.TrimStartAndEnd();
|
||||||
if (Token.IsEmpty()) continue;
|
if (Token.IsEmpty()) continue;
|
||||||
|
|
||||||
// Split "type name" on the last space.
|
// Split "type◦name" on the white bullet.
|
||||||
int32 LastSpace;
|
FString TypeStr, NameStr;
|
||||||
if (!Token.FindLastChar(TEXT(' '), LastSpace))
|
if (!Token.Split(TEXT("◦"), &TypeStr, &NameStr))
|
||||||
{
|
{
|
||||||
UWingServer::Printf(TEXT("ERROR: Expected 'type name' but got '%s'\n"), *Token);
|
UWingServer::Printf(TEXT("ERROR: Expected 'type◦name' but got '%s'\n"), *Token);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FString TypeStr = Token.Left(LastSpace).TrimStartAndEnd();
|
TypeStr.TrimStartAndEndInline();
|
||||||
FString NameStr = Token.Mid(LastSpace + 1).TrimStartAndEnd();
|
NameStr.TrimStartAndEndInline();
|
||||||
|
|
||||||
if (TypeStr.IsEmpty() || NameStr.IsEmpty())
|
if (TypeStr.IsEmpty() || NameStr.IsEmpty())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -149,11 +149,11 @@ FString UWingTypes::TypeToTextInner(FName Category, FName SubCategory, UObject*
|
|||||||
if (Category == UEdGraphSchema_K2::PC_Object)
|
if (Category == UEdGraphSchema_K2::PC_Object)
|
||||||
return Short;
|
return Short;
|
||||||
if (Category == UEdGraphSchema_K2::PC_Class)
|
if (Category == UEdGraphSchema_K2::PC_Class)
|
||||||
return FString::Printf(TEXT("Class<%s>"), *Short);
|
return FString::Printf(TEXT("Class◂%s▸"), *Short);
|
||||||
if (Category == UEdGraphSchema_K2::PC_SoftObject)
|
if (Category == UEdGraphSchema_K2::PC_SoftObject)
|
||||||
return FString::Printf(TEXT("Soft<%s>"), *Short);
|
return FString::Printf(TEXT("Soft◂%s▸"), *Short);
|
||||||
if (Category == UEdGraphSchema_K2::PC_SoftClass)
|
if (Category == UEdGraphSchema_K2::PC_SoftClass)
|
||||||
return FString::Printf(TEXT("SoftClass<%s>"), *Short);
|
return FString::Printf(TEXT("SoftClass◂%s▸"), *Short);
|
||||||
if (Category == UEdGraphSchema_K2::PC_Interface)
|
if (Category == UEdGraphSchema_K2::PC_Interface)
|
||||||
return Short;
|
return Short;
|
||||||
}
|
}
|
||||||
@@ -171,9 +171,9 @@ FString UWingTypes::TypeToText(const FEdGraphPinType& PinType)
|
|||||||
return FString();
|
return FString();
|
||||||
|
|
||||||
if (PinType.IsArray())
|
if (PinType.IsArray())
|
||||||
return FString::Printf(TEXT("Array<%s>"), *Inner);
|
return FString::Printf(TEXT("Array◂%s▸"), *Inner);
|
||||||
if (PinType.IsSet())
|
if (PinType.IsSet())
|
||||||
return FString::Printf(TEXT("Set<%s>"), *Inner);
|
return FString::Printf(TEXT("Set◂%s▸"), *Inner);
|
||||||
if (PinType.IsMap())
|
if (PinType.IsMap())
|
||||||
{
|
{
|
||||||
FString ValueInner = Types->TypeToTextInner(
|
FString ValueInner = Types->TypeToTextInner(
|
||||||
@@ -182,7 +182,7 @@ FString UWingTypes::TypeToText(const FEdGraphPinType& PinType)
|
|||||||
PinType.PinValueType.TerminalSubCategoryObject.Get());
|
PinType.PinValueType.TerminalSubCategoryObject.Get());
|
||||||
if (ValueInner.IsEmpty())
|
if (ValueInner.IsEmpty())
|
||||||
return FString();
|
return FString();
|
||||||
return FString::Printf(TEXT("Map<%s, %s>"), *Inner, *ValueInner);
|
return FString::Printf(TEXT("Map◂%s◆%s▸"), *Inner, *ValueInner);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Inner;
|
return Inner;
|
||||||
@@ -428,29 +428,29 @@ bool UWingTypes::ParsePlainIdentifier(FEdGraphPinType& OutType)
|
|||||||
bool UWingTypes::ParseWrapped(FName Wrapper, FEdGraphPinType& OutType)
|
bool UWingTypes::ParseWrapped(FName Wrapper, FEdGraphPinType& OutType)
|
||||||
{
|
{
|
||||||
Cursor++;
|
Cursor++;
|
||||||
if (!ParseChar('<')) return false;
|
if (!ParseChar(L'◂')) return false;
|
||||||
if (!ParsePlainIdentifier(OutType)) return false;
|
if (!ParsePlainIdentifier(OutType)) return false;
|
||||||
if (!Cast<UClass>(OutType.PinSubCategoryObject))
|
if (!Cast<UClass>(OutType.PinSubCategoryObject))
|
||||||
{
|
{
|
||||||
Error = FString::Printf(TEXT("%s is not a Class"), *OutType.PinSubCategoryObject->GetName());
|
Error = FString::Printf(TEXT("%s is not a Class"), *OutType.PinSubCategoryObject->GetName());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!ParseChar('>')) return false;
|
if (!ParseChar(L'▸')) return false;
|
||||||
OutType.PinCategory = Wrapper;
|
OutType.PinCategory = Wrapper;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UWingTypes::ParseMaybeWrapped(FEdGraphPinType& OutType)
|
bool UWingTypes::ParseMaybeWrapped(FEdGraphPinType& OutType)
|
||||||
{
|
{
|
||||||
if (TokenIs(TEXT("Soft"), '<'))
|
if (TokenIs(TEXT("Soft"), L'◂'))
|
||||||
{
|
{
|
||||||
return ParseWrapped(UEdGraphSchema_K2::PC_SoftObject, OutType);
|
return ParseWrapped(UEdGraphSchema_K2::PC_SoftObject, OutType);
|
||||||
}
|
}
|
||||||
else if (TokenIs(TEXT("Class"), '<'))
|
else if (TokenIs(TEXT("Class"), L'◂'))
|
||||||
{
|
{
|
||||||
return ParseWrapped(UEdGraphSchema_K2::PC_Class, OutType);
|
return ParseWrapped(UEdGraphSchema_K2::PC_Class, OutType);
|
||||||
}
|
}
|
||||||
else if (TokenIs(TEXT("SoftClass"), '<'))
|
else if (TokenIs(TEXT("SoftClass"), L'◂'))
|
||||||
{
|
{
|
||||||
return ParseWrapped(UEdGraphSchema_K2::PC_SoftClass, OutType);
|
return ParseWrapped(UEdGraphSchema_K2::PC_SoftClass, OutType);
|
||||||
}
|
}
|
||||||
@@ -460,40 +460,40 @@ bool UWingTypes::ParseMaybeWrapped(FEdGraphPinType& OutType)
|
|||||||
bool UWingTypes::ParseArrayOrSet(FEdGraphPinType& OutType)
|
bool UWingTypes::ParseArrayOrSet(FEdGraphPinType& OutType)
|
||||||
{
|
{
|
||||||
Cursor++;
|
Cursor++;
|
||||||
if (!ParseChar('<')) return false;
|
if (!ParseChar(L'◂')) return false;
|
||||||
if (!ParseMaybeWrapped(OutType)) return false;
|
if (!ParseMaybeWrapped(OutType)) return false;
|
||||||
if (!ParseChar('>')) return false;
|
if (!ParseChar(L'▸')) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UWingTypes::ParseMap(FEdGraphPinType& OutType)
|
bool UWingTypes::ParseMap(FEdGraphPinType& OutType)
|
||||||
{
|
{
|
||||||
Cursor++;
|
Cursor++;
|
||||||
if (!ParseChar('<')) return false;
|
if (!ParseChar(L'◂')) return false;
|
||||||
if (!ParsePlainIdentifier(OutType)) return false;
|
if (!ParsePlainIdentifier(OutType)) return false;
|
||||||
if (!ParseChar(',')) return false;
|
if (!ParseChar(L'◆')) return false;
|
||||||
FEdGraphPinType ValueType;
|
FEdGraphPinType ValueType;
|
||||||
if (!ParseMaybeWrapped(ValueType)) return false;
|
if (!ParseMaybeWrapped(ValueType)) return false;
|
||||||
OutType.PinValueType.TerminalCategory = ValueType.PinCategory;
|
OutType.PinValueType.TerminalCategory = ValueType.PinCategory;
|
||||||
OutType.PinValueType.TerminalSubCategory = ValueType.PinSubCategory;
|
OutType.PinValueType.TerminalSubCategory = ValueType.PinSubCategory;
|
||||||
OutType.PinValueType.TerminalSubCategoryObject = ValueType.PinSubCategoryObject;
|
OutType.PinValueType.TerminalSubCategoryObject = ValueType.PinSubCategoryObject;
|
||||||
if (!ParseChar('>')) return false;
|
if (!ParseChar(L'▸')) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UWingTypes::ParseType(FEdGraphPinType& OutType)
|
bool UWingTypes::ParseType(FEdGraphPinType& OutType)
|
||||||
{
|
{
|
||||||
if (TokenIs(TEXT("Array"), '<'))
|
if (TokenIs(TEXT("Array"), L'◂'))
|
||||||
{
|
{
|
||||||
OutType.ContainerType = EPinContainerType::Array;
|
OutType.ContainerType = EPinContainerType::Array;
|
||||||
if (!ParseArrayOrSet(OutType)) return false;
|
if (!ParseArrayOrSet(OutType)) return false;
|
||||||
}
|
}
|
||||||
else if (TokenIs(TEXT("Set"), '<'))
|
else if (TokenIs(TEXT("Set"), L'◂'))
|
||||||
{
|
{
|
||||||
OutType.ContainerType = EPinContainerType::Set;
|
OutType.ContainerType = EPinContainerType::Set;
|
||||||
if (!ParseArrayOrSet(OutType)) return false;
|
if (!ParseArrayOrSet(OutType)) return false;
|
||||||
}
|
}
|
||||||
else if (TokenIs(TEXT("Map"), '<'))
|
else if (TokenIs(TEXT("Map"), L'◂'))
|
||||||
{
|
{
|
||||||
OutType.ContainerType = EPinContainerType::Map;
|
OutType.ContainerType = EPinContainerType::Map;
|
||||||
if (!ParseMap(OutType)) return false;
|
if (!ParseMap(OutType)) return false;
|
||||||
|
|||||||
@@ -51,7 +51,16 @@ extern int32 TrySavePackageSEH(
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// Name Formatting
|
// Name sanitization
|
||||||
|
//
|
||||||
|
// Our parsers use Unicode geometric shape delimiters that
|
||||||
|
// are unlikely to appear in names: ◂▸ for type brackets, ◆
|
||||||
|
// for map key◆value, ◦ for type◦name in prototypes, │ for
|
||||||
|
// list/path separation. If any of these characters appear
|
||||||
|
// in a name, we replace them with safe ASCII equivalents.
|
||||||
|
// One consequence of name sanitization is that we can't use
|
||||||
|
// Unreal's name-lookup routines — the LLM only sees
|
||||||
|
// sanitized names. So we do our own name lookups.
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
void WingUtils::SanitizeNameInPlace(FString &Name)
|
void WingUtils::SanitizeNameInPlace(FString &Name)
|
||||||
@@ -61,7 +70,11 @@ void WingUtils::SanitizeNameInPlace(FString &Name)
|
|||||||
{
|
{
|
||||||
TCHAR c = Name[Src];
|
TCHAR c = Name[Src];
|
||||||
if (c < 0x20 || c == 0x7F) continue;
|
if (c < 0x20 || c == 0x7F) continue;
|
||||||
if ((c == ' ') || (c == ',') || (c == ':')) c = '_';
|
if (c == L'◂') c='<';
|
||||||
|
if (c == L'▸') c='>';
|
||||||
|
if (c == L'◆') c='*';
|
||||||
|
if (c == L'◦') c='.';
|
||||||
|
if (c == L'│') c = '|';
|
||||||
Name[Dst++] = c;
|
Name[Dst++] = c;
|
||||||
}
|
}
|
||||||
if (Dst == 0) Name[Dst++] = '_';
|
if (Dst == 0) Name[Dst++] = '_';
|
||||||
@@ -82,6 +95,10 @@ FString WingUtils::SanitizeName(FName Name)
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Name Lookup
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
FString WingUtils::FormatName(const UWorld *World)
|
FString WingUtils::FormatName(const UWorld *World)
|
||||||
{
|
{
|
||||||
return World->GetPathName();
|
return World->GetPathName();
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ struct WingFunctionArgs
|
|||||||
// CustomEvent, or Tunnel).
|
// CustomEvent, or Tunnel).
|
||||||
static bool HasArgs(UEdGraphNode* Node);
|
static bool HasArgs(UEdGraphNode* Node);
|
||||||
|
|
||||||
// Returns the user-defined pins as a string like "int x, float y".
|
// Returns the user-defined pins as a string like "int◦x│float◦y".
|
||||||
static FString GetArgs(UEdGraphNode* Node);
|
static FString GetArgs(UEdGraphNode* Node);
|
||||||
|
|
||||||
// Sets the user-defined pins from a string like "int x, float y".
|
// Sets the user-defined pins from a string like "int◦x│float◦y".
|
||||||
// Returns true on success.
|
// Returns true on success.
|
||||||
static bool SetArgs(UEdGraphNode* Node, const FString& Args);
|
static bool SetArgs(UEdGraphNode* Node, const FString& Args);
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ private:
|
|||||||
FName PinName;
|
FName PinName;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse "int x, float y" into an array of FParsedArg.
|
// Parse "int◦x│float◦y" into an array of FParsedArg.
|
||||||
// Returns false and prints an error on failure.
|
// Returns false and prints an error on failure.
|
||||||
static bool ParseArgs(const FString& Args, TArray<FParsedArg>& OutArgs);
|
static bool ParseArgs(const FString& Args, TArray<FParsedArg>& OutArgs);
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,15 @@ HOST = "localhost"
|
|||||||
PORT = 9847
|
PORT = 9847
|
||||||
TIMEOUT = 120
|
TIMEOUT = 120
|
||||||
|
|
||||||
|
# Map ASCII characters to the Unicode geometric delimiters used by the plugin.
|
||||||
|
DELIMITER_MAP = str.maketrans({
|
||||||
|
'<': '◂',
|
||||||
|
'>': '▸',
|
||||||
|
'*': '◆',
|
||||||
|
'.': '◦',
|
||||||
|
'|': '│',
|
||||||
|
})
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
args = sys.argv[1:]
|
args = sys.argv[1:]
|
||||||
if not args:
|
if not args:
|
||||||
@@ -35,6 +44,11 @@ def main():
|
|||||||
pass
|
pass
|
||||||
msg[key] = value
|
msg[key] = value
|
||||||
|
|
||||||
|
# Translate ASCII delimiter shortcuts to Unicode geometric shapes.
|
||||||
|
for key, value in msg.items():
|
||||||
|
if isinstance(value, str):
|
||||||
|
msg[key] = value.translate(DELIMITER_MAP)
|
||||||
|
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
sock.settimeout(TIMEOUT)
|
sock.settimeout(TIMEOUT)
|
||||||
try:
|
try:
|
||||||
|
|||||||
Reference in New Issue
Block a user