Removed all code to save packages from the MCP

This commit is contained in:
2026-03-19 10:56:20 -04:00
parent d6cc090aca
commit 23c096b614
28 changed files with 880 additions and 251 deletions

View File

@@ -91,13 +91,11 @@ public:
// Set target skeleton
NewAnimBP->TargetSkeleton = SkeletonObj;
// Compile and save
// Compile
FKismetEditorUtilities::CompileBlueprint(NewAnimBP);
bool bSaved = WingUtils::SaveBlueprintPackage(NewAnimBP);
UWingServer::Printf(TEXT("Created: %s\n"), *AssetPath);
UWingServer::Printf(TEXT("ParentClass: %s\n"), *WingUtils::FormatName(ParentClassObj));
UWingServer::Printf(TEXT("Saved: %s\n"), bSaved ? TEXT("true") : TEXT("false"));
TArray<UEdGraph*> Graphs = WingUtils::AllGraphs(NewAnimBP);
for (UEdGraph* Graph : Graphs)

View File

@@ -126,13 +126,6 @@ public:
BS->ValidateSampleData();
// Save
bool bSaved = WingUtils::SaveGenericPackage(BS);
UWingServer::Printf(TEXT("Set %d samples on %s\n"), SamplesSet, *WingUtils::FormatName(BS));
if (!bSaved)
{
UWingServer::Print(TEXT("WARNING: package save failed\n"));
}
}
};

View File

@@ -55,11 +55,8 @@ public:
NewBS->SetSkeleton(SkeletonObj);
NewBS->MarkPackageDirty();
bool bSaved = WingUtils::SaveGenericPackage(NewBS);
UWingServer::Printf(TEXT("Created %s\n"), *NewBS->GetPathName());
UWingServer::Printf(TEXT("Skeleton: %s\n"), *SkeletonObj->GetPathName());
if (!bSaved)
UWingServer::Print(TEXT("WARNING: Package save failed\n"));
}
};

View File

@@ -112,6 +112,5 @@ public:
UWingServer::Printf(TEXT("Created custom event: %s\n"), *WingUtils::FormatName(NewEvent));
}
WingUtils::SaveBlueprintPackage(BP);
}
};

View File

@@ -87,10 +87,7 @@ public:
// Remove the graph
FString GraphName = WingUtils::FormatName(TargetGraph);
FBlueprintEditorUtils::RemoveGraph(BP, TargetGraph, EGraphRemoveFlags::Default);
bool bSaved = WingUtils::SaveBlueprintPackage(BP);
UWingServer::Printf(TEXT("Deleted %s graph %s\n"), *GraphType, *GraphName);
if (!bSaved)
UWingServer::Print(TEXT("WARNING: Package save failed.\n"));
}
};

View File

@@ -75,7 +75,6 @@ public:
}
FBlueprintEditorUtils::RenameGraph(TargetGraph, NewName);
WingUtils::SaveBlueprintPackage(BP);
UWingServer::Printf(TEXT("Renamed to %s %s\n"),
bIsFunction ? TEXT("function") : TEXT("macro"),

View File

@@ -110,8 +110,6 @@ public:
SCS->AddNode(NewNode);
}
bool bSaved = WingUtils::SaveBlueprintPackage(BP);
UWingServer::Printf(TEXT("Added component %s (%s)"),
*WingUtils::FormatName(NewNode->ComponentTemplate),
*WingUtils::FormatName(ComponentClassObj));
@@ -119,6 +117,6 @@ public:
{
UWingServer::Printf(TEXT(" under %s"), *WingUtils::FormatName(ParentSCSNode->ComponentTemplate));
}
UWingServer::Printf(TEXT("\nSaved: %s\n"), bSaved ? TEXT("true") : TEXT("false"));
UWingServer::Print(TEXT("\n"));
}
};

View File

@@ -115,7 +115,6 @@ public:
if (!EntryNode)
{
WingUtils::SaveBlueprintPackage(BP);
UWingServer::Print(TEXT("Error: Event dispatcher created but entry node not found — parameters could not be added.\n"));
return;
}
@@ -135,8 +134,6 @@ public:
}
}
WingUtils::SaveBlueprintPackage(BP);
UWingServer::Printf(TEXT("Created event dispatcher '%s'"), *DispatcherName);
if (ParamCount > 0)
UWingServer::Printf(TEXT(" with %d parameter(s)"), ParamCount);

View File

@@ -86,10 +86,6 @@ public:
// Remove the node (promotes children to parent if it has any — but we've guarded root above)
SCS->RemoveNodeAndPromoteChildren(NodeToRemove);
bool bSaved = WingUtils::SaveBlueprintPackage(BP);
UWingServer::Printf(TEXT("Removed component %s.%s\n"),
*RemovedName,
bSaved ? TEXT("") : TEXT(" WARNING: save failed."));
UWingServer::Printf(TEXT("Removed component %s.\n"), *RemovedName);
}
};

View File

@@ -25,12 +25,12 @@ public:
UPROPERTY(meta=(Description="Blueprint package path"))
FString Blueprint;
UPROPERTY(meta=(Description="New parent class: C++ class name or Blueprint package path"))
FString NewParentClass;
UPROPERTY(meta=(Description="New parent class"))
FString Parent;
virtual FString GetDescription() const override
{
return TEXT("Change a Blueprint's parent class. Accepts C++ class names or Blueprint package paths.");
return TEXT("Change a Blueprint's parent class.");
}
virtual void Handle() override
@@ -50,7 +50,6 @@ public:
BP->ParentClass = NewParentClassObj;
FBlueprintEditorUtils::RefreshAllNodes(BP);
FKismetEditorUtilities::CompileBlueprint(BP);
bool bSaved = WingUtils::SaveBlueprintPackage(BP);
UWingServer::Printf(TEXT("Reparented %s: %s -> %s\n"),
*WingUtils::FormatName(BP), *OldParentName, *WingUtils::FormatName(NewParentClassObj));

View File

@@ -62,10 +62,6 @@ public:
FEnumEditorUtils::SetEnumeratorDisplayName(NewEnum, NewIndex, FText::FromString(EnumValues[i]));
}
bool bSaved = WingUtils::SaveGenericPackage(NewEnum);
UWingServer::Printf(TEXT("Created %s with %d values\n"), *NewEnum->GetPathName(), EnumValues.Num());
if (!bSaved)
UWingServer::Print(TEXT("WARNING: Package save failed\n"));
}
};

View File

@@ -44,10 +44,6 @@ public:
if (!Description.IsEmpty())
MF->Description = Description;
bool bSaved = WingUtils::SaveGenericPackage(MF);
UWingServer::Printf(TEXT("Created %s\n"), *MF->GetPathName());
if (!bSaved)
UWingServer::Print(TEXT("WARNING: Package save failed\n"));
}
};

View File

@@ -107,9 +107,8 @@ public:
NewState->GetBoundGraph()->AddNode(SeqNode, false, false);
}
// Compile and save
// Compile
FKismetEditorUtilities::CompileBlueprint(AnimBP);
WingUtils::SaveBlueprintPackage(AnimBP);
UWingServer::Printf(TEXT("Created state '%s' in %s\n"), *StateName, *WingUtils::FormatName(SMGraph));
UWingServer::Printf(TEXT(" node: %s\n"), *WingUtils::FormatName(NewState));

View File

@@ -89,9 +89,8 @@ public:
TransNode->PriorityOrder = Priority;
TransNode->Bidirectional = BBidirectional;
// Compile and save
// Compile
FKismetEditorUtilities::CompileBlueprint(AnimBP);
WingUtils::SaveBlueprintPackage(AnimBP);
UWingServer::Printf(TEXT("Created transition %s -> %s: %s\n"),
*FromState, *ToState, *WingUtils::FormatName(TransNode));

View File

@@ -72,9 +72,8 @@ public:
StateNode->BreakAllNodeLinks();
SMGraph->RemoveNode(StateNode);
// Compile and save
// Compile
FKismetEditorUtilities::CompileBlueprint(BP);
WingUtils::SaveBlueprintPackage(BP);
UWingServer::Printf(TEXT("Removed state %s and %d transition(s).\n"),
*WingUtils::FormatName(StateNode), RemovedTransitions);

View File

@@ -97,9 +97,8 @@ public:
SeqNode->SetAnimationAsset(AnimSeq);
// Compile and save
// Compile
FKismetEditorUtilities::CompileBlueprint(AnimBP);
WingUtils::SaveBlueprintPackage(AnimBP);
if (bCreatedNew)
UWingServer::Printf(TEXT("Created sequence player in state '%s', assigned %s\n"), *StateName, *WingUtils::FormatName(AnimSeq));

View File

@@ -103,14 +103,11 @@ public:
WireVariable(AnimBP, InnerGraph, BSNode, XVariable, TEXT("X"));
WireVariable(AnimBP, InnerGraph, BSNode, YVariable, TEXT("Y"));
// Compile and save
// Compile
FKismetEditorUtilities::CompileBlueprint(AnimBP);
bool bSaved = WingUtils::SaveBlueprintPackage(AnimBP);
UWingServer::Printf(TEXT("BlendSpacePlayer %s placed in state %s\n"),
*WingUtils::FormatName(BSNode), *StateName);
if (!bSaved)
UWingServer::Print(TEXT("WARNING: Failed to save package\n"));
}
private:

View File

@@ -82,9 +82,8 @@ public:
TransNode->LogicType = (ETransitionLogicType::Type)LogicType;
TransNode->Bidirectional = BBidirectional;
// Compile and save
// Compile
FKismetEditorUtilities::CompileBlueprint(AnimBP);
WingUtils::SaveBlueprintPackage(AnimBP);
UWingServer::Printf(TEXT("Updated transition %s -> %s: %s\n"),
*FromState, *ToState, *WingUtils::FormatName(TransNode));

View File

@@ -88,12 +88,8 @@ public:
PropsAdded++;
}
bool bSaved = WingUtils::SaveGenericPackage(NewStruct);
UWingServer::Printf(TEXT("Created %s\n"), *NewStruct->GetPathName());
if (PropsAdded > 0)
UWingServer::Printf(TEXT("Properties added: %d\n"), PropsAdded);
if (!bSaved)
UWingServer::Print(TEXT("WARNING: Package save failed\n"));
}
};

View File

@@ -83,12 +83,10 @@ public:
return;
}
// Compile and save
// Compile
FKismetEditorUtilities::CompileBlueprint(NewBP);
bool bSaved = WingUtils::SaveBlueprintPackage(NewBP);
// Report result
UWingServer::Printf(TEXT("Created: %s\n"), *WingUtils::FormatName(NewBP));
if (!bSaved) UWingServer::Print(TEXT("Warning: save failed\n"));
}
};

View File

@@ -73,7 +73,6 @@ public:
return;
}
WingUtils::SaveGenericPackage(MI);
UWingServer::Printf(TEXT("Cleared override for '%s' on %s\n"),
*Parameter, *WingUtils::FormatName(MI));
}

View File

@@ -56,9 +56,6 @@ public:
// Set parent.
MI->Parent = ParentMaterialObj;
// Save.
bool bSaved = WingUtils::SaveGenericPackage(MI);
UWingServer::Printf(TEXT("Created %s\n"), *MI->GetPathName());
if (UMaterialInstance* ParentMI = Cast<UMaterialInstance>(ParentMaterialObj))
UWingServer::Printf(TEXT("Parent: %s\n"), *WingUtils::FormatName(ParentMI));
@@ -66,7 +63,5 @@ public:
UWingServer::Printf(TEXT("Parent: %s\n"), *WingUtils::FormatName(ParentMat));
else
UWingServer::Printf(TEXT("Parent: %s\n"), *ParentMaterialObj->GetPathName());
if (!bSaved)
UWingServer::Print(TEXT("WARNING: Package save failed\n"));
}
};

View File

@@ -101,8 +101,6 @@ public:
UWingServer::Printf(TEXT("Parameters of type %d (see EMaterialParameterType) are not implemented"), (int)Type);
return;
}
WingUtils::SaveGenericPackage(MI);
UWingServer::Printf(TEXT("Set '%s' = %s on %s\n"),
*Parameter, *Value, *WingUtils::FormatName(MI));
}

View File

@@ -38,8 +38,6 @@ public:
UMaterial* MaterialObj = Maker.CreateAsset<UMaterial, UMaterialFactoryNew>();
if (!MaterialObj) return;
bool bSaved = WingUtils::SaveGenericPackage(MaterialObj);
UWingServer::Printf(TEXT("Created %s\n"), *MaterialObj->GetPathName());
if (!bSaved) UWingServer::Print(TEXT("WARNING: Package save failed\n"));
}
};

View File

@@ -69,11 +69,6 @@ public:
SuccessCount++;
}
// Save.
bool bSaved = WingUtils::SaveGenericPackage(Obj);
UWingServer::Printf(TEXT("Set %d/%d properties.\n"), SuccessCount, Properties.Json->Values.Num());
if (!bSaved)
UWingServer::Print(TEXT("Warning: Save failed\n"));
}
};

View File

@@ -15,7 +15,6 @@
#include "EdGraph/EdGraphSchema.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "Kismet2/KismetEditorUtilities.h"
#include "UObject/SavePackage.h"
#include "UObject/UObjectIterator.h"
#include "UObject/UnrealType.h"
#include "Misc/Paths.h"
@@ -43,13 +42,6 @@
#include "Animation/BlendSpace.h"
#include "Engine/Texture.h"
// SEH support (Windows only) — defined in BlueprintWingServer.cpp
#if PLATFORM_WINDOWS
extern int32 TryCompileBlueprintSEH(UBlueprint* BP, EBlueprintCompileOptions Opts);
extern int32 TrySavePackageSEH(
UPackage* Package, UObject* Asset, const TCHAR* Filename,
FSavePackageArgs* SaveArgs, ESavePackageResult* OutResult);
#endif
// ============================================================
// Name sanitization
@@ -354,132 +346,6 @@ TArray<UEdGraphNode*> WingUtils::AllNodes(UBlueprint* BP)
return Nodes;
}
bool WingUtils::SaveBlueprintPackage(UBlueprint* BP)
{
UPackage* Package = BP->GetPackage();
// 1. Build absolute package filename — use .umap for map packages, .uasset otherwise
FString PackageExtension = Package->ContainsMap()
? FPackageName::GetMapPackageExtension()
: FPackageName::GetAssetPackageExtension();
FString PackageFilename = FPackageName::LongPackageNameToFilename(
Package->GetName(), PackageExtension);
PackageFilename = FPaths::ConvertRelativePathToFull(PackageFilename);
UE_LOG(LogTemp, Display, TEXT("UEWingman: Save target: %s"), *PackageFilename);
// 2. Phase 1: Try explicit compilation (same flags as UCompileAllBlueprintsCommandlet)
bool bCompiled = false;
{
EBlueprintCompileOptions CompileOpts =
EBlueprintCompileOptions::SkipSave |
EBlueprintCompileOptions::BatchCompile |
EBlueprintCompileOptions::SkipGarbageCollection |
EBlueprintCompileOptions::SkipFiBSearchMetaUpdate;
UE_LOG(LogTemp, Display, TEXT("UEWingman: Phase 1: Attempting explicit compilation..."));
#if PLATFORM_WINDOWS
int32 CompileResult = TryCompileBlueprintSEH(BP, CompileOpts);
if (CompileResult == 0)
{
bCompiled = (BP->Status == BS_UpToDate);
UE_LOG(LogTemp, Display, TEXT("UEWingman: Compilation %s (status=%d)"),
bCompiled ? TEXT("succeeded") : TEXT("completed with warnings"), (int32)BP->Status);
}
else
{
UE_LOG(LogTemp, Warning, TEXT("UEWingman: Compilation crashed (SEH), proceeding uncompiled"));
}
#else
FKismetEditorUtilities::CompileBlueprint(BP, CompileOpts, nullptr);
bCompiled = (BP->Status == BS_UpToDate);
#endif
}
// 3. Phase 2: Set guards for save
uint8 OldRegen = BP->bIsRegeneratingOnLoad;
BP->bIsRegeneratingOnLoad = true;
EBlueprintStatus OldStatus = (EBlueprintStatus)(uint8)BP->Status;
if (!bCompiled)
{
// Tell PreSave the BP is up-to-date so it doesn't try to compile
BP->Status = BS_UpToDate;
}
// 4. Clear read-only attribute if present (source control or LFS may set this)
if (FPlatformFileManager::Get().GetPlatformFile().IsReadOnly(*PackageFilename))
{
UE_LOG(LogTemp, Display, TEXT("UEWingman: Clearing read-only attribute on %s"), *PackageFilename);
FPlatformFileManager::Get().GetPlatformFile().SetReadOnly(*PackageFilename, false);
}
// 5. Phase 3: Save with SAVE_NoError + SEH protection
FSavePackageArgs SaveArgs;
SaveArgs.TopLevelFlags = RF_Public | RF_Standalone;
SaveArgs.SaveFlags = SAVE_NoError;
// For level blueprints (map packages), the base object should be the UWorld, not the BP
bool bIsMapPackage = Package->ContainsMap();
UObject* BaseObject = BP;
if (bIsMapPackage)
{
// Find the UWorld in this package — it's the actual asset for .umap files
UWorld* World = FindObject<UWorld>(Package, *Package->GetName().Mid(Package->GetName().Find(TEXT("/"), ESearchCase::IgnoreCase, ESearchDir::FromEnd) + 1));
if (!World)
{
// Fallback: iterate the package to find any UWorld
ForEachObjectWithPackage(Package, [&World](UObject* Obj) {
if (UWorld* W = Cast<UWorld>(Obj))
{
World = W;
return false; // stop
}
return true; // continue
});
}
if (World)
{
BaseObject = World;
UE_LOG(LogTemp, Display, TEXT("UEWingman: Map package detected — saving UWorld '%s'"), *World->GetName());
}
else
{
UE_LOG(LogTemp, Warning, TEXT("UEWingman: Map package detected but no UWorld found — saving with BP as base"));
}
}
ESavePackageResult SaveResult = ESavePackageResult::Error;
UE_LOG(LogTemp, Display, TEXT("UEWingman: Phase 3: Calling UPackage::Save (compiled=%s, isMap=%s)..."),
bCompiled ? TEXT("yes") : TEXT("no"), bIsMapPackage ? TEXT("yes") : TEXT("no"));
#if PLATFORM_WINDOWS
int32 SEHCode = TrySavePackageSEH(Package, BaseObject, *PackageFilename, &SaveArgs, &SaveResult);
if (SEHCode != 0)
{
UE_LOG(LogTemp, Error, TEXT("UEWingman: UPackage::Save CRASHED (SEH exception caught)"));
}
#else
FSavePackageResultStruct Result = UPackage::Save(Package, BaseObject, *PackageFilename, SaveArgs);
SaveResult = Result.Result;
#endif
// 6. Restore guards
BP->bIsRegeneratingOnLoad = OldRegen;
if (!bCompiled)
{
BP->Status = (TEnumAsByte<EBlueprintStatus>)OldStatus;
}
bool bSuccess = (SaveResult == ESavePackageResult::Success);
UE_LOG(LogTemp, Display, TEXT("UEWingman: SaveBlueprintPackage — %s for '%s' (compiled=%s, result=%d)"),
bSuccess ? TEXT("SUCCEEDED") : TEXT("FAILED"),
*BP->GetName(), bCompiled ? TEXT("yes") : TEXT("no"), (int32)SaveResult);
return bSuccess;
}
// ============================================================
// Material helpers
// ============================================================
@@ -529,43 +395,6 @@ UMaterial* WingUtils::ReplaceMaterialWithTransientCopy(UMaterial* Material)
return Material;
}
bool WingUtils::SaveGenericPackage(UObject* Asset)
{
if (!Asset) return false;
UPackage* Package = Asset->GetPackage();
UE_LOG(LogTemp, Display, TEXT("UEWingman: SaveGenericPackage — begin for '%s'"), *Asset->GetName());
FString PackageFilename = FPackageName::LongPackageNameToFilename(
Package->GetName(), FPackageName::GetAssetPackageExtension());
PackageFilename = FPaths::ConvertRelativePathToFull(PackageFilename);
if (FPlatformFileManager::Get().GetPlatformFile().IsReadOnly(*PackageFilename))
{
FPlatformFileManager::Get().GetPlatformFile().SetReadOnly(*PackageFilename, false);
}
FSavePackageArgs SaveArgs;
SaveArgs.TopLevelFlags = RF_Public | RF_Standalone;
SaveArgs.SaveFlags = SAVE_NoError;
ESavePackageResult SaveResult = ESavePackageResult::Error;
#if PLATFORM_WINDOWS
int32 SEHCode = TrySavePackageSEH(Package, Asset, *PackageFilename, &SaveArgs, &SaveResult);
if (SEHCode != 0)
{
UE_LOG(LogTemp, Error, TEXT("UEWingman: SaveGenericPackage CRASHED (SEH exception)"));
}
#else
FSavePackageResultStruct Result = UPackage::Save(Package, Asset, *PackageFilename, SaveArgs);
SaveResult = Result.Result;
#endif
bool bSuccess = (SaveResult == ESavePackageResult::Success);
UE_LOG(LogTemp, Display, TEXT("UEWingman: SaveGenericPackage — %s for '%s'"),
bSuccess ? TEXT("SUCCEEDED") : TEXT("FAILED"), *Asset->GetName());
return bSuccess;
}
// ============================================================
// Anim blueprint helpers

View File

@@ -164,11 +164,8 @@ public:
return Result;
}
static bool SaveBlueprintPackage(UBlueprint* BP);
// ----- Material helpers -----
static void EnsureMaterialGraph(UMaterial* Material);
static bool SaveGenericPackage(UObject* Asset);
// If the material editor has a transient preview copy of this material,
// return that copy (which is what the editor is actually working on).