A few more bug fixes
This commit is contained in:
@@ -1,7 +0,0 @@
|
|||||||
# WingCommandlet Bug Report
|
|
||||||
|
|
||||||
## 1. The documented `-run=` name does not match the commandlet class name
|
|
||||||
`WingCommandlet.h` says to launch the tool with `-run=UEWingman`, but the actual class is `UWingCommandlet`. In Unreal, commandlets are resolved from the class name without the `Commandlet` suffix, so this class would normally be invoked as `-run=Wing` rather than `-run=UEWingman`. As written, the usage text points users at a commandlet name that does not correspond to this class, so the advertised entry point is wrong.
|
|
||||||
|
|
||||||
## 2. Startup failures leave the commandlet spinning forever
|
|
||||||
`Main()` assumes `UWingServer` has already started and then loops until engine exit, but `UWingServer::Initialize()` can return early on socket creation, bind, or listen failure without setting `bRunning`. In that case `UWingServer::TickServer()` becomes a no-op, yet the commandlet keeps sleeping and rechecking `IsEngineExitRequested()` forever. A failed server start should terminate the commandlet with an error instead of hanging silently.
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
# WingComponent.cpp Bug Report
|
|
||||||
|
|
||||||
## Duplicate component lookup is ambiguous
|
|
||||||
`GetAll()` returns every SCS node from every ancestor blueprint, but `FindSCSNodeByName()` already treats component names as “nearest match wins.” If a child blueprint overrides or shadows a component name from an ancestor, `WingFetcher::Component` can see multiple refs with the same external ID and fail the lookup as ambiguous instead of resolving to the visible component.
|
|
||||||
|
|
||||||
## AddComponent crashes on blueprints without an SCS
|
|
||||||
`AddComponent()` assumes `BP->SimpleConstructionScript` is valid and calls `CreateNode()` / `AddNode()` unconditionally. That works for actor blueprints, but the handler can still be pointed at blueprints that do not own an SCS, which turns this helper into a null-dereference crash instead of a clean error.
|
|
||||||
|
|
||||||
## CheckOwnedByBlueprint dereferences a null SCS on its error path
|
|
||||||
`CheckOwnedByBlueprint()` explicitly allows the “missing component” case in its guard, but the error message then unconditionally reads `FC.SCS->GetSCS()->GetBlueprint()`. If the helper is ever reached with `FC.SCS == nullptr`, the function crashes while trying to report the problem.
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
# WingEntities.cpp Review
|
|
||||||
|
|
||||||
I did not find a concrete bug in `WingEntities.cpp`. The file is a generated entity lookup table, and its constructor and static map initialization match the expectations in `WingTokenizer` for HTML entity escape handling.
|
|
||||||
|
|
||||||
The only notable behavior is that `GetName()` returns one deterministic alias per codepoint, which is exactly what `WingTokenizer::ExternalizeID()` needs when it emits readable escapes. The generated table also stays within the `TCHAR` range that the generator documents as a constraint.
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
# WingFactories bugs
|
|
||||||
|
|
||||||
## 1. `/Game` validation is too loose
|
|
||||||
`CheckNewAssetPath` only checks `Path.StartsWith(TEXT("/Game"))`, so paths like `/GameX/Foo` or `/Game123/Bar` pass even though they are not actually under the `/Game` mount point. That makes the asset-path guard weaker than the surrounding validation suggests and can route requests into the wrong package namespace.
|
|
||||||
|
|
||||||
## 2. Existing-package detection only sees loaded packages
|
|
||||||
`CheckNewAssetPath` uses `FindObject<UPackage>(nullptr, *Path)` to decide whether the destination already exists. That only catches packages already loaded into memory, so an on-disk asset that is not currently loaded can slip through and then collide with the new create request.
|
|
||||||
|
|
||||||
## 3. `CreateAsset` assumes `GEditor` is always present
|
|
||||||
After a successful factory call, `CreateAsset` unconditionally does `GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()` and may open the asset editor. This is safe only in a fully initialized editor session; commandlet or other headless paths can leave `GEditor` null and crash here, unlike the guarded pattern used elsewhere in the plugin.
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# WingFetcher Bugs
|
|
||||||
|
|
||||||
## Material assets can be resolved to the wrong object
|
|
||||||
`WingFetcher::Asset()` special-cases `UMaterial`, but it uses `GetMaterialInterface()->GetBaseMaterial()` instead of the existing transient-copy helper in `WingUtils`. That means a fetch can bind to the original asset instead of the live editor copy when a material editor is already open, so later graph or node operations may hit the wrong object state.
|
|
||||||
|
|
||||||
## Whitespace validation is incomplete
|
|
||||||
`Walk()` rejects only literal space characters with `Path.Contains(TEXT(" "))`, but it does not reject tabs, newlines, or other whitespace. Those inputs can still reach the path parser and produce confusing downstream failures instead of the clean "paths may not contain whitespace" error the code promises.
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# WingGraphActions Bugs
|
|
||||||
|
|
||||||
## `Search()` treats `MaxResults == 0` as "return nothing"
|
|
||||||
`FWingGraphActions::Search()` breaks out of the loop before checking any candidate whenever `MaxResults` is zero, because it tests `Results.Num() == MaxResults` at the top of the loop. The header gives `MaxResults` a default value of `0`, so the API advertises a default that produces an empty result set instead of an unlimited search or a sensible default cap.
|
|
||||||
|
|
||||||
## Exact name lookup is not protected against duplicate action labels
|
|
||||||
`CollectActions()` and `CollectSpawners()` append every matching graph action, but `Search(..., Exact=true)` only compares the standardized display name. If the action database contains two spawners or schema actions that normalize to the same name, callers like `GraphNode_Add` will fail the "exactly one" check even though the requested node type is valid. The file never deduplicates or otherwise disambiguates those collisions.
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
# WingGraphExport Bugs
|
|
||||||
|
|
||||||
## `GetLinkedTo()` does not follow reroute/knot chains
|
|
||||||
The helper comment in [WingGraphExport.h](/home/jyelon/integration/Plugins/UEWingman/Source/UEWingman/Public/WingGraphExport.h#L25) says a linked knot node should be followed to the far end of the chain, but the implementation in [WingGraphExport.cpp](/home/jyelon/integration/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp#L39) only returns `LinkedTo[0]`. That means exported pin sources can name the reroute node instead of the real upstream source, which makes the dump inaccurate for graphs that use reroute nodes.
|
|
||||||
|
|
||||||
## String-like pin defaults are emitted without escaping
|
|
||||||
`FormatPinSource()` wraps `PC_String`, `PC_Name`, and `PC_Text` defaults in quotes, but it prints `Pin->DefaultValue` and `Pin->DefaultTextValue.ToString()` verbatim at [WingGraphExport.cpp](/home/jyelon/integration/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp#L109). Any embedded quotes, backslashes, or newlines will produce ambiguous output and can make the dump impossible to parse back reliably.
|
|
||||||
|
|
||||||
## Suppressed minor-property notice is never emitted
|
|
||||||
`EmitNode()` sets `SuppressedDetails = true` when it hides secondary properties, and `EmitDetailsSuggestion()` is clearly meant to warn the caller afterward. But neither constructor calls [WingGraphExport::EmitDetailsSuggestion](/home/jyelon/integration/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp#L336), so the user never sees the hint to rerun with `details=true`.
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# WingHacks Bugs
|
|
||||||
|
|
||||||
## `WasOpenedInDefaultsMode()` dereferences null without a guard
|
|
||||||
`WingHacks::WasOpenedInDefaultsMode(FBlueprintEditor* Editor)` immediately reads `Editor->*...` and has no null check. The current call site in `WingNotifier` happens to guard the pointer first, but this helper is public and unsafe on its own, so any future caller that passes a null editor will crash.
|
|
||||||
|
|
||||||
## The private-member accessor is tightly coupled to engine internals
|
|
||||||
`WingHacks` relies on the exact private member names and signatures of `FToolMenuEntry::Action`, `FToolMenuEntry::Command`, and `FBlueprintEditor::bWasOpenedInDefaultsMode`. That makes the code fragile across Unreal upgrades: a minor engine refactor will break compilation or silently invalidate the accessor trick, so this helper should be treated as a high-risk compatibility shim rather than a stable API.
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# WingManual.cpp Bug Report
|
|
||||||
|
|
||||||
## 1. `Documentation_Commands` omits the descriptions it promises
|
|
||||||
`WingManual::Commands()` prints only the command prototype when `Verbose` is false, so the default `Documentation_Commands` output is just a name list. That conflicts with [Documentation_Commands.h](/home/jyelon/integration/Plugins/UEWingman/Source/UEWingman/Handlers/Documentation_Commands.h), which advertises "all the main commands with their descriptions," and it makes the non-verbose mode less useful than the command name implies.
|
|
||||||
|
|
||||||
## 2. The manual text advertises stale command names
|
|
||||||
The manual section in [WingManual.cpp](/home/jyelon/integration/Plugins/UEWingman/Source/UEWingman/Private/WingManual.cpp) still tells users to run `Property_Dump` and `Property_Set`, but those command names do not exist in the current handler registry. The actual property-oriented handlers in this plugin are named differently, so the manual gives users instructions that cannot be followed as written.
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# WingNotifier
|
|
||||||
|
|
||||||
## 1. `SendNotifications()` crashes in commandlet/headless mode
|
|
||||||
`SendNotifications()` dereferences `GEditor` unconditionally when it fetches the `UAssetEditorSubsystem` ([WingNotifier.cpp](./WingNotifier.cpp#L25)). That is unsafe in the commandlet path, because `WingCommandlet::Main()` explicitly ticks the wing server in commandlet mode ([WingCommandlet.cpp](/home/jyelon/integration/Plugins/UEWingman/Source/UEWingman/Private/WingCommandlet.cpp#L10)), and the notifier is always flushed at the end of each request ([WingServer.cpp](/home/jyelon/integration/Plugins/UEWingman/Source/UEWingman/Private/WingServer.cpp#L175)). Any mutating request in a headless run can therefore null-deref before the later `if (GEditor)` viewport guard is reached.
|
|
||||||
|
|
||||||
## 2. Graph edits are not fully propagated because node reconstruction is skipped
|
|
||||||
The notifier comments out the node-level reconstruction pass and only calls `NotifyGraphChanged()` on touched graphs ([WingNotifier.cpp](./WingNotifier.cpp#L58)). That is not enough for edits that change pin layout or node internals: the project already uses `ReconstructNode()` directly in `WingVariables.cpp` after variable changes ([WingVariables.cpp](/home/jyelon/integration/Plugins/UEWingman/Source/UEWingman/Private/WingVariables.cpp#L529)), which shows that graph-shape updates need more than a graph-wide change broadcast. As written, node edits can leave the open editor showing stale pins or other cached node state until a heavier manual refresh happens.
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# WingParameterEditor Bugs
|
|
||||||
|
|
||||||
## 1. `GetMaterialParameters()` reuses `Temp` across every parameter type
|
|
||||||
[`WingParameterEditor.cpp`](./WingParameterEditor.cpp) allocates one `TMap<FMaterialParameterInfo, Metadata> Temp;` and then passes the same map to `GetAllParametersOfType()` for every `EMaterialParameterType` without clearing it first. If that Unreal API appends to the map instead of replacing it, later iterations will reprocess stale entries under the wrong type, which can corrupt the material dump and even trip the `check` on the metadata type at line 119.
|
|
||||||
|
|
||||||
## 2. The cached `FProperty*` map is never refreshed after a reload
|
|
||||||
`GetGetterAndSetterMap()` builds a static map of raw `FProperty*` pointers once and keeps them forever. In the editor, hot reload or live coding can rebuild the generated `FWingParameterEditor` struct, which makes those cached pointers stale; after that, `AddOverride()` and `Print()` can dereference invalid property metadata.
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# WingProperty Bugs
|
|
||||||
|
|
||||||
## Unsigned numeric properties are not handled correctly
|
|
||||||
`GetDouble()` and `GetInt64()` read integral properties through `GetSignedIntPropertyValue()`, and `SetInt64Internal()` validates by round-tripping through the signed accessor as well. That means valid unsigned values above `INT64_MAX` are misread or rejected even though `IsUnsigned()` exists in the same file and clearly shows the code was meant to distinguish signed from unsigned numeric properties.
|
|
||||||
|
|
||||||
## Printed editability does not respect stripped mutable state
|
|
||||||
`GetDetails()` deliberately calls `StripEditable()` when a property should be treated as read-only, but `Print()` ignores the `Editable` field and recomputes editability from `CPF_EditConst` alone. As a result, exported details can show a property as editable even when `Set*()` will reject writes to it, which makes the diagnostics misleading and inconsistent with the actual setter behavior.
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# WingServer Bug Report
|
|
||||||
|
|
||||||
## 1. Stale global server pointer after startup failure
|
|
||||||
`Initialize()` assigns `GWingServer = this` before the socket has actually been created, bound, and listened on. If any of those steps fail, the function returns early, and `Deinitialize()` also returns early when `bRunning` is still false, so `GWingServer` is never cleared again. That leaves the static helpers in [WingServer.h](/home/jyelon/integration/Plugins/UEWingman/Source/UEWingman/Public/WingServer.h) pointing at an object that is no longer a valid running server, which can crash later calls or make commandlet-mode ticking silently operate on a dead subsystem.
|
|
||||||
|
|
||||||
## 2. Handler registry is not invalidated on module unload
|
|
||||||
`OnModulesChanged()` rebuilds the handler registry only when `Reason == EModuleChangeReason::ModuleLoaded`, so module unloads are ignored. In an editor session with hot reload or plugin unload, `WingHandlerRegistry` can keep commands whose `UClass` objects have gone away, which means the server may advertise or dispatch stale handlers into unloaded code. The registry needs to be refreshed or cleared for unloads as well, not just loads.
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# WingTokenizer bugs
|
|
||||||
|
|
||||||
## Numeric escapes can overflow before they are validated
|
|
||||||
`FromHex()` and `FromDecimal()` accumulate into an `int32` and only check `Value > 0xFFFF` after each multiply/add. A long escape such as `�` can overflow the signed accumulator before the range check runs, which is undefined behavior and can let malformed data slip through. These helpers should validate the next digit before the arithmetic or use a wider unsigned accumulator.
|
|
||||||
|
|
||||||
## The identifier scanner accepts whitespace-like Unicode as raw identifier text
|
|
||||||
`TokenizeIdentifier()` treats every `Cat::Other` character as an identifier character, not just the printable whitelist. That means many Unicode separator characters that are not literally ASCII space or tab can be absorbed into names instead of being rejected or escaped, producing visually blank or ambiguous identifiers that violate the tokenizer's own whitespace model. The raw-name fallback should be narrowed so non-whitespace "other" characters are the only ones accepted.
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# WingToolMenu Bugs
|
|
||||||
|
|
||||||
## Missing schema-level context menu actions
|
|
||||||
`GetMenuItems(UGraphNodeContextMenuContext*, const FToolMenuContext&)` only calls `UEdGraphNode::GetNodeContextMenuActions()` and never asks the schema for its context menu entries. The schema call is still present in the file as a commented-out line, so any actions that are only exposed through `UEdGraphSchema::GetContextMenuActions()` are invisible to the MCP.
|
|
||||||
|
|
||||||
## Pin actions can be hidden by disabled node actions
|
|
||||||
When merging node and pin entries, the code records every node label in `OriginalLabels` before checking whether that node entry can execute. A pin entry with the same raw label is then dropped even if the node action is currently disabled, which can hide a usable pin action from the menu and leave the result incomplete.
|
|
||||||
@@ -87,23 +87,6 @@ bool UWingTypes::IsBlueprintable(const FEdGraphPinType &Type)
|
|||||||
return FKismetEditorUtilities::CanCreateBlueprintOfClass(Class);
|
return FKismetEditorUtilities::CanCreateBlueprintOfClass(Class);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UWingTypes::IsBlueprintable(const Info &TypeInfo)
|
|
||||||
{
|
|
||||||
// Only classes can be blueprintable.
|
|
||||||
if (TypeInfo.PinCategory != UEdGraphSchema_K2::PC_Object &&
|
|
||||||
TypeInfo.PinCategory != UEdGraphSchema_K2::PC_Interface)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// User-defined classes are already blueprints, so yes.
|
|
||||||
if (TypeInfo.IsUserDefined) return true;
|
|
||||||
|
|
||||||
// Load and check.
|
|
||||||
UClass* Class = LoadObject<UClass>(nullptr, *TypeInfo.PinSubCategoryObject);
|
|
||||||
if (!Class) return false;
|
|
||||||
return FKismetEditorUtilities::CanCreateBlueprintOfClass(Class);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool UWingTypes::IsChildOf(const FEdGraphPinType &Type, UClass *Parent)
|
bool UWingTypes::IsChildOf(const FEdGraphPinType &Type, UClass *Parent)
|
||||||
{
|
{
|
||||||
if (Type.IsContainer()) return false;
|
if (Type.IsContainer()) return false;
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
# WingTypes Bugs
|
|
||||||
|
|
||||||
## 1. Wrapped primitive types can crash the parser
|
|
||||||
`ParseWrapped()` assumes that anything inside `Soft<>`, `Class<>`, or `SoftClass<>` will resolve to an object type, but it reports the failure by dereferencing `OutType.PinSubCategoryObject` unconditionally. A wrapped primitive such as `Soft<int>` or `Class<float>` reaches the error branch with a null `PinSubCategoryObject`, so the parser crashes instead of returning a normal parse error. This is a hard failure in the type parser at [WingTypes.cpp:494-506](/home/jyelon/integration/Plugins/UEWingman/Source/UEWingman/Private/WingTypes.cpp#L494).
|
|
||||||
|
|
||||||
## 2. Delegate entries are treated as valid Blueprint types
|
|
||||||
`IsBlueprintType(const Info&)` says delegates are blocked, but the implementation only rejects `None` and then treats any entry with an empty `PinSubCategoryObject` as a valid Blueprint type. That means the reserved `Delegate` and `MCDelegate` registry entries are classified as searchable Blueprint types even though the pin-based checker explicitly rejects delegates. The mismatch makes `TypeName_Search` advertise types that cannot satisfy `Require.BlueprintType`, which is misleading for users and inconsistent with [WingTypes.cpp:104-119](/home/jyelon/integration/Plugins/UEWingman/Source/UEWingman/Private/WingTypes.cpp#L104).
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
# WingUtils Bugs
|
|
||||||
|
|
||||||
## 1. Handler names and groups strip the wrong prefix
|
|
||||||
`GetHandlerName()` and `GetHandlerGroup()` both call `RemoveFromStart(TEXT("Wing_"))` on `UClass::GetName()`, but these handler classes are named `UWing_*`. That means the prefix is never removed, so registered command names stay prefixed with `UWing_`, and the grouping logic in `WingManual::Commands()` collapses everything under the same `UWing` group instead of the intended command families.
|
|
||||||
|
|
||||||
## 2. `ReplaceMaterialWithTransientCopy()` can crash when `GEditor` is null
|
|
||||||
This helper dereferences `GEditor` unconditionally at line 553 before checking whether an editor subsystem exists. In commandlet or other headless/editor-less execution paths, that is an immediate null-deref even though the rest of the module has safer editor checks in `CheckOpenEditorForAsset()`.
|
|
||||||
|
|
||||||
## 3. `WrapText()` destroys embedded formatting
|
|
||||||
`WrapText()` tokenizes input with `ParseIntoArrayWS()`, which collapses all whitespace, including newlines and repeated spaces. That is fine for plain prose, but it loses user formatting when the function is used on graph comments in `WingGraphExport::EmitComments()`, turning multi-line comments into a single flattened paragraph instead of preserving the original text content.
|
|
||||||
@@ -513,7 +513,8 @@ bool WingVariables::ModifyGraph(WingOut Errors)
|
|||||||
|
|
||||||
UK2Node_EditablePinBase *InputNode, *OutputNode;
|
UK2Node_EditablePinBase *InputNode, *OutputNode;
|
||||||
UK2Node_FunctionEntry *LocalNode;
|
UK2Node_FunctionEntry *LocalNode;
|
||||||
if (!GetGraphNodes(InputNode, OutputNode, LocalNode, Errors)) return false;
|
bool CreateOutputNode = !OutputVariables.Variables.IsEmpty();
|
||||||
|
if (!GetGraphNodes(InputNode, OutputNode, LocalNode, CreateOutputNode, Errors)) return false;
|
||||||
|
|
||||||
for (Var &V : LocalVariables.Variables)
|
for (Var &V : LocalVariables.Variables)
|
||||||
{
|
{
|
||||||
@@ -524,6 +525,7 @@ bool WingVariables::ModifyGraph(WingOut Errors)
|
|||||||
if (V.DefaultSpecified) Desc->DefaultValue = V.DefaultValue;
|
if (V.DefaultSpecified) Desc->DefaultValue = V.DefaultValue;
|
||||||
}
|
}
|
||||||
if (!ModifyEditablePinBase(InputVariables, InputNode, Errors)) return false;
|
if (!ModifyEditablePinBase(InputVariables, InputNode, Errors)) return false;
|
||||||
|
if (OutputNode)
|
||||||
if (!ModifyEditablePinBase(OutputVariables, OutputNode, Errors)) return false;
|
if (!ModifyEditablePinBase(OutputVariables, OutputNode, Errors)) return false;
|
||||||
|
|
||||||
if (InputNode) InputNode->ReconstructNode();
|
if (InputNode) InputNode->ReconstructNode();
|
||||||
@@ -557,6 +559,7 @@ bool WingVariables::GetGraphNodes(
|
|||||||
UK2Node_EditablePinBase *&InputNode,
|
UK2Node_EditablePinBase *&InputNode,
|
||||||
UK2Node_EditablePinBase *&OutputNode,
|
UK2Node_EditablePinBase *&OutputNode,
|
||||||
UK2Node_FunctionEntry *&LocalNode,
|
UK2Node_FunctionEntry *&LocalNode,
|
||||||
|
bool CreateOutputNode,
|
||||||
WingOut Errors)
|
WingOut Errors)
|
||||||
{
|
{
|
||||||
// In theory, none of these errors should trigger, because
|
// In theory, none of these errors should trigger, because
|
||||||
@@ -573,7 +576,7 @@ bool WingVariables::GetGraphNodes(
|
|||||||
Errors.Printf(TEXT("ERROR: no function entry node for graph."));
|
Errors.Printf(TEXT("ERROR: no function entry node for graph."));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!Outputs.IsValid() && (!OutputVariables.Variables.IsEmpty()))
|
if (!Outputs.IsValid() && CreateOutputNode)
|
||||||
{
|
{
|
||||||
Outputs = FBlueprintEditorUtils::FindOrCreateFunctionResultNode(Inputs.Get());
|
Outputs = FBlueprintEditorUtils::FindOrCreateFunctionResultNode(Inputs.Get());
|
||||||
if (!Outputs.IsValid())
|
if (!Outputs.IsValid())
|
||||||
@@ -636,7 +639,8 @@ bool WingVariables::CreateGraph(WingOut Errors)
|
|||||||
|
|
||||||
UK2Node_EditablePinBase *InputNode, *OutputNode;
|
UK2Node_EditablePinBase *InputNode, *OutputNode;
|
||||||
UK2Node_FunctionEntry *LocalNode;
|
UK2Node_FunctionEntry *LocalNode;
|
||||||
if (!GetGraphNodes(InputNode, OutputNode, LocalNode, Errors)) return false;
|
bool CreateOutputNode = (!OutputVariables.Variables.IsEmpty());
|
||||||
|
if (!GetGraphNodes(InputNode, OutputNode, LocalNode, CreateOutputNode, Errors)) return false;
|
||||||
|
|
||||||
// Check for name collisions against existing local variables.
|
// Check for name collisions against existing local variables.
|
||||||
const TCHAR *ctx = TEXT("local, function input, and function output variables");
|
const TCHAR *ctx = TEXT("local, function input, and function output variables");
|
||||||
@@ -737,9 +741,14 @@ bool WingVariables::RemoveGraph(WingOut Errors)
|
|||||||
{
|
{
|
||||||
UK2Node_EditablePinBase *InputNode, *OutputNode;
|
UK2Node_EditablePinBase *InputNode, *OutputNode;
|
||||||
UK2Node_FunctionEntry *LocalNode;
|
UK2Node_FunctionEntry *LocalNode;
|
||||||
if (!GetGraphNodes(InputNode, OutputNode, LocalNode, Errors)) return false;
|
if (!GetGraphNodes(InputNode, OutputNode, LocalNode, false, Errors)) return false;
|
||||||
|
|
||||||
// Verify that all named variables exist before removing anything.
|
// Verify that all named variables exist before removing anything.
|
||||||
|
if (!OutputNode && (!OutputVariables.Variables.IsEmpty()))
|
||||||
|
{
|
||||||
|
Errors.Printf(TEXT("No output variables on this function to remove.\n"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
for (const Var& V : InputVariables.Variables)
|
for (const Var& V : InputVariables.Variables)
|
||||||
{
|
{
|
||||||
TSharedPtr<FUserPinInfo> Found =
|
TSharedPtr<FUserPinInfo> Found =
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
# WingVariables Bugs
|
|
||||||
|
|
||||||
- `CreateBlueprint()` and `CreateGraph()` are not transactional. They add variables and pins one at a time, and if a later step fails the earlier edits remain in the blueprint or graph even though the command returns `false` ([WingVariables.cpp](./WingVariables.cpp#L605), [WingVariables.cpp](./WingVariables.cpp#L632)). That leaves the editor in a partially-modified state and makes retry behavior depend on exactly where the failure occurred.
|
|
||||||
|
|
||||||
- The local-variable paths never rebuild the function entry node after changing `LocalNode->LocalVariables` or creating locals. `CreateGraph()` adds locals but only reconstructs the input/output nodes, while `ModifyGraph()` and `RemoveGraph()` edit the same backing array without calling `LocalNode->ReconstructNode()` afterward ([WingVariables.cpp](./WingVariables.cpp#L665), [WingVariables.cpp](./WingVariables.cpp#L509), [WingVariables.cpp](./WingVariables.cpp#L736)). The entry node can therefore keep stale cached state even though the underlying local-variable data changed successfully.
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# WingWidgets Bugs
|
|
||||||
|
|
||||||
## Unloaded widget blueprints are not filtered like loaded classes
|
|
||||||
The constructor filters loaded `UClass` entries for `CLASS_Abstract`, `CLASS_Deprecated`, `CLASS_NewerVersionExists`, and `CLASS_Hidden`, but the asset-registry path only checks `IsAssetLoaded()` and `GeneratedClassPath`. That means unloaded widget blueprints that are abstract or otherwise non-instantiable can still be advertised by `Widget_SearchTypes`, even though `Widget_Add` will not be able to create them successfully.
|
|
||||||
|
|
||||||
## `PrintWidgetTree()` assumes every panel slot has content
|
|
||||||
The tree dump recurses over `Panel->GetSlots()` and immediately calls `PrintWidgetTree(Slot->Content, Depth + 1)` with no null guard. If a widget tree is partially constructed or contains an empty/malformed slot, that recursive call path can dereference a nulsl child instead of skipping the slot or printing a placeholder.
|
|
||||||
@@ -178,10 +178,15 @@ private:
|
|||||||
bool CreateCustomEvent(WingOut Errors);
|
bool CreateCustomEvent(WingOut Errors);
|
||||||
bool RemoveCustomEvent(WingOut Errors);
|
bool RemoveCustomEvent(WingOut Errors);
|
||||||
|
|
||||||
|
// Get the entry, output, and local variable nodes. The
|
||||||
|
// input and local node are guaranteed to be non-null. The
|
||||||
|
// output node is not guaranteed to be non-null unless you
|
||||||
|
// pass CreateOutputNode=true.
|
||||||
bool GetGraphNodes(
|
bool GetGraphNodes(
|
||||||
UK2Node_EditablePinBase *&InputNode,
|
UK2Node_EditablePinBase *&InputNode,
|
||||||
UK2Node_EditablePinBase *&OutputNode,
|
UK2Node_EditablePinBase *&OutputNode,
|
||||||
UK2Node_FunctionEntry *&LocalNode,
|
UK2Node_FunctionEntry *&LocalNode,
|
||||||
|
bool CreateOutputNode,
|
||||||
WingOut Errors);
|
WingOut Errors);
|
||||||
|
|
||||||
bool ModifyEditablePinBase(WingVariableList &List, UK2Node_EditablePinBase *Node, WingOut Errors);
|
bool ModifyEditablePinBase(WingVariableList &List, UK2Node_EditablePinBase *Node, WingOut Errors);
|
||||||
|
|||||||
Reference in New Issue
Block a user