void FLevelCollectionModel::SaveLevels(const FLevelModelList& InLevelList)
{
if (IsReadOnly())
{
return;
}
FLevelModelList LevelModelsToSave;
TArray<ULevel*> LevelsToSave;
for (auto It = InLevelList.CreateConstIterator(); It; ++It)
{
if ((*It)->GetLevelObject())
{
if (!(*It)->IsVisible())
{
FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "UnableToSaveInvisibleLevels", "Save aborted. Levels must be made visible before they can be saved.") );
return;
}
else if ((*It)->IsLocked())
{
FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "UnableToSaveLockedLevels", "Save aborted. Level must be unlocked before it can be saved.") );
return;
}
LevelModelsToSave.Add(*It);
LevelsToSave.Add((*It)->GetLevelObject());
}
}
TArray< UPackage* > PackagesNotNeedingCheckout;
// Prompt the user to check out the levels from source control before saving
if (FEditorFileUtils::PromptToCheckoutLevels(false, LevelsToSave, &PackagesNotNeedingCheckout))
{
for (auto It = LevelsToSave.CreateIterator(); It; ++It)
{
FEditorFileUtils::SaveLevel(*It);
}
}
else if (PackagesNotNeedingCheckout.Num() > 0)
{
// The user canceled the checkout dialog but some packages didn't need to be checked out in order to save
// For each selected level if the package its in didn't need to be saved, save the level!
for (int32 LevelIdx = 0; LevelIdx < LevelsToSave.Num(); ++LevelIdx)
{
ULevel* Level = LevelsToSave[LevelIdx];
if (PackagesNotNeedingCheckout.Contains(Level->GetOutermost()))
{
FEditorFileUtils::SaveLevel(Level);
}
else
{
//remove it from the list, so that only successfully saved levels are highlighted when saving is complete
LevelModelsToSave.RemoveAt(LevelIdx);
LevelsToSave.RemoveAt(LevelIdx);
}
}
}
// Select tiles that were saved successfully
SetSelectedLevels(LevelModelsToSave);
}
void FEdModeGeometry::GetFromSource()
{
GWarn->BeginSlowTask( NSLOCTEXT("EditorModes", "GeometryMode-BeginRebuildingBSPTask", "Rebuilding BSP"), false);
TArray<HGeomMidPoints> GeomData;
// Go through each brush and update its components before updating below
for( int32 i=0; i<GeomObjects.Num(); i++ )
{
FGeomObject* GeomObject = GeomObjects[i];
if(GeomObject && GeomObject->ActualBrush)
{
#ifdef BSP_RESELECT
// Cache any information that'll help us reselect the object after it's reconstructed
CacheSelectedData( GeomData, *GeomObject );
#endif // BSP_RESELECT
GeomObject->ActualBrush->UnregisterAllComponents();
if (GeomObject->ActualBrush->GetWorld())
{
GeomObject->ActualBrush->RegisterAllComponents();
}
delete GeomObject;
}
}
GeomObjects.Empty();
TArray<FGeomBase*> SelectedGeom;
// Notify the selected actors that they have been moved.
bool bFound = true;
for ( FSelectionIterator It( GEditor->GetSelectedActorIterator() ) ; It ; ++It )
{
AActor* Actor = static_cast<AActor*>( *It );
checkSlow( Actor->IsA(AActor::StaticClass()) );
ABrush* BrushActor = Cast< ABrush >( Actor );
if ( BrushActor )
{
if( BrushActor->Brush != NULL )
{
FGeomObject* GeomObject = new FGeomObject();
GeomObject->SetParentObjectIndex( GeomObjects.Add( GeomObject ) );
GeomObject->ActualBrush = BrushActor;
GeomObject->GetFromSource();
#ifdef BSP_RESELECT
// Attempt to find all the previously selected geometry on this object if everything has gone OK so far
if ( bFound && !FindFromCache( GeomData, *GeomObject, SelectedGeom ) )
{
#ifdef BSP_RESELECT__ALL_OR_NOTHING
// If it didn't succeed, don't attempt to reselect anything as the user will only end up moving part of their previous selection
UE_LOG(LogGeometryMode, Warning, TEXT( "Unable to find all previously selected geometry data, resetting selection" ) );
SelectedGeom.Empty();
GeomData.Empty();
bFound = false;
#endif // BSP_RESELECT__ALL_OR_NOTHING
}
#endif // BSP_RESELECT
}
}
}
#ifdef BSP_RESELECT
// Reselect anything that came close to the cached midpoints
SelectCachedData( SelectedGeom );
#endif // BSP_RESELECT
GWarn->EndSlowTask();
}
void AGroupActor::AddSelectedActorsToSelectedGroup()
{
UWorld* EditorWorld = GEditor->GetEditorWorldContext().World();
if (EditorWorld)
{
int32 SelectedGroupIndex = -1;
for(int32 GroupIdx=0; GroupIdx < EditorWorld->ActiveGroupActors.Num(); ++GroupIdx )
{
AGroupActor* GroupActor = Cast<AGroupActor>(EditorWorld->ActiveGroupActors[GroupIdx]);
if( GroupActor != NULL )
{
if(GroupActor->HasSelectedActors(false))
{
// Assign the index of the selected group.
// If this is the second group we find, too many groups are selected, return.
if( SelectedGroupIndex == -1 )
{
SelectedGroupIndex = GroupIdx;
}
else
{
return;
}
}
}
}
AGroupActor* SelectedGroup = Cast<AGroupActor>(EditorWorld->ActiveGroupActors[SelectedGroupIndex]);
if( SelectedGroupIndex != -1 && SelectedGroup != NULL )
{
ULevel* GroupLevel = SelectedGroup->GetLevel();
// We've established that only one group is selected, so we can just call Add on all these actors.
// Any actors already in the group will be ignored.
TArray<AActor*> ActorsToAdd;
bool bActorsInSameLevel = true;
for ( FSelectionIterator It( GEditor->GetSelectedActorIterator() ) ; It ; ++It )
{
AActor* Actor = CastChecked<AActor>( *It );
if( Actor->GetLevel() == GroupLevel )
{
ActorsToAdd.Add( Actor );
}
else
{
bActorsInSameLevel = false;
break;
}
}
if( bActorsInSameLevel )
{
if( ActorsToAdd.Num() > 0 )
{
const FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "Group_Add", "Add Actors to Group") );
for( int32 ActorIndex = 0; ActorIndex < ActorsToAdd.Num(); ++ActorIndex )
{
if ( ActorsToAdd[ActorIndex] != SelectedGroup )
{
SelectedGroup->Add( *ActorsToAdd[ActorIndex] );
}
}
}
}
else
{
FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "Group_CantCreateGroupMultipleLevels", "Can't group the selected actors because they are in different levels.") );
}
}
}
}
void CreateSpritesFromTextures(TArray<UTexture2D*>& Textures)
{
const FString DefaultSuffix = TEXT("_Sprite");
FAssetToolsModule& AssetToolsModule = FModuleManager::Get().LoadModuleChecked<FAssetToolsModule>("AssetTools");
FContentBrowserModule& ContentBrowserModule = FModuleManager::LoadModuleChecked<FContentBrowserModule>("ContentBrowser");
TArray<UObject*> ObjectsToSync;
for (auto TextureIt = Textures.CreateConstIterator(); TextureIt; ++TextureIt)
{
UTexture2D* Texture = *TextureIt;
// Create the factory used to generate the sprite
UPaperSpriteFactory* SpriteFactory = ConstructObject<UPaperSpriteFactory>(UPaperSpriteFactory::StaticClass());
SpriteFactory->InitialTexture = Texture;
// Create the sprite
FString Name;
FString PackageName;
if (!bExtractSprites)
{
// Get a unique name for the sprite
AssetToolsModule.Get().CreateUniqueAssetName(Texture->GetOutermost()->GetName(), DefaultSuffix, /*out*/ PackageName, /*out*/ Name);
const FString PackagePath = FPackageName::GetLongPackagePath(PackageName);
if (UObject* NewAsset = AssetToolsModule.Get().CreateAsset(Name, PackagePath, UPaperSprite::StaticClass(), SpriteFactory))
{
ObjectsToSync.Add(NewAsset);
}
}
else
{
FScopedSlowTask Feedback(1, NSLOCTEXT("Paper2D", "Paper2D_ExtractSpritesFromTexture", "Extracting Sprites From Texture"));
Feedback.MakeDialog(true);
// First extract the rects from the texture
TArray<FIntRect> ExtractedRects;
UPaperSprite::ExtractRectsFromTexture(Texture, /*out*/ ExtractedRects);
// Sort the rectangles by approximate row
struct FRectangleSortHelper
{
FRectangleSortHelper(TArray<FIntRect>& InOutSprites)
{
// Sort by Y, then by X (top left corner), descending order (so we can use it as a stack from the top row down)
TArray<FIntRect> SpritesLeft = InOutSprites;
SpritesLeft.Sort([](const FIntRect& A, const FIntRect& B) { return (A.Min.Y == B.Min.Y) ? (A.Min.X > B.Min.X) : (A.Min.Y > B.Min.Y); });
InOutSprites.Reset();
// Start pulling sprites out, the first one in each row will dominate remaining ones and cause them to get labeled
TArray<FIntRect> DominatedSprites;
DominatedSprites.Empty(SpritesLeft.Num());
while (SpritesLeft.Num())
{
FIntRect DominatingSprite = SpritesLeft.Pop();
DominatedSprites.Add(DominatingSprite);
// Find the sprites that are dominated (intersect the infinite horizontal band described by the dominating sprite)
for (int32 Index = 0; Index < SpritesLeft.Num();)
{
const FIntRect& CurElement = SpritesLeft[Index];
if ((CurElement.Min.Y <= DominatingSprite.Max.Y) && (CurElement.Max.Y >= DominatingSprite.Min.Y))
{
DominatedSprites.Add(CurElement);
SpritesLeft.RemoveAt(Index, /*Count=*/ 1, /*bAllowShrinking=*/ false);
}
else
{
++Index;
}
}
// Sort the sprites in the band by X and add them to the result
DominatedSprites.Sort([](const FIntRect& A, const FIntRect& B) { return (A.Min.X < B.Min.X); });
InOutSprites.Append(DominatedSprites);
DominatedSprites.Reset();
}
}
};
FRectangleSortHelper RectSorter(ExtractedRects);
Feedback.TotalAmountOfWork = ExtractedRects.Num();
for (int ExtractedRectIndex = 0; ExtractedRectIndex < ExtractedRects.Num(); ++ExtractedRectIndex)
{
Feedback.EnterProgressFrame(1, NSLOCTEXT("Paper2D", "Paper2D_ExtractSpritesFromTexture", "Extracting Sprites From Texture"));
FIntRect& ExtractedRect = ExtractedRects[ExtractedRectIndex];
SpriteFactory->bUseSourceRegion = true;
SpriteFactory->InitialSourceUV = FVector2D(ExtractedRect.Min.X, ExtractedRect.Min.Y);
SpriteFactory->InitialSourceDimension = FVector2D(ExtractedRect.Width(), ExtractedRect.Height());
// Get a unique name for the sprite
const FString Suffix = FString::Printf(TEXT("%s_%d"), *DefaultSuffix, ExtractedRectIndex);
AssetToolsModule.Get().CreateUniqueAssetName(Texture->GetOutermost()->GetName(), Suffix, /*out*/ PackageName, /*out*/ Name);
const FString PackagePath = FPackageName::GetLongPackagePath(PackageName);
if (UObject* NewAsset = AssetToolsModule.Get().CreateAsset(Name, PackagePath, UPaperSprite::StaticClass(), SpriteFactory))
//.........这里部分代码省略.........
/** Generate a widget for the specified column name */
TSharedRef<SWidget> FPListNodeFile::GenerateWidgetForColumn(const FName& ColumnName, int32 Depth, ITableRow* RowPtr)
{
return GenerateInvalidRow(NSLOCTEXT("PListNodeArray", "PListNodeFileArrayUsesColumns", "PListNodeFile does not use columns"));
}
void AOnlineBeaconClient::NotifyControlMessage(UNetConnection* Connection, uint8 MessageType, class FInBunch& Bunch)
{
if(NetDriver->ServerConnection)
{
check(Connection == NetDriver->ServerConnection);
// We are the client
#if !(UE_BUILD_SHIPPING && WITH_EDITOR)
UE_LOG(LogNet, Log, TEXT("Beacon: Client received: %s"), FNetControlMessageInfo::GetName(MessageType));
#endif
switch (MessageType)
{
case NMT_BeaconWelcome:
{
Connection->ClientResponse = TEXT("0");
FNetControlMessage<NMT_Netspeed>::Send(Connection, Connection->CurrentNetSpeed);
FString BeaconType = GetBeaconType();
if (!BeaconType.IsEmpty())
{
FNetControlMessage<NMT_BeaconJoin>::Send(Connection, BeaconType);
NetDriver->ServerConnection->FlushNet();
}
else
{
// Force close the session
UE_LOG(LogNet, Log, TEXT("Beacon close from invalid beacon type"));
OnFailure();
}
break;
}
case NMT_BeaconAssignGUID:
{
FNetworkGUID NetGUID;
FNetControlMessage<NMT_BeaconAssignGUID>::Receive(Bunch, NetGUID);
if (NetGUID.IsValid())
{
Connection->Driver->GuidCache->RegisterNetGUID_Client( NetGUID, this );
FString BeaconType = GetBeaconType();
FNetControlMessage<NMT_BeaconNetGUIDAck>::Send(Connection, BeaconType);
// Server will send ClientOnConnected() when it gets this control message
// Fail safe for connection to server but no client connection RPC
FTimerDelegate TimerDelegate = FTimerDelegate::CreateUObject(this, &AOnlineBeaconClient::OnFailure);
GetWorldTimerManager().SetTimer(TimerHandle_OnFailure, TimerDelegate, BEACON_RPC_TIMEOUT, false);
}
else
{
// Force close the session
UE_LOG(LogNet, Log, TEXT("Beacon close from invalid NetGUID"));
OnFailure();
}
break;
}
case NMT_Upgrade:
{
// Report mismatch.
uint32 RemoteNetworkVersion;
FNetControlMessage<NMT_Upgrade>::Receive(Bunch, RemoteNetworkVersion);
// Upgrade
const FString ConnectionError = NSLOCTEXT("Engine", "ClientOutdated", "The match you are trying to join is running an incompatible version of the game. Please try upgrading your game version.").ToString();
GEngine->BroadcastNetworkFailure(GetWorld(), NetDriver, ENetworkFailure::OutdatedClient, ConnectionError);
break;
}
case NMT_Failure:
{
FString ErrorMsg;
FNetControlMessage<NMT_Failure>::Receive(Bunch, ErrorMsg);
if (ErrorMsg.IsEmpty())
{
ErrorMsg = NSLOCTEXT("NetworkErrors", "GenericBeaconConnectionFailed", "Beacon Connection Failed.").ToString();
}
// Force close the session
UE_LOG(LogNet, Log, TEXT("Beacon close from NMT_Failure %s"), *ErrorMsg);
OnFailure();
break;
}
case NMT_BeaconJoin:
case NMT_BeaconNetGUIDAck:
default:
{
// Force close the session
UE_LOG(LogNet, Log, TEXT("Beacon close from unexpected control message"));
OnFailure();
break;
}
}
}
}
请发表评论