//------------------------------------------------------------------------------ bool FEditorCategoryUtils::IsCategoryHiddenFromClass(UClass const* Class, FString const& Category) { bool bIsHidden = false; TArray<FString> ClassHideCategories; GetClassHideCategories(Class, ClassHideCategories); // run the category through sanitization so we can ensure compares will hit FString const DisplayCategory = GetCategoryDisplayString(Category); for (FString& HideCategory : ClassHideCategories) { bIsHidden = (HideCategory == DisplayCategory); if (bIsHidden) { TArray<FString> ClassShowCategories; GetClassShowCategories(Class, ClassShowCategories); // if they hid it, and showed it... favor showing (could be a shown in a sub-class, and hid in a super) bIsHidden = (ClassShowCategories.Find(DisplayCategory) == INDEX_NONE); } else // see if the category's root is hidden { TArray<FString> SubCategoryList; DisplayCategory.ParseIntoArray(&SubCategoryList, TEXT("|"), /*InCullEmpty =*/true); FString FullSubCategoryPath; for (FString const& SubCategory : SubCategoryList) { FullSubCategoryPath += SubCategory; if ((HideCategory == SubCategory) || (HideCategory == FullSubCategoryPath)) { TArray<FString> ClassShowCategories; GetClassShowCategories(Class, ClassShowCategories); // if they hid it, and showed it... favor showing (could be a shown in a sub-class, and hid in a super) bIsHidden = (ClassShowCategories.Find(DisplayCategory) == INDEX_NONE); } FullSubCategoryPath += "|"; } } if (bIsHidden) { break; } } return bIsHidden; }
/** * Recursively look for `TargetItem` in `InsertInto` and any of the descendants. * Insert `ItemToInsert` relative to the target. * Relative positioning dictated by `RelativeLocation`. * * @return true when successful. */ static bool InsertRecursive(TArray< TSharedPtr< FTestData > >& InsertInto, const TSharedRef<FTestData>& ItemToInsert, const TSharedRef<FTestData>& TargetItem, EItemDropZone RelativeLocation) { const int32 TargetIndex = InsertInto.Find(TargetItem); if (TargetIndex != INDEX_NONE) { if (RelativeLocation == EItemDropZone::AboveItem) { InsertInto.Insert(ItemToInsert, TargetIndex); } else if (RelativeLocation == EItemDropZone::BelowItem) { InsertInto.Insert(ItemToInsert, TargetIndex + 1); } else { ensure(RelativeLocation == EItemDropZone::OntoItem); InsertInto[TargetIndex]->Children.Insert(ItemToInsert, 0); } return true; } // Did not successfully remove an item. Try all the children. for (int32 ItemIndex = 0; ItemIndex < InsertInto.Num(); ++ItemIndex) { if (InsertRecursive(InsertInto[ItemIndex]->Children, ItemToInsert, TargetItem, RelativeLocation)) { return true; } } return false; }
/** * Enacts the transaction. */ void FTransaction::Apply() { checkSlow(Inc==1||Inc==-1); // Figure out direction. const int32 Start = Inc==1 ? 0 : Records.Num()-1; const int32 End = Inc==1 ? Records.Num() : -1; // Init objects. TArray<UObject*> ChangedObjects; for( int32 i=Start; i!=End; i+=Inc ) { Records[i].bRestored = false; if(ChangedObjects.Find(Records[i].Object) == INDEX_NONE) { Records[i].Object->CheckDefaultSubobjects(); Records[i].Object->PreEditUndo(); ChangedObjects.Add(Records[i].Object); } } for( int32 i=Start; i!=End; i+=Inc ) { Records[i].Restore( this ); } NumModelsModified = 0; // Count the number of UModels that were changed. for(int32 ObjectIndex = 0;ObjectIndex < ChangedObjects.Num();ObjectIndex++) { UObject* ChangedObject = ChangedObjects[ObjectIndex]; UModel* Model = Cast<UModel>(ChangedObject); if( Model && Model->Nodes.Num() ) { FBSPOps::bspBuildBounds( Model ); ++NumModelsModified; } ChangedObject->PostEditUndo(); } // Rebuild BSP here instead of waiting for the next tick since // multiple transaction events can occur in a single tick if (ABrush::NeedsRebuild()) { GEditor->RebuildAlteredBSP(); } // Flip it. if( bFlip ) { Inc *= -1; } for(int32 ObjectIndex = 0;ObjectIndex < ChangedObjects.Num();ObjectIndex++) { UObject* ChangedObject = ChangedObjects[ObjectIndex]; ChangedObject->CheckDefaultSubobjects(); } }
void CSystemCreateStats::AddStationTable (CSystem *pSystem, const CString &sStationCriteria, const CString &sLocationAttribs, TArray<CStationTableCache::SEntry> &Table) // AddStationTable // // Adds the station table. { int i; // See if we already have an entry for this table. // If we don't we add it. SEncounterTable *pEntry; if (!FindEncounterTable(Table, &pEntry)) { pEntry = m_EncounterTables.Insert(); pEntry->iLevel = pSystem->GetLevel(); pEntry->pSystemType = pSystem->GetType(); pEntry->sStationCriteria = sStationCriteria; pEntry->iCount = 1; ParseAttributes(sLocationAttribs, &pEntry->LabelAttribs); pEntry->bHasStation = false; for (i = 0; i < Table.GetCount(); i++) { pEntry->Table.Insert(Table[i].pType, Table[i].iChance); if (Table[i].pType->GetScale() == scaleStructure || Table[i].pType->GetScale() == scaleShip) pEntry->bHasStation = true; } return; } // If we already have the table we need to aggregate the entry. We start // by incrementing the count. pEntry->iCount++; // Next we remove any location/label attributes that are not common to // both tables. [We assume that if we have two identical tables then only // the attributes in common count to make the table unique.] TArray<CString> NewAttribs; ParseAttributes(sLocationAttribs, &NewAttribs); for (i = 0; i < pEntry->LabelAttribs.GetCount(); i++) { if (!NewAttribs.Find(pEntry->LabelAttribs[i])) { pEntry->LabelAttribs.Delete(i); i--; } } }
void UNiagaraGraph::GetAttributes(TArray< FNiagaraVariableInfo >& OutAttributes)const { const UNiagaraNodeOutput* OutNode = FindOutputNode(); check(OutNode); for (const FNiagaraVariableInfo& Attr : OutNode->Outputs) { check(!OutAttributes.Find(Attr)); OutAttributes.Add(Attr); } }
FLinearColor FLogVisualizer::GetColorForCategory(const FString& InFilterName) const { static TArray<FString> Filters; int32 CategoryIndex = Filters.Find(InFilterName); if (CategoryIndex == INDEX_NONE) { CategoryIndex = Filters.Add(InFilterName); } return GetColorForCategory(CategoryIndex); }
bool CDeviceClass::AccumulateEnhancements (CItemCtx &Device, CInstalledDevice *pTarget, TArray<CString> &EnhancementIDs, CItemEnhancementStack *pEnhancements) // AccumulateEnhancements // // If this device can enhance pTarget, then we add to the list of enhancements. { int i; bool bEnhanced = false; CInstalledDevice *pDevice = Device.GetDevice(); CSpaceObject *pSource = Device.GetSource(); // See if we can enhance the target device if (pDevice == NULL || (pDevice->IsEnabled() && !pDevice->IsDamaged())) { for (i = 0; i < m_Enhancements.GetCount(); i++) { // If this type of enhancement has already been applied, skip it if (!m_Enhancements[i].sType.IsBlank() && EnhancementIDs.Find(m_Enhancements[i].sType)) continue; // If we don't match the criteria, skip it. if (pSource && pTarget && !pSource->GetItemForDevice(pTarget).MatchesCriteria(m_Enhancements[i].Criteria)) continue; // Add the enhancement pEnhancements->Insert(m_Enhancements[i].Enhancement); bEnhanced = true; // Remember that we added this enhancement class if (!m_Enhancements[i].sType.IsBlank()) EnhancementIDs.Insert(m_Enhancements[i].sType); } } // Let sub-classes add their own if (OnAccumulateEnhancements(Device, pTarget, EnhancementIDs, pEnhancements)) bEnhanced = true; // Done return bEnhanced; }
void SVisualLoggerTimelinesContainer::OnObjectSelectionChanged(const TArray<FName>& RowNames) { CachedSelectedTimelines.Reset(); for (TSharedPtr<SLogVisualizerTimeline>& Timeline : TimelineItems) { if (RowNames.Find(Timeline->GetName()) != INDEX_NONE) { CachedSelectedTimelines.Add(Timeline); } } if (CachedSelectedTimelines.Num() >= 1) { FSlateApplication::Get().SetKeyboardFocus(SharedThis(CachedSelectedTimelines[CachedSelectedTimelines.Num()-1].Get()), EFocusCause::Navigation); } }
/** Add items to the output object array according to the input object set */ void Generate(EStaticMeshLightingInfoObjectSets InObjectSet, TArray< TWeakObjectPtr<UObject> >& OutObjects) { /** The levels we are gathering information for. */ TArray<ULevel*> Levels; UWorld* World = GWorld; // Fill the light list for (TObjectIterator<ULightComponent> LightIt; LightIt; ++LightIt) { ULightComponent* const Light = *LightIt; const bool bLightIsInWorld = Light->GetOwner() && !Light->GetOwner()->HasAnyFlags(RF_ClassDefaultObject) && World->ContainsActor(Light->GetOwner()); if (bLightIsInWorld) { if (Light->HasStaticLighting() || Light->HasStaticShadowing()) { // Add the light to the system's list of lights in the world. AllLights.Add(Light); } //append to the list of levels in use AddRequiredLevels( InObjectSet, World, Levels ); } } if (Levels.Num() > 0) { // Iterate over static mesh components in the list of levels... for (TObjectIterator<UStaticMeshComponent> SMCIt; SMCIt; ++SMCIt) { AActor* Owner = Cast<AActor>( (*SMCIt)->GetOwner() ); if (Owner && !Owner->HasAnyFlags(RF_ClassDefaultObject) ) { int32 Dummy; ULevel* CheckLevel = Owner->GetLevel(); if ((CheckLevel != NULL) && (Levels.Find(CheckLevel, Dummy))) { AddItem(*SMCIt, Owner, OutObjects); } } } } }
int32 DiffTreeView::CurrentDifference(TSharedRef< STreeView<TSharedPtr< FBlueprintDifferenceTreeEntry > > > TreeView, const TArray< TSharedPtr<class FBlueprintDifferenceTreeEntry> >& Differences) { auto SelectedItems = TreeView->GetSelectedItems(); if (SelectedItems.Num() == 0) { return INDEX_NONE; } for (int32 Iter = 0; Iter < SelectedItems.Num(); ++Iter) { int32 Index = Differences.Find(SelectedItems[Iter]); if (Index != INDEX_NONE) { return Index; } } return INDEX_NONE; }
void FStreamingLevelModel::OnDrop(const TSharedPtr<FLevelDragDropOp>& Op) { TArray<ULevelStreaming*> DropStreamingLevels; for (auto It = Op->StreamingLevelsToDrop.CreateConstIterator(); It; ++It) { if ((*It).IsValid()) { DropStreamingLevels.AddUnique((*It).Get()); } } // Prevent dropping items on itself if (DropStreamingLevels.Num() && DropStreamingLevels.Find(LevelStreaming.Get()) == INDEX_NONE) { UWorld* CurrentWorld = LevelCollectionModel.GetWorld(); auto& WorldStreamingLevels = CurrentWorld->StreamingLevels; // Remove streaming level objects from a world streaming levels list for (auto It : DropStreamingLevels) { WorldStreamingLevels.Remove(It); } // Find a new place where to insert the in a world streaming levels list // Right after the current level, or at start of the list in case if this is persistent level int32 InsertIndex = WorldStreamingLevels.Find(LevelStreaming.Get()); if (InsertIndex == INDEX_NONE) { InsertIndex = 0; } else { InsertIndex++; } WorldStreamingLevels.Insert(DropStreamingLevels, InsertIndex); CurrentWorld->MarkPackageDirty(); // Force levels list refresh LevelCollectionModel.PopulateLevelsList(); } }
/** * Recursively look for `ItemToRemove` in `RemoveFrom` and any of the descendants, and remove `ItemToRemove`. * @return true when successful. */ static bool RemoveRecursive(TArray< TSharedPtr< FTestData > >& RemoveFrom, const TSharedPtr<FTestData>& ItemToRemove) { int32 ItemIndex = RemoveFrom.Find(ItemToRemove); if (ItemIndex != INDEX_NONE) { RemoveFrom.RemoveAt(ItemIndex); return true; } // Did not successfully remove an item. Try all the children. for (ItemIndex = 0; ItemIndex < RemoveFrom.Num(); ++ItemIndex) { if (RemoveRecursive(RemoveFrom[ItemIndex]->Children, ItemToRemove)) { return true; } } return false; }
void UK2Node_CallArrayFunction::GetArrayTypeDependentPins(TArray<UEdGraphPin*>& OutPins) const { OutPins.Empty(); UFunction* TargetFunction = GetTargetFunction(); check(TargetFunction); const FString DependentPinMetaData = TargetFunction->GetMetaData(FBlueprintMetadata::MD_ArrayDependentParam); TArray<FString> TypeDependentPinNames; DependentPinMetaData.ParseIntoArray(TypeDependentPinNames, TEXT(","), true); for(TArray<UEdGraphPin*>::TConstIterator it(Pins); it; ++it) { UEdGraphPin* CurrentPin = *it; int32 ItemIndex = 0; if( CurrentPin && TypeDependentPinNames.Find(CurrentPin->PinName, ItemIndex) ) { OutPins.Add(CurrentPin); } } }
void UK2Node_FormatText::PinDefaultValueChanged(UEdGraphPin* Pin) { const auto FormatPin = GetFormatPin(); if(Pin == FormatPin && FormatPin->LinkedTo.Num() == 0) { const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); TArray< FString > ArgumentParams; FText::GetFormatPatternParameters(FormatPin->DefaultTextValue, ArgumentParams); PinNames.Empty(); for(auto It = ArgumentParams.CreateConstIterator(); It; ++It) { if(!FindArgumentPin(FText::FromString(*It))) { CreatePin(EGPD_Input, K2Schema->PC_Text, TEXT(""), NULL, false, false, *It); } PinNames.Add(FText::AsCultureInvariant(*It)); } for(auto It = Pins.CreateConstIterator(); It; ++It) { UEdGraphPin* CheckPin = *It; if(CheckPin != FormatPin && CheckPin->Direction == EGPD_Input) { int Index = 0; if(!ArgumentParams.Find(CheckPin->PinName, Index)) { CheckPin->BreakAllPinLinks(); Pins.Remove(CheckPin); --It; } } } GetGraph()->NotifyGraphChanged(); } }
void FBoneHierarchyBuilder::ProcessBone(FName BoneName, int32 ExpectedParentIndex, const FTransform& InitialTransform, const FString& AnimationNameForErrors, int32 TimeForErrors) { const int32 BoneNameAlreadyInsertedIndex = AllBones.Find(BoneName); if (BoneNameAlreadyInsertedIndex == INDEX_NONE) { if (ExpectedParentIndex == INDEX_NONE) { RootBones.Add(BoneName); } AllBones.Add(BoneName); ParentIndices.Add(ExpectedParentIndex); Transforms.Add(InitialTransform); } else { // Verify that the hierarchy hasn't changed if (ParentIndices[BoneNameAlreadyInsertedIndex] != ExpectedParentIndex) { UE_LOG(LogInit, Warning, TEXT("Bone hierarchy (for bone '%s') in animation '%s' was changed at time %d ms. This change will be ignored and the animation will not play properly."), *BoneName.ToString(), *AnimationNameForErrors, TimeForErrors); } } }
EReplacementResult FBlueprintNativeCodeGenModule::IsTargetedForReplacement(const UObject* Object) const { if (Object == nullptr) { return EReplacementResult::DontReplace; } const UStruct* Struct = Cast<UStruct>(Object); const UEnum* Enum = Cast<UEnum>(Object); if (Struct == nullptr && Enum == nullptr) { return EReplacementResult::DontReplace; } EReplacementResult Result = EReplacementResult::ReplaceCompletely; if (const UClass* BlueprintClass = Cast<UClass>(Struct)) { if (UBlueprint* Blueprint = Cast<UBlueprint>(BlueprintClass->ClassGeneratedBy)) { static const FBoolConfigValueHelper NativizeAnimBPOnlyWhenNonReducibleFuncitons(TEXT("BlueprintNativizationSettings"), TEXT("bNativizeAnimBPOnlyWhenNonReducibleFuncitons")); if (NativizeAnimBPOnlyWhenNonReducibleFuncitons) { if (UAnimBlueprint* AnimBlueprint = Cast<UAnimBlueprint>(Blueprint)) { ensure(AnimBlueprint->bHasBeenRegenerated); if (AnimBlueprint->bHasAnyNonReducibleFunction == UBlueprint::EIsBPNonReducible::No) { UE_LOG(LogBlueprintCodeGen, Log, TEXT("AnimBP %s without non-reducible functions is excluded from nativization"), *GetPathNameSafe(Blueprint)); Result = EReplacementResult::GenerateStub; } } } const EBlueprintType UnconvertableBlueprintTypes[] = { //BPTYPE_Const, // WTF is a "const" Blueprint? BPTYPE_MacroLibrary, BPTYPE_LevelScript, }; EBlueprintType BlueprintType = Blueprint->BlueprintType; for (int32 TypeIndex = 0; TypeIndex < ARRAY_COUNT(UnconvertableBlueprintTypes); ++TypeIndex) { if (BlueprintType == UnconvertableBlueprintTypes[TypeIndex]) { Result = EReplacementResult::GenerateStub; } } static const FBoolConfigValueHelper DontNativizeDataOnlyBP(TEXT("BlueprintNativizationSettings"), TEXT("bDontNativizeDataOnlyBP")); if (DontNativizeDataOnlyBP) { if (FBlueprintEditorUtils::IsDataOnlyBlueprint(Blueprint)) { return EReplacementResult::DontReplace; } } for (UBlueprintGeneratedClass* ParentClassIt = Cast<UBlueprintGeneratedClass>(BlueprintClass->GetSuperClass()) ; ParentClassIt; ParentClassIt = Cast<UBlueprintGeneratedClass>(ParentClassIt->GetSuperClass())) { EReplacementResult ParentResult = IsTargetedForReplacement(ParentClassIt); if (ParentResult != EReplacementResult::ReplaceCompletely) { Result = EReplacementResult::GenerateStub; } } for (TAssetSubclassOf<UBlueprint> ExcludedBlueprintTypeAsset : ExcludedBlueprintTypes) { UClass* ExcludedBPClass = ExcludedBlueprintTypeAsset.Get(); if (!ExcludedBPClass) { ExcludedBPClass = ExcludedBlueprintTypeAsset.LoadSynchronous(); } if (ExcludedBPClass && Blueprint->IsA(ExcludedBPClass)) { Result = EReplacementResult::GenerateStub; } } } } auto IsObjectFromDeveloperPackage = [](const UObject* Obj) -> bool { return Obj && Obj->GetOutermost()->HasAllPackagesFlags(PKG_Developer); }; auto IsDeveloperObject = [&](const UObject* Obj) -> bool { if (Obj) { if (IsObjectFromDeveloperPackage(Obj)) { return true; } const UStruct* StructToTest = Obj->IsA<UStruct>() ? CastChecked<const UStruct>(Obj) : Obj->GetClass(); for (; StructToTest; StructToTest = StructToTest->GetSuperStruct()) { if (IsObjectFromDeveloperPackage(StructToTest)) { return true; } } } return false; }; if (Object && (IsEditorOnlyObject(Object) || IsDeveloperObject(Object))) { UE_LOG(LogBlueprintCodeGen, Warning, TEXT("Object %s depends on Editor or Development stuff. It shouldn't be cooked."), *GetPathNameSafe(Object)); return EReplacementResult::DontReplace; } // check blacklists: // we can't use FindObject, because we may be converting a type while saving if (Enum && ExcludedAssetTypes.Find(Enum->GetPathName()) != INDEX_NONE) { Result = EReplacementResult::GenerateStub; } while (Struct) { if (ExcludedAssetTypes.Find(Struct->GetPathName()) != INDEX_NONE) { Result = EReplacementResult::GenerateStub; } Struct = Struct->GetSuperStruct(); } if (ExcludedAssets.Contains(Object->GetOutermost())) { Result = EReplacementResult::GenerateStub; } return Result; }
void FSavedCustomSortSectionInfo::Restore(USkeletalMesh* NewSkelMesh, int32 LODModelIndex, TArray<int32>& UnmatchedSections) { FStaticLODModel& LODModel = NewSkelMesh->GetImportedResource()->LODModels[LODModelIndex]; FSkeletalMeshLODInfo& LODInfo = NewSkelMesh->LODInfo[LODModelIndex]; // Re-order the UnmatchedSections so the old section index from the previous model is tried first int32 PrevSectionIndex = UnmatchedSections.Find(SavedSectionIdx); if( PrevSectionIndex != 0 && PrevSectionIndex != INDEX_NONE ) { Exchange( UnmatchedSections[0], UnmatchedSections[PrevSectionIndex] ); } // Find the strips in the old triangle data. TArray< TArray<uint32> > OldStrips[2]; for( int32 IndexCopy=0; IndexCopy < (SavedSortOption==TRISORT_CustomLeftRight ? 2 : 1); IndexCopy++ ) { const uint32* OldIndices = &SavedIndices[(SavedIndices.Num()>>1)*IndexCopy]; TArray<uint32> OldTriSet; GetConnectedTriangleSets( SavedNumTriangles, OldIndices, OldTriSet ); // Convert to strips int32 PrevTriSet = MAX_int32; for( int32 TriIndex=0;TriIndex<SavedNumTriangles; TriIndex++ ) { if( OldTriSet[TriIndex] != PrevTriSet ) { OldStrips[IndexCopy].AddZeroed(); PrevTriSet = OldTriSet[TriIndex]; } OldStrips[IndexCopy][OldStrips[IndexCopy].Num()-1].Add(OldIndices[TriIndex*3+0]); OldStrips[IndexCopy][OldStrips[IndexCopy].Num()-1].Add(OldIndices[TriIndex*3+1]); OldStrips[IndexCopy][OldStrips[IndexCopy].Num()-1].Add(OldIndices[TriIndex*3+2]); } } bool bFoundMatchingSection = false; // Try all remaining sections to find a match for( int32 UnmatchedSectionsIdx=0; !bFoundMatchingSection && UnmatchedSectionsIdx<UnmatchedSections.Num(); UnmatchedSectionsIdx++ ) { // Section of the new mesh to try int32 SectionIndex = UnmatchedSections[UnmatchedSectionsIdx]; FSkelMeshSection& Section = LODModel.Sections[SectionIndex]; TArray<uint32> Indices; LODModel.MultiSizeIndexContainer.GetIndexBuffer( Indices ); const uint32* NewSectionIndices = Indices.GetData() + Section.BaseIndex; // Build the list of triangle sets in the new mesh's section TArray<uint32> TriSet; GetConnectedTriangleSets( Section.NumTriangles, NewSectionIndices, TriSet ); // Mapping from triangle set number to the array of indices that make up the contiguous strip. TMap<uint32, TArray<uint32> > NewStripsMap; // Go through each triangle and assign it to the appropriate contiguous strip. // This is necessary if the strips in the index buffer are not contiguous. int32 Index=0; for( int32 s=0;s<TriSet.Num();s++ ) { // Store the indices for this triangle in the appropriate contiguous set. TArray<uint32>* ThisStrip = NewStripsMap.Find(TriSet[s]); if( !ThisStrip ) { ThisStrip = &NewStripsMap.Add(TriSet[s],TArray<uint32>()); } // Add the three indices for this triangle. ThisStrip->Add(NewSectionIndices[Index++]); ThisStrip->Add(NewSectionIndices[Index++]); ThisStrip->Add(NewSectionIndices[Index++]); } // Get the new vertices TArray<FSoftSkinVertex> NewVertices; LODModel.GetVertices(NewVertices); // Do the processing once for each copy if the index data for( int32 IndexCopy=0; IndexCopy < (SavedSortOption==TRISORT_CustomLeftRight ? 2 : 1); IndexCopy++ ) { // Copy strips in the new mesh's section into an array. We'll remove items from // here as we match to the old strips, so we need to keep a new copy of it each time. TArray<TArray<uint32> > NewStrips; for( TMap<uint32, TArray<uint32> >::TIterator It(NewStripsMap); It; ++It ) { NewStrips.Add(It.Value()); } // Match up old strips to new int32 NumMismatchedStrips = 0; TArray<TArray<uint32> > NewSortedStrips; // output for( int32 OsIdx=0;OsIdx<OldStrips[IndexCopy].Num();OsIdx++ ) { TArray<uint32>& OldStripIndices = OldStrips[IndexCopy][OsIdx]; int32 MatchingNewStrip = INDEX_NONE; for( int32 NsIdx=0;NsIdx<NewStrips.Num() && MatchingNewStrip==INDEX_NONE;NsIdx++ ) { // Check if we have the same number of triangles in the old and new strips. if( NewStrips[NsIdx].Num() != OldStripIndices.Num() ) { continue; } // Make a copy of the indices, as we'll remove them as we try to match triangles. TArray<uint32> NewStripIndices = NewStrips[NsIdx]; // Check if all the triangles in the new strip closely match those in the old. for( int32 OldTriIdx=0;OldTriIdx<OldStripIndices.Num();OldTriIdx+=3 ) { // Try to find a match for this triangle in the new strip. bool FoundMatch = false; for( int32 NewTriIdx=0;NewTriIdx<NewStripIndices.Num();NewTriIdx+=3 ) { if( (SavedVertices[OldStripIndices[OldTriIdx+0]] - NewVertices[NewStripIndices[NewTriIdx+0]].Position).SizeSquared() < KINDA_SMALL_NUMBER && (SavedVertices[OldStripIndices[OldTriIdx+1]] - NewVertices[NewStripIndices[NewTriIdx+1]].Position).SizeSquared() < KINDA_SMALL_NUMBER && (SavedVertices[OldStripIndices[OldTriIdx+2]] - NewVertices[NewStripIndices[NewTriIdx+2]].Position).SizeSquared() < KINDA_SMALL_NUMBER ) { // Found a triangle match. Remove the triangle from the new list and try to match the next old triangle. NewStripIndices.RemoveAt(NewTriIdx,3); FoundMatch = true; break; } } // If we didn't find a match for this old triangle, the whole strip doesn't match. if( !FoundMatch ) { break; } } if( NewStripIndices.Num() == 0 ) { // strip completely matched MatchingNewStrip = NsIdx; } } if( MatchingNewStrip != INDEX_NONE ) { NewSortedStrips.Add( NewStrips[MatchingNewStrip] ); NewStrips.RemoveAt(MatchingNewStrip); } else { NumMismatchedStrips++; } } if( IndexCopy == 0 ) { if( 100 * NumMismatchedStrips / OldStrips[0].Num() > 50 ) { // If less than 50% of this section's strips match, we assume this is not the correct section. break; } // This section matches! bFoundMatchingSection = true; // Warn the user if we couldn't match things up. if( NumMismatchedStrips ) { UnFbx::FFbxImporter* FFbxImporter = UnFbx::FFbxImporter::GetInstance(); FFbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Warning, FText::Format(LOCTEXT("RestoreSortingMismatchedStripsForSection", "While restoring \"{0}\" sort order for section {1}, {2} of {3} strips could not be matched to the new data."), FText::FromString(TriangleSortOptionToString((ETriangleSortOption)SavedSortOption)), FText::AsNumber(SavedSectionIdx), FText::AsNumber(NumMismatchedStrips), FText::AsNumber(OldStrips[0].Num())))); } // Restore the settings saved in the LODInfo (used for the UI) FTriangleSortSettings& TriangleSortSettings = LODInfo.TriangleSortSettings[SectionIndex]; TriangleSortSettings.TriangleSorting = SavedSortOption; TriangleSortSettings.CustomLeftRightAxis = SavedCustomLeftRightAxis; TriangleSortSettings.CustomLeftRightBoneName = SavedCustomLeftRightBoneName; // Restore the sorting mode. For TRISORT_CustomLeftRight, this will also make the second copy of the index data. FVector SortCenter; bool bHaveSortCenter = NewSkelMesh->GetSortCenterPoint(SortCenter); LODModel.SortTriangles(SortCenter, bHaveSortCenter, SectionIndex, (ETriangleSortOption)SavedSortOption); } // Append any strips we couldn't match to the end NewSortedStrips += NewStrips; // Export the strips out to the index buffer in order TArray<uint32> Indexes; LODModel.MultiSizeIndexContainer.GetIndexBuffer( Indexes ); uint32* NewIndices = Indexes.GetData() + (Section.BaseIndex + Section.NumTriangles*3*IndexCopy); for( int32 StripIdx=0;StripIdx<NewSortedStrips.Num();StripIdx++ ) { FMemory::Memcpy( NewIndices, &NewSortedStrips[StripIdx][0], NewSortedStrips[StripIdx].Num() * sizeof(uint32) ); // Cache-optimize the triangle order inside the final strip CacheOptimizeSortStrip( NewIndices, NewSortedStrips[StripIdx].Num() ); NewIndices += NewSortedStrips[StripIdx].Num(); } LODModel.MultiSizeIndexContainer.CopyIndexBuffer( Indexes ); } } if( !bFoundMatchingSection ) { UnFbx::FFbxImporter* FFbxImporter = UnFbx::FFbxImporter::GetInstance(); FFbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Warning, FText::Format(LOCTEXT("FailedRestoreSortingNoSectionMatch", "Unable to restore triangle sort setting \"{0}\" for section number {1} in the old mesh, as a matching section could not be found in the new mesh. The custom sorting information has been lost."), FText::FromString(TriangleSortOptionToString((ETriangleSortOption)SavedSortOption)), FText::AsNumber(SavedSectionIdx)))); } }
bool CSimpleMesh::LoadFromObjFile(char *szFileName) { TArray<VECTOR3Df> m_oVertexArray; TArray<VECTOR3Df> m_oNormalArray; TArray<VECTOR2Df> m_oTextureCoordArray; m_oMaterials.RemoveAll(); m_oMaterialNames.RemoveAll(); m_oSubsetsStartIndex.RemoveAll(); m_oSubsetsMaterialIndex.RemoveAll(); FreeTexureArray(); m_oMaterialsTextureIndex.RemoveAll(); TArray<FACE_STRUCT> oFaceBuffer; #ifdef USE_HASHTABLE_FOR_VERTEX_SEARCH THashTable<FACE_STRUCT> oFaceHash(NUM_KEYS, FACE_STRUCT::GetKey); #endif //USE_HASHTABLE_FOR_VERTEX_SEARCH TArray<unsigned short> oIndexBuffer; DELETE_OBJECT(m_poVB); DELETE_OBJECT(m_poIB); FILE *file = fopen(szFileName, "rt"); if (!file) return false; char szLine[MAX_LINE_LEN]; CString *ppsTokens; int iNumTokens; int iNumIndexes = 0; while (fgets(szLine, MAX_LINE_LEN, file)) { CString sLine(szLine); sLine.ToUpper(); sLine.Tokenize(&ppsTokens, &iNumTokens, sDelimiters); if (iNumTokens == 0) continue; if (ppsTokens[0].Equals("MTLLIB")) { LoadMaterials(ppsTokens[1]); } else if (ppsTokens[0].Equals("VN")) { m_oNormalArray.Append(VECTOR3Df(ppsTokens[1].ToFloat(), ppsTokens[2].ToFloat(), ppsTokens[3].ToFloat())); } else if (ppsTokens[0].Equals("VT")) { m_oTextureCoordArray.Append(VECTOR2Df(ppsTokens[1].ToFloat(), ppsTokens[2].ToFloat())); } else if (ppsTokens[0].Equals("V")) { m_oVertexArray.Append(VECTOR3Df(ppsTokens[1].ToFloat(), ppsTokens[2].ToFloat(), ppsTokens[3].ToFloat())); } else if (ppsTokens[0].Equals("USEMTL")) { int iMaterialIndex = m_oMaterialNames.Find(ppsTokens[1]); m_oSubsetsMaterialIndex.Append(iMaterialIndex); m_oSubsetsStartIndex.Append(oIndexBuffer.GetSize()); } else if (ppsTokens[0].Equals("F")) { struct FACE_STRUCT face; for (int i = 0; i < 3; i++) { face.iVertexIndex = ppsTokens[i * 3 + 1].ToInt() - 1; face.iTextureIndex = ppsTokens[i * 3 + 2].ToInt() - 1; face.iNormalIndex = ppsTokens[i * 3 + 3].ToInt() - 1; #ifndef USE_HASHTABLE_FOR_VERTEX_SEARCH int index = oFaceBuffer.Find(face); if (index == -1) { oIndexBuffer.Append(oFaceBuffer.GetSize()); oFaceBuffer.Append(face); } else { oIndexBuffer.Append(index); } #else FACE_STRUCT *found = oFaceHash.Find(face); if (found) { int index = found->iIndex; oIndexBuffer.Append(index); } else { face.iIndex = iNumIndexes++; oFaceHash.Insert(face); oIndexBuffer.Append(oFaceBuffer.GetSize()); oFaceBuffer.Append(face); } #endif //USE_HASHTABLE_FOR_VERTEX_SEARCH } } SAFE_DELETE_ARRAY(ppsTokens); } m_oSubsetsStartIndex.Append(oIndexBuffer.GetSize()); fclose(file); m_poIB = new CIndexBuffer(oIndexBuffer.GetSize()); memcpy(m_poIB->GetIndexBuffer(), &oIndexBuffer[0], oIndexBuffer.GetSize() * sizeof(unsigned short)); m_bHasTextures = m_oTextures.GetSize() > 0; m_bHasMaterials = m_oMaterials.GetSize() > 0; int iFormat = VERTEXFORMAT_XYZ | VERTEXFORMAT_NORMAL | (m_bHasTextures ? VERTEXFORMAT_TEXTURE : 0); m_poVB = new CVertexBuffer(iFormat, oFaceBuffer.GetSize()); int iIndex = 0, iNumVertex = oFaceBuffer.GetSize(); for (int i = 0; i < iNumVertex; i++) { float *pVertex = (float *)m_poVB->GetVertexAtIndex(i); memcpy(pVertex, &m_oVertexArray[oFaceBuffer[i].iVertexIndex], 3 * sizeof(float)); memcpy(pVertex + 3, &m_oNormalArray[oFaceBuffer[i].iNormalIndex], 3 * sizeof(float)); if (m_bHasTextures) memcpy(pVertex + 6, &m_oTextureCoordArray[oFaceBuffer[i].iTextureIndex], 2 * sizeof(float)); } return true; }
/** Tests to see if a pin is schema compatible with a property */ bool FKismetCompilerUtilities::IsTypeCompatibleWithProperty(UEdGraphPin* SourcePin, UProperty* Property, FCompilerResultsLog& MessageLog, const UEdGraphSchema_K2* Schema, UClass* SelfClass) { check(SourcePin != NULL); const FEdGraphPinType& Type = SourcePin->PinType; const EEdGraphPinDirection Direction = SourcePin->Direction; const FString& PinCategory = Type.PinCategory; const FString& PinSubCategory = Type.PinSubCategory; const UObject* PinSubCategoryObject = Type.PinSubCategoryObject.Get(); UProperty* TestProperty = NULL; const UFunction* OwningFunction = Cast<UFunction>(Property->GetOuter()); if( Type.bIsArray ) { // For arrays, the property we want to test against is the inner property if( UArrayProperty* ArrayProp = Cast<UArrayProperty>(Property) ) { if(OwningFunction) { // Check for the magic ArrayParm property, which always matches array types FString ArrayPointerMetaData = OwningFunction->GetMetaData(TEXT("ArrayParm")); TArray<FString> ArrayPinComboNames; ArrayPointerMetaData.ParseIntoArray(&ArrayPinComboNames, TEXT(","), true); for(auto Iter = ArrayPinComboNames.CreateConstIterator(); Iter; ++Iter) { TArray<FString> ArrayPinNames; Iter->ParseIntoArray(&ArrayPinNames, TEXT("|"), true); if( ArrayPinNames[0] == SourcePin->PinName ) { return true; } } } TestProperty = ArrayProp->Inner; } else { MessageLog.Error(*LOCTEXT("PinSpecifiedAsArray_Error", "Pin @@ is specified as an array, but does not have a valid array property.").ToString(), SourcePin); return false; } } else { // For scalars, we just take the passed in property TestProperty = Property; } // Check for the early out...if this is a type dependent parameter in an array function if ( (OwningFunction != NULL) && OwningFunction->HasMetaData(TEXT("ArrayParm")) ) { // Check to see if this param is type dependent on an array parameter const FString DependentParams = OwningFunction->GetMetaData(TEXT("ArrayTypeDependentParams")); TArray<FString> DependentParamNames; DependentParams.ParseIntoArray(&DependentParamNames, TEXT(","), true); if (DependentParamNames.Find(SourcePin->PinName) != INDEX_NONE) { //@todo: This assumes that the wildcard coersion has done its job...I'd feel better if there was some easier way of accessing the target array type return true; } } int32 NumErrorsAtStart = MessageLog.NumErrors; // First check the type bool bTypeMismatch = false; bool bSubtypeMismatch = false; FString DesiredSubType(TEXT("")); if (PinCategory == Schema->PC_Boolean) { UBoolProperty* SpecificProperty = Cast<UBoolProperty>(TestProperty); bTypeMismatch = (SpecificProperty == NULL); } else if (PinCategory == Schema->PC_Byte) { UByteProperty* SpecificProperty = Cast<UByteProperty>(TestProperty); bTypeMismatch = (SpecificProperty == NULL); } else if (PinCategory == Schema->PC_Class) { const UClass* ClassType = (PinSubCategory == Schema->PSC_Self) ? SelfClass : Cast<const UClass>(PinSubCategoryObject); if (ClassType == NULL) { MessageLog.Error(*FString::Printf(*LOCTEXT("FindClassForPin_Error", "Failed to find class for pin @@").ToString()), SourcePin); } else { const UClass* MetaClass = NULL; if (auto ClassProperty = Cast<UClassProperty>(TestProperty)) { MetaClass = ClassProperty->MetaClass; } else if (auto AssetClassProperty = Cast<UAssetClassProperty>(TestProperty)) { MetaClass = AssetClassProperty->MetaClass; } if (MetaClass != NULL) { DesiredSubType = MetaClass->GetName(); const UClass* OutputClass = (Direction == EGPD_Output) ? ClassType : MetaClass; const UClass* InputClass = (Direction == EGPD_Output) ? MetaClass : ClassType; // It matches if it's an exact match or if the output class is more derived than the input class bTypeMismatch = bSubtypeMismatch = !((OutputClass == InputClass) || (OutputClass->IsChildOf(InputClass))); } else { bTypeMismatch = true; } } } else if (PinCategory == Schema->PC_Float) { UFloatProperty* SpecificProperty = Cast<UFloatProperty>(TestProperty); bTypeMismatch = (SpecificProperty == NULL); } else if (PinCategory == Schema->PC_Int) { UIntProperty* SpecificProperty = Cast<UIntProperty>(TestProperty); bTypeMismatch = (SpecificProperty == NULL); } else if (PinCategory == Schema->PC_Name) { UNameProperty* SpecificProperty = Cast<UNameProperty>(TestProperty); bTypeMismatch = (SpecificProperty == NULL); } else if (PinCategory == Schema->PC_Delegate) { const UFunction* SignatureFunction = Cast<const UFunction>(PinSubCategoryObject); const UDelegateProperty* PropertyDelegate = Cast<const UDelegateProperty>(TestProperty); bTypeMismatch = !(SignatureFunction && PropertyDelegate && PropertyDelegate->SignatureFunction && PropertyDelegate->SignatureFunction->IsSignatureCompatibleWith(SignatureFunction)); } else if (PinCategory == Schema->PC_Object) { const UClass* ObjectType = (PinSubCategory == Schema->PSC_Self) ? SelfClass : Cast<const UClass>(PinSubCategoryObject); if (ObjectType == NULL) { MessageLog.Error(*FString::Printf(*LOCTEXT("FindClassForPin_Error", "Failed to find class for pin @@").ToString()), SourcePin); } else { UObjectPropertyBase* ObjProperty = Cast<UObjectPropertyBase>(TestProperty); if (ObjProperty != NULL && ObjProperty->PropertyClass) { DesiredSubType = ObjProperty->PropertyClass->GetName(); const UClass* OutputClass = (Direction == EGPD_Output) ? ObjectType : ObjProperty->PropertyClass; const UClass* InputClass = (Direction == EGPD_Output) ? ObjProperty->PropertyClass : ObjectType; // It matches if it's an exact match or if the output class is more derived than the input class bTypeMismatch = bSubtypeMismatch = !((OutputClass == InputClass) || (OutputClass->IsChildOf(InputClass))); } else if (UInterfaceProperty* IntefaceProperty = Cast<UInterfaceProperty>(TestProperty)) { UClass const* InterfaceClass = IntefaceProperty->InterfaceClass; if (InterfaceClass == NULL) { bTypeMismatch = true; } else { DesiredSubType = InterfaceClass->GetName(); bTypeMismatch = ObjectType->ImplementsInterface(InterfaceClass); } } else { bTypeMismatch = true; } } } else if (PinCategory == Schema->PC_String) { UStrProperty* SpecificProperty = Cast<UStrProperty>(TestProperty); bTypeMismatch = (SpecificProperty == NULL); } else if (PinCategory == Schema->PC_Text) { UTextProperty* SpecificProperty = Cast<UTextProperty>(TestProperty); bTypeMismatch = (SpecificProperty == NULL); } else if (PinCategory == Schema->PC_Struct) { const UScriptStruct* StructType = Cast<const UScriptStruct>(PinSubCategoryObject); if (StructType == NULL) { MessageLog.Error(*FString::Printf(*LOCTEXT("FindStructForPin_Error", "Failed to find struct for pin @@").ToString()), SourcePin); } else { UStructProperty* StructProperty = Cast<UStructProperty>(TestProperty); if (StructProperty != NULL) { DesiredSubType = StructProperty->Struct->GetName(); bSubtypeMismatch = bTypeMismatch = (StructType != StructProperty->Struct); } else { bTypeMismatch = true; } } } else { MessageLog.Error(*FString::Printf(*LOCTEXT("UnsupportedTypeForPin", "Unsupported type (%s) on @@").ToString(), *UEdGraphSchema_K2::TypeToString(Type)), SourcePin); } if (bTypeMismatch) { MessageLog.Error(*FString::Printf(*LOCTEXT("TypeDoesNotMatchPropertyOfType_Error", "@@ of type %s doesn't match the property %s of type %s").ToString(), *UEdGraphSchema_K2::TypeToString(Type), *Property->GetName(), *UEdGraphSchema_K2::TypeToString(Property)), SourcePin); } // Now check the direction if (Property->HasAnyPropertyFlags(CPF_Parm)) { // Parameters are directional const bool bOutParam = (Property->HasAnyPropertyFlags(CPF_OutParm | CPF_ReturnParm) && !(Property->HasAnyPropertyFlags(CPF_ReferenceParm))); if ( ((SourcePin->Direction == EGPD_Input) && bOutParam) || ((SourcePin->Direction == EGPD_Output) && !bOutParam)) { MessageLog.Error(*FString::Printf(*LOCTEXT("DirectionMismatchParameter_Error", "The direction of @@ doesn't match the direction of parameter %s").ToString(), *Property->GetName()), SourcePin); } if (Property->HasAnyPropertyFlags(CPF_ReferenceParm)) { TArray<FString> AutoEmittedTerms; Schema->GetAutoEmitTermParameters(OwningFunction, AutoEmittedTerms); const bool bIsAutoEmittedTerm = AutoEmittedTerms.Contains(SourcePin->PinName); // Make sure reference parameters are linked, except for FTransforms, which have a special node handler that adds an internal constant term if (!bIsAutoEmittedTerm && (SourcePin->LinkedTo.Num() == 0) && (!SourcePin->PinType.PinSubCategoryObject.IsValid() || SourcePin->PinType.PinSubCategoryObject.Get()->GetName() != TEXT("Transform")) ) { MessageLog.Error(*LOCTEXT("PassLiteral_Error", "Cannot pass a literal to @@. Connect a variable to it instead.").ToString(), SourcePin); } } } return NumErrorsAtStart == MessageLog.NumErrors; }
void ParseCompatibility() { TArray<FMD5Holder> md5array; FMD5Holder md5; FCompatValues flags; int i, x; unsigned int j; BCompatMap.Clear(); CompatParams.Clear(); // The contents of this file are not cumulative, as it should not // be present in user-distributed maps. FScanner sc(Wads.GetNumForFullName("compatibility.txt")); while (sc.GetString()) // Get MD5 signature { do { if (strlen(sc.String) != 32) { sc.ScriptError("MD5 signature must be exactly 32 characters long"); } for (i = 0; i < 32; ++i) { if (sc.String[i] >= '0' && sc.String[i] <= '9') { x = sc.String[i] - '0'; } else { sc.String[i] |= 'a' ^ 'A'; if (sc.String[i] >= 'a' && sc.String[i] <= 'f') { x = sc.String[i] - 'a' + 10; } else { x = 0; sc.ScriptError("MD5 signature must be a hexadecimal value"); } } if (!(i & 1)) { md5.Bytes[i / 2] = x << 4; } else { md5.Bytes[i / 2] |= x; } } md5array.Push(md5); sc.MustGetString(); } while (!sc.Compare("{")); memset(flags.CompatFlags, 0, sizeof(flags.CompatFlags)); flags.ExtCommandIndex = ~0u; while (sc.GetString()) { if ((i = sc.MatchString(&Options[0].Name, sizeof(*Options))) >= 0) { flags.CompatFlags[Options[i].WhichSlot] |= Options[i].CompatFlags; } else if (sc.Compare("clearlineflags")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_CLEARFLAGS); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else if (sc.Compare("setlineflags")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETFLAGS); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else if (sc.Compare("setlinespecial")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETSPECIAL); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetString(); CompatParams.Push(P_FindLineSpecial(sc.String, NULL, NULL)); for (int i = 0; i < 5; i++) { sc.MustGetNumber(); CompatParams.Push(sc.Number); } } else if (sc.Compare("clearlinespecial")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_CLEARSPECIAL); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else if (sc.Compare("setactivation")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETACTIVATION); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else if (sc.Compare("setsectoroffset")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETSECTOROFFSET); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetString(); CompatParams.Push(sc.MustMatchString(SectorPlanes)); sc.MustGetFloat(); CompatParams.Push(int(sc.Float*65536.)); } else if (sc.Compare("setsectorspecial")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETSECTORSPECIAL); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else if (sc.Compare("setwallyscale")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETWALLYSCALE); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetString(); CompatParams.Push(sc.MustMatchString(LineSides)); sc.MustGetString(); CompatParams.Push(sc.MustMatchString(WallTiers)); sc.MustGetFloat(); CompatParams.Push(int(sc.Float*65536.)); } else if (sc.Compare("setwalltexture")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETWALLTEXTURE); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetString(); CompatParams.Push(sc.MustMatchString(LineSides)); sc.MustGetString(); CompatParams.Push(sc.MustMatchString(WallTiers)); sc.MustGetString(); const FString texName = sc.String; const unsigned int texIndex = TexNames.Find(texName); const unsigned int texCount = TexNames.Size(); if (texIndex == texCount) { TexNames.Push(texName); } CompatParams.Push(texIndex); } else if (sc.Compare("setthingz")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETTHINGZ); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetFloat(); CompatParams.Push(int(sc.Float*256)); // do not use full fixed here so that it can eventually handle larger levels } else if (sc.Compare("setsectortag")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETTAG); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else if (sc.Compare("setthingflags")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETTHINGFLAGS); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else if (sc.Compare("setvertex")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETVERTEX); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetFloat(); CompatParams.Push(int(sc.Float * 256)); // do not use full fixed here so that it can eventually handle larger levels sc.MustGetFloat(); CompatParams.Push(int(sc.Float * 256)); // do not use full fixed here so that it can eventually handle larger levels flags.CompatFlags[SLOT_BCOMPAT] |= BCOMPATF_REBUILDNODES; } else if (sc.Compare("setthingskills")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETTHINGSKILLS); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else if (sc.Compare("setsectortexture")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETSECTORTEXTURE); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetString(); CompatParams.Push(sc.MustMatchString(SectorPlanes)); sc.MustGetString(); const FString texName = sc.String; const unsigned int texIndex = TexNames.Find(texName); const unsigned int texCount = TexNames.Size(); if (texIndex == texCount) { TexNames.Push(texName); } CompatParams.Push(texIndex); } else if (sc.Compare("setsectorlight")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETSECTORLIGHT); sc.MustGetNumber(); CompatParams.Push(sc.Number); sc.MustGetNumber(); CompatParams.Push(sc.Number); } else { sc.UnGet(); break; } } if (flags.ExtCommandIndex != ~0u) { CompatParams.Push(CP_END); } sc.MustGetStringName("}"); for (j = 0; j < md5array.Size(); ++j) { BCompatMap[md5array[j]] = flags; } md5array.Clear(); } }
void SSuperSearchBox::OnTextChanged(const FText& InText) { if(bIgnoreUIUpdate) { return; } const FString& InputTextStr = InputText->GetText().ToString(); if(!InputTextStr.IsEmpty()) { //search through google for online content { TSharedRef<class IHttpRequest> HttpRequest = FHttpModule::Get().CreateRequest(); // build the url FString UrlEncodedString = FPlatformHttp::UrlEncode(InText.ToString()); //we need to url encode for special characters (especially other languages) // use partial response to only look at items and things we care about for items right now (title,link and label name) const FText QueryURL = FText::Format(FText::FromString("https://www.googleapis.com/customsearch/v1?key=AIzaSyCMGfdDaSfjqv5zYoS0mTJnOT3e9MURWkU&cx=009868829633250020713:y7tfd8hlcgg&fields=items(title,link,labels/name)&q={0}+less:forums"), FText::FromString(UrlEncodedString)); //save http request into map to ensure correct ordering FText & Query = RequestQueryMap.FindOrAdd(HttpRequest); Query = InText; // kick off http request to read friends HttpRequest->OnProcessRequestComplete().BindRaw(this, &SSuperSearchBox::Query_HttpRequestComplete); HttpRequest->SetURL(QueryURL.ToString()); HttpRequest->SetHeader(TEXT("Content-Type"), TEXT("application/json")); HttpRequest->SetVerb(TEXT("GET")); HttpRequest->ProcessRequest(); } #if WITH_EDITOR //search local tutorials { FAssetRegistryModule& AssetRegistry = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry")); FARFilter Filter; Filter.ClassNames.Add(UBlueprint::StaticClass()->GetFName()); Filter.bRecursiveClasses = true; Filter.TagsAndValues.Add(TEXT("ParentClass"), FString::Printf(TEXT("%s'%s'"), *UClass::StaticClass()->GetName(), *UEditorTutorial::StaticClass()->GetPathName())); TArray<FAssetData> AssetData; AssetRegistry.Get().GetAssets(Filter, AssetData); //add search result into cache FSearchResults& SearchResults = SearchResultsCache.FindOrAdd(InText.ToString()); TArray<FSearchEntry>& TutorialResults = SearchResults.TutorialResults; TutorialResults.Empty(); for (const FAssetData& Asset : AssetData) { const FString* SearchTag = Asset.TagsAndValues.Find("SearchTags"); const FString* ResultTitle = Asset.TagsAndValues.Find("Title"); if( ResultTitle) { if (ResultTitle->Contains(InText.ToString())) { FSearchEntry SearchEntry; SearchEntry.Title = *ResultTitle; SearchEntry.URL = ""; SearchEntry.bCategory = false; SearchEntry.AssetData = Asset; TutorialResults.Add(SearchEntry); } } // If the asset has search tags, search them if ((SearchTag) && (SearchTag->IsEmpty()== false)) { TArray<FString> SearchTags; SearchTag->ParseIntoArray(SearchTags,TEXT(",")); //trim any xs spaces off the strings. for (int32 iTag = 0; iTag < SearchTags.Num() ; iTag++) { SearchTags[iTag] = SearchTags[iTag].Trim(); SearchTags[iTag] = SearchTags[iTag].TrimTrailing(); } if (SearchTags.Find(InText.ToString()) != INDEX_NONE) { FSearchEntry SearchEntry; SearchEntry.Title = *ResultTitle; SearchEntry.URL = ""; SearchEntry.bCategory = false; SearchEntry.AssetData = Asset; TutorialResults.Add(SearchEntry); } } } } #endif } else { ClearSuggestions(); } }
void CollectFilesToAdd(TArray<FPakInputPair>& OutFilesToAdd, const TArray<FPakInputPair>& InEntries, const TMap<FString, uint64>& OrderMap) { UE_LOG(LogPakFile, Display, TEXT("Collecting files to add to pak file...")); const double StartTime = FPlatformTime::Seconds(); // Start collecting files TSet<FString> AddedFiles; for (int32 Index = 0; Index < InEntries.Num(); Index++) { const FPakInputPair& Input = InEntries[Index]; const FString& Source = Input.Source; bool bCompression = Input.bNeedsCompression; bool bEncryption = Input.bNeedEncryption; FString Filename = FPaths::GetCleanFilename(Source); FString Directory = FPaths::GetPath(Source); FPaths::MakeStandardFilename(Directory); FPakFile::MakeDirectoryFromPath(Directory); if (Filename.IsEmpty()) { Filename = TEXT("*.*"); } if ( Filename.Contains(TEXT("*")) ) { // Add multiple files TArray<FString> FoundFiles; IFileManager::Get().FindFilesRecursive(FoundFiles, *Directory, *Filename, true, false); for (int32 FileIndex = 0; FileIndex < FoundFiles.Num(); FileIndex++) { FPakInputPair FileInput; FileInput.Source = FoundFiles[FileIndex]; FPaths::MakeStandardFilename(FileInput.Source); FileInput.Dest = FileInput.Source.Replace(*Directory, *Input.Dest, ESearchCase::IgnoreCase); const uint64* FoundOrder = OrderMap.Find(FileInput.Dest); if(FoundOrder) { FileInput.SuggestedOrder = *FoundOrder; } FileInput.bNeedsCompression = bCompression; FileInput.bNeedEncryption = bEncryption; if (!AddedFiles.Contains(FileInput.Source)) { OutFilesToAdd.Add(FileInput); AddedFiles.Add(FileInput.Source); } else { int32 FoundIndex; OutFilesToAdd.Find(FileInput,FoundIndex); OutFilesToAdd[FoundIndex].bNeedEncryption |= bEncryption; OutFilesToAdd[FoundIndex].bNeedsCompression |= bCompression; } } } else { // Add single file FPakInputPair FileInput; FileInput.Source = Input.Source; FPaths::MakeStandardFilename(FileInput.Source); FileInput.Dest = FileInput.Source.Replace(*Directory, *Input.Dest, ESearchCase::IgnoreCase); const uint64* FoundOrder = OrderMap.Find(FileInput.Dest); if (FoundOrder) { FileInput.SuggestedOrder = *FoundOrder; } FileInput.bNeedEncryption = bEncryption; FileInput.bNeedsCompression = bCompression; if (AddedFiles.Contains(FileInput.Source)) { int32 FoundIndex; OutFilesToAdd.Find(FileInput, FoundIndex); OutFilesToAdd[FoundIndex].bNeedEncryption |= bEncryption; OutFilesToAdd[FoundIndex].bNeedsCompression |= bCompression; } else { OutFilesToAdd.Add(FileInput); AddedFiles.Add(FileInput.Source); } } } // Sort by suggested order then alphabetically struct FInputPairSort { FORCEINLINE bool operator()(const FPakInputPair& A, const FPakInputPair& B) const { return A.SuggestedOrder == B.SuggestedOrder ? A.Dest < B.Dest : A.SuggestedOrder < B.SuggestedOrder; } }; OutFilesToAdd.Sort(FInputPairSort()); UE_LOG(LogPakFile, Display, TEXT("Collected %d files in %.2lfs."), OutFilesToAdd.Num(), FPlatformTime::Seconds() - StartTime); }
void UMorphTarget::RemapVertexIndices( USkeletalMesh* InBaseMesh, const TArray< TArray<uint32> > & BasedWedgePointIndices ) { // make sure base wedge point indices have more than what this morph target has // any morph target import needs base mesh (correct LOD index if it belongs to LOD) check ( BasedWedgePointIndices.Num() >= MorphLODModels.Num() ); check ( InBaseMesh ); // for each LOD FSkeletalMeshResource* ImportedResource = InBaseMesh->GetImportedResource(); for ( int32 LODIndex=0; LODIndex<MorphLODModels.Num(); ++LODIndex ) { FStaticLODModel & BaseLODModel = ImportedResource->LODModels[LODIndex]; FMorphTargetLODModel& MorphLODModel = MorphLODModels[LODIndex]; const TArray<uint32> & LODWedgePointIndices = BasedWedgePointIndices[LODIndex]; TArray<uint32> NewWedgePointIndices; // If the LOD has been simplified, don't remap vertex indices else the data will be useless if the mesh is unsimplified. check( LODIndex < InBaseMesh->LODInfo.Num() ); if ( InBaseMesh->LODInfo[ LODIndex ].bHasBeenSimplified ) { continue; } // copy the wedge point indices - it makes easy to find if( BaseLODModel.RawPointIndices.GetBulkDataSize() ) { NewWedgePointIndices.Empty( BaseLODModel.RawPointIndices.GetElementCount() ); NewWedgePointIndices.AddUninitialized( BaseLODModel.RawPointIndices.GetElementCount() ); FMemory::Memcpy( NewWedgePointIndices.GetData(), BaseLODModel.RawPointIndices.Lock(LOCK_READ_ONLY), BaseLODModel.RawPointIndices.GetBulkDataSize() ); BaseLODModel.RawPointIndices.Unlock(); // Source Indices used : Save it so that you don't use it twice TArray<uint32> SourceIndicesUsed; SourceIndicesUsed.Empty(MorphLODModel.Vertices.Num()); // go through all vertices for ( int32 VertIdx=0; VertIdx<MorphLODModel.Vertices.Num(); ++VertIdx ) { // Get Old Base Vertex ID uint32 OldVertIdx = MorphLODModel.Vertices[VertIdx].SourceIdx; // find PointIndices from the old list uint32 BasePointIndex = LODWedgePointIndices[OldVertIdx]; // Find the PointIndices from new list int32 NewVertIdx = NewWedgePointIndices.Find(BasePointIndex); // See if it's already used if ( SourceIndicesUsed.Find(NewVertIdx) != INDEX_NONE ) { // if used look for next right vertex index for ( int32 Iter = NewVertIdx + 1; Iter<NewWedgePointIndices.Num(); ++Iter ) { // found one if (NewWedgePointIndices[Iter] == BasePointIndex) { // see if used again if (SourceIndicesUsed.Find(Iter) == INDEX_NONE) { // if not, this slot is available // update new value MorphLODModel.Vertices[VertIdx].SourceIdx = Iter; SourceIndicesUsed.Add(Iter); break; } } } } else { // update new value MorphLODModel.Vertices[VertIdx].SourceIdx = NewVertIdx; SourceIndicesUsed.Add(NewVertIdx); } } MorphLODModel.Vertices.Sort(FCompareVertexAnimDeltas()); } } }
void FDestructibleMeshEditorViewportClient::ProcessClick( class FSceneView& View, class HHitProxy* HitProxy, FKey Key, EInputEvent Event, uint32 HitX, uint32 HitY ) { #if WITH_APEX bool bKeepSelection = Viewport->KeyState(EKeys::LeftControl) || Viewport->KeyState(EKeys::RightControl); bool bSelectionChanged = false; if (Key == EKeys::LeftMouseButton && Event == EInputEvent::IE_Released) { UDestructibleComponent* Comp = PreviewDestructibleComp.Get(); NxDestructibleAsset* Asset = Comp->DestructibleMesh->ApexDestructibleAsset; const NxRenderMeshAsset* RenderMesh = Asset->getRenderMeshAsset(); FVector2D ScreenPos(HitX, HitY); FVector ClickOrigin, ViewDir; View.DeprojectFVector2D(ScreenPos, ClickOrigin, ViewDir); float NearestHitDistance = FLT_MAX; int32 ClickedChunk = -1; for (uint32 i=0; i < Asset->getChunkCount(); ++i) { int32 PartIdx = Asset->getPartIndex(i); int32 BoneIdx = i+1; if (!Comp->IsBoneHidden(BoneIdx)) { PxBounds3 PBounds = RenderMesh->getBounds(PartIdx); FVector Center = P2UVector(PBounds.getCenter()) + Comp->GetBoneLocation(Comp->GetBoneName(BoneIdx)); FVector Extent = P2UVector(PBounds.getExtents()); FBox Bounds(Center - Extent, Center + Extent); FVector HitLoc, HitNorm; float HitTime; if (FMath::LineExtentBoxIntersection(Bounds, ClickOrigin, ClickOrigin + ViewDir * 1000.0f, FVector(0,0,0), HitLoc, HitNorm, HitTime)) { float dist = (HitLoc - ClickOrigin).SizeSquared(); if (dist < NearestHitDistance) { NearestHitDistance = dist; ClickedChunk = i; } } } } if (ClickedChunk >= 0) { int32 Idx = SelectedChunkIndices.Find(ClickedChunk); if (Idx < 0) { if (!bKeepSelection) { SelectedChunkIndices.Empty(); } SelectedChunkIndices.Add(ClickedChunk); bSelectionChanged = true; } else { SelectedChunkIndices.RemoveAt(Idx); bSelectionChanged = true; } } else if (!bKeepSelection) { SelectedChunkIndices.Empty(); bSelectionChanged = true; } } if (bSelectionChanged) { UpdateChunkSelection(SelectedChunkIndices); } #endif // WITH_APEX }
/** Determine if any pins are connected, if so make all the other pins the same type, if not, make sure pins are switched back to wildcards */ void UK2Node_Select::NotifyPinConnectionListChanged(UEdGraphPin* Pin) { Super::NotifyPinConnectionListChanged(Pin); const UEdGraphSchema_K2* Schema = GetDefault<UEdGraphSchema_K2>(); // If this is the Enum pin we need to set the enum and reconstruct the node if (Pin == GetIndexPin()) { // If the index pin was just linked to another pin if (Pin->LinkedTo.Num() > 0) { UEdGraphPin* LinkPin = Pin->LinkedTo[0]; IndexPinType = LinkPin->PinType; Pin->PinType = IndexPinType; // See if it was an enum pin if (LinkPin->PinType.PinCategory == Schema->PC_Byte && LinkPin->PinType.PinSubCategoryObject != NULL && LinkPin->PinType.PinSubCategoryObject->IsA(UEnum::StaticClass())) { UEnum* EnumPtr = Cast<UEnum>(LinkPin->PinType.PinSubCategoryObject.Get()); SetEnum(EnumPtr); } else { SetEnum(NULL); } Schema->SetPinDefaultValueBasedOnType(Pin); GetGraph()->NotifyGraphChanged(); UBlueprint* Blueprint = GetBlueprint(); if(!Blueprint->bBeingCompiled) { FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint); Blueprint->BroadcastChanged(); } // If the index pin is a boolean, we need to remove all but 2 options if (IndexPinType.PinCategory == Schema->PC_Boolean && NumOptionPins != 2) { NumOptionPins = 2; bReconstructNode = true; } } } else { // Grab references to all option pins and the return pin TArray<UEdGraphPin*> OptionPins; GetOptionPins(OptionPins); UEdGraphPin* ReturnPin = FindPin(Schema->PN_ReturnValue); // See if this pin is one of the wildcard pins bool bIsWildcardPin = (Pin == ReturnPin || OptionPins.Find(Pin) != INDEX_NONE) && Pin->PinType.PinCategory == Schema->PC_Wildcard; // If the pin was one of the wildcards we have to handle it specially if (bIsWildcardPin) { // If the pin is linked, make sure the other wildcard pins match if (Pin->LinkedTo.Num() > 0) { // Set pin type on the pin Pin->PinType = Pin->LinkedTo[0]->PinType; // Make sure the return pin is the same pin type if (ReturnPin != Pin) { ReturnPin->Modify(); ReturnPin->PinType = Pin->PinType; UEdGraphSchema_K2::ValidateExistingConnections(ReturnPin); } // Make sure all options are of the same pin type for (auto It = OptionPins.CreateConstIterator(); It; It++) { UEdGraphPin* OptionPin = (*It); if (*It && *It != Pin) { (*It)->Modify(); (*It)->PinType = Pin->PinType; UEdGraphSchema_K2::ValidateExistingConnections(*It); } } bReconstructNode = true; } } } }
/** * Should the shader for this material with the given platform, shader type and vertex * factory type combination be compiled * * @param Platform The platform currently being compiled for * @param ShaderType Which shader is being compiled * @param VertexFactory Which vertex factory is being compiled (can be NULL) * * @return true if the shader should be compiled */ virtual bool ShouldCache(EShaderPlatform Platform, const FShaderType* ShaderType, const FVertexFactoryType* VertexFactoryType) const { // only generate the needed shaders (which should be very restrictive for fast recompiling during editing) // @todo: Add a FindShaderType by fname or something if( Material->IsUIMaterial() ) { if (FCString::Stristr(ShaderType->GetName(), TEXT("TSlateMaterialShaderPS"))) { return true; } } { bool bEditorStatsMaterial = Material->bIsMaterialEditorStatsMaterial; // Always allow HitProxy shaders. if (FCString::Stristr(ShaderType->GetName(), TEXT("HitProxy"))) { return true; } // we only need local vertex factory for the preview static mesh if (VertexFactoryType != FindVertexFactoryType(FName(TEXT("FLocalVertexFactory"), FNAME_Find))) { //cache for gpu skinned vertex factory if the material allows it //this way we can have a preview skeletal mesh if (bEditorStatsMaterial || !IsUsedWithSkeletalMesh() || (VertexFactoryType != FindVertexFactoryType(FName(TEXT("TGPUSkinVertexFactoryfalse"), FNAME_Find)) && VertexFactoryType != FindVertexFactoryType(FName(TEXT("TGPUSkinVertexFactorytrue"), FNAME_Find)))) { return false; } } if (bEditorStatsMaterial) { TArray<FString> ShaderTypeNames; TArray<FString> ShaderTypeDescriptions; GetRepresentativeShaderTypesAndDescriptions(ShaderTypeNames, ShaderTypeDescriptions); //Only allow shaders that are used in the stats. return ShaderTypeNames.Find(ShaderType->GetName()) != INDEX_NONE; } // look for any of the needed type bool bShaderTypeMatches = false; // For FMaterialResource::GetRepresentativeInstructionCounts if (FCString::Stristr(ShaderType->GetName(), TEXT("BasePassPSTDistanceFieldShadowsAndLightMapPolicyHQ"))) { bShaderTypeMatches = true; } else if (FCString::Stristr(ShaderType->GetName(), TEXT("BasePassPSFNoLightMapPolicy"))) { bShaderTypeMatches = true; } else if (FCString::Stristr(ShaderType->GetName(), TEXT("CachedPointIndirectLightingPolicy"))) { bShaderTypeMatches = true; } else if (FCString::Stristr(ShaderType->GetName(), TEXT("BasePassPSFSelfShadowedTranslucencyPolicy"))) { bShaderTypeMatches = true; } // Pick tessellation shader based on material settings else if(FCString::Stristr(ShaderType->GetName(), TEXT("BasePassVSFNoLightMapPolicy")) || FCString::Stristr(ShaderType->GetName(), TEXT("BasePassHSFNoLightMapPolicy")) || FCString::Stristr(ShaderType->GetName(), TEXT("BasePassDSFNoLightMapPolicy"))) { bShaderTypeMatches = true; } else if (FCString::Stristr(ShaderType->GetName(), TEXT("DepthOnly"))) { bShaderTypeMatches = true; } else if (FCString::Stristr(ShaderType->GetName(), TEXT("ShadowDepth"))) { bShaderTypeMatches = true; } else if (FCString::Stristr(ShaderType->GetName(), TEXT("TDistortion"))) { bShaderTypeMatches = true; } else if (FCString::Stristr(ShaderType->GetName(), TEXT("TBasePassForForwardShading"))) { bShaderTypeMatches = true; } return bShaderTypeMatches; } }
//------------------------------------------------------------------------- // //------------------------------------------------------------------------- bool UnFbx::FFbxImporter::CreateAndLinkExpressionForMaterialProperty( FbxSurfaceMaterial& FbxMaterial, UMaterial* UnrealMaterial, const char* MaterialProperty , FExpressionInput& MaterialInput, bool bSetupAsNormalMap, TArray<FString>& UVSet ) { bool bCreated = false; FbxProperty FbxProperty = FbxMaterial.FindProperty( MaterialProperty ); if( FbxProperty.IsValid() ) { int32 LayeredTextureCount = FbxProperty.GetSrcObjectCount(FbxLayeredTexture::ClassId); if (LayeredTextureCount>0) { UE_LOG(LogFbxMaterialImport, Warning,TEXT("Layered TEXTures are not supported (material %s)"),ANSI_TO_TCHAR(FbxMaterial.GetName())); } else { int32 TextureCount = FbxProperty.GetSrcObjectCount(FbxTexture::ClassId); if (TextureCount>0) { for(int32 TextureIndex =0; TextureIndex<TextureCount; ++TextureIndex) { FbxFileTexture* FbxTexture = FbxProperty.GetSrcObject(FBX_TYPE(FbxFileTexture), TextureIndex); // create an unreal texture asset UTexture* UnrealTexture = ImportTexture(FbxTexture, bSetupAsNormalMap); if (UnrealTexture) { // and link it to the material UMaterialExpressionTextureSample* UnrealTextureExpression = ConstructObject<UMaterialExpressionTextureSample>( UMaterialExpressionTextureSample::StaticClass(), UnrealMaterial ); UnrealMaterial->Expressions.Add( UnrealTextureExpression ); MaterialInput.Expression = UnrealTextureExpression; UnrealTextureExpression->Texture = UnrealTexture; UnrealTextureExpression->SamplerType = bSetupAsNormalMap ? SAMPLERTYPE_Normal : SAMPLERTYPE_Color; // add/find UVSet and set it to the texture FbxString UVSetName = FbxTexture->UVSet.Get(); FString LocalUVSetName = ANSI_TO_TCHAR(UVSetName.Buffer()); int32 SetIndex = UVSet.Find(LocalUVSetName); UMaterialExpressionTextureCoordinate* MyCoordExpression = ConstructObject<UMaterialExpressionTextureCoordinate>( UMaterialExpressionTextureCoordinate::StaticClass(), UnrealMaterial ); UnrealMaterial->Expressions.Add( MyCoordExpression ); MyCoordExpression->CoordinateIndex = (SetIndex >= 0)? SetIndex: 0; UnrealTextureExpression->Coordinates.Expression = MyCoordExpression; if ( !bSetupAsNormalMap ) { UnrealMaterial->BaseColor.Expression = UnrealTextureExpression; } else { UnrealMaterial->Normal.Expression = UnrealTextureExpression; } bCreated = true; } } } if (MaterialInput.Expression) { TArray<FExpressionOutput> Outputs = MaterialInput.Expression->GetOutputs(); FExpressionOutput* Output = Outputs.GetTypedData(); MaterialInput.Mask = Output->Mask; MaterialInput.MaskR = Output->MaskR; MaterialInput.MaskG = Output->MaskG; MaterialInput.MaskB = Output->MaskB; MaterialInput.MaskA = Output->MaskA; } } } return bCreated; }
int32 FProceduralTerrainWorker::PolygonizeToTriangles( UTerrainGrid *TerrainGrid, float p_fSurfaceCrossValue, FIntVector ChunkStartSize, FIntVector ChunkEndSize, FVector &ChunkLocation, FVector &ChunkScale, FTransform &TerrainTransform, TArray<FVector> &Vertices, TArray<int32> &Indices, TArray<FVector> &Normals, TArray<FVector2D> &UVs, TArray<FColor> &VertexColors, TArray<FProcMeshTangent> &Tangents ) { // TODO? float PosX = ChunkLocation.X; float PosY = ChunkLocation.Y; float PosZ = ChunkLocation.Z; TArray<FVector> Positions; int NumTriangles = 0; for (int32 x = ChunkStartSize.X; x < ChunkEndSize.X; ++x) { for (int32 y = ChunkStartSize.Y; y < ChunkEndSize.Y; ++y) { for (int32 z = ChunkStartSize.Z; z < ChunkEndSize.Z; ++z) { // Get each points of a cube. float p0 = TerrainGrid->GetVoxel(x, y, z); float p1 = TerrainGrid->GetVoxel(x + 1, y, z); float p2 = TerrainGrid->GetVoxel(x, y + 1, z); float p3 = TerrainGrid->GetVoxel(x + 1, y + 1, z); float p4 = TerrainGrid->GetVoxel(x, y, z + 1); float p5 = TerrainGrid->GetVoxel(x + 1, y, z + 1); float p6 = TerrainGrid->GetVoxel(x, y + 1, z + 1); float p7 = TerrainGrid->GetVoxel(x + 1, y + 1, z + 1); /* Determine the index into the edge table which tells us which vertices are inside of the surface */ int crossBitMap = 0; if (p0 < p_fSurfaceCrossValue) crossBitMap |= 1; if (p1 < p_fSurfaceCrossValue) crossBitMap |= 2; if (p2 < p_fSurfaceCrossValue) crossBitMap |= 8; if (p3 < p_fSurfaceCrossValue) crossBitMap |= 4; if (p4 < p_fSurfaceCrossValue) crossBitMap |= 16; if (p5 < p_fSurfaceCrossValue) crossBitMap |= 32; if (p6 < p_fSurfaceCrossValue) crossBitMap |= 128; if (p7 < p_fSurfaceCrossValue) crossBitMap |= 64; /* Cube is entirely in/out of the surface */ int edgeBits = edgeTable[crossBitMap]; if (edgeBits == 0) continue; float interpolatedCrossingPoint = 0.0f; FVector interpolatedValues[12]; if ((edgeBits & 1) > 0) { interpolatedCrossingPoint = (p_fSurfaceCrossValue - p0) / (p1 - p0); interpolatedValues[0] = FMath::Lerp(FVector(PosX + x, PosY + y, PosZ + z), FVector(PosX + x + 1, PosY + y, PosZ + z), interpolatedCrossingPoint); } if ((edgeBits & 2) > 0) { interpolatedCrossingPoint = (p_fSurfaceCrossValue - p1) / (p3 - p1); interpolatedValues[1] = FMath::Lerp(FVector(PosX + x + 1, PosY + y, PosZ + z), FVector(PosX + x + 1, PosY + y + 1, PosZ + z), interpolatedCrossingPoint); } if ((edgeBits & 4) > 0) { interpolatedCrossingPoint = (p_fSurfaceCrossValue - p2) / (p3 - p2); interpolatedValues[2] = FMath::Lerp(FVector(PosX + x, PosY + y + 1, PosZ + z), FVector(PosX + x + 1, PosY + y + 1, PosZ + z), interpolatedCrossingPoint); } if ((edgeBits & 8) > 0) { interpolatedCrossingPoint = (p_fSurfaceCrossValue - p0) / (p2 - p0); interpolatedValues[3] = FMath::Lerp(FVector(PosX + x, PosY + y, PosZ + z), FVector(PosX + x, PosY + y + 1, PosZ + z), interpolatedCrossingPoint); } //Top four edges if ((edgeBits & 16) > 0) { interpolatedCrossingPoint = (p_fSurfaceCrossValue - p4) / (p5 - p4); interpolatedValues[4] = FMath::Lerp(FVector(PosX + x, PosY + y, PosZ + z + 1), FVector(PosX + x + 1, PosY + y, PosZ + z + 1), interpolatedCrossingPoint); } if ((edgeBits & 32) > 0) { interpolatedCrossingPoint = (p_fSurfaceCrossValue - p5) / (p7 - p5); interpolatedValues[5] = FMath::Lerp(FVector(PosX + x + 1, PosY + y, PosZ + z + 1), FVector(PosX + x + 1, PosY + y + 1, PosZ + z + 1), interpolatedCrossingPoint); } if ((edgeBits & 64) > 0) { interpolatedCrossingPoint = (p_fSurfaceCrossValue - p6) / (p7 - p6); interpolatedValues[6] = FMath::Lerp(FVector(PosX + x, PosY + y + 1, PosZ + z + 1), FVector(PosX + x + 1, PosY + y + 1, PosZ + z + 1), interpolatedCrossingPoint); } if ((edgeBits & 128) > 0) { interpolatedCrossingPoint = (p_fSurfaceCrossValue - p4) / (p6 - p4); interpolatedValues[7] = FMath::Lerp(FVector(PosX + x, PosY + y, PosZ + z + 1), FVector(PosX + x, PosY + y + 1, PosZ + z + 1), interpolatedCrossingPoint); } //Side four edges if ((edgeBits & 256) > 0) { interpolatedCrossingPoint = (p_fSurfaceCrossValue - p0) / (p4 - p0); interpolatedValues[8] = FMath::Lerp(FVector(PosX + x, PosY + y, PosZ + z), FVector(PosX + x, PosY + y, PosZ + z + 1), interpolatedCrossingPoint); } if ((edgeBits & 512) > 0) { interpolatedCrossingPoint = (p_fSurfaceCrossValue - p1) / (p5 - p1); interpolatedValues[9] = FMath::Lerp(FVector(PosX + x + 1, PosY + y, PosZ + z), FVector(PosX + x + 1, PosY + y, PosZ + z + 1), interpolatedCrossingPoint); } if ((edgeBits & 1024) > 0) { interpolatedCrossingPoint = (p_fSurfaceCrossValue - p3) / (p7 - p3); interpolatedValues[10] = FMath::Lerp(FVector(PosX + x + 1, PosY + y + 1, PosZ + z), FVector(PosX + x + 1, PosY + y + 1, PosZ + z + 1), interpolatedCrossingPoint); } if ((edgeBits & 2048) > 0) { interpolatedCrossingPoint = (p_fSurfaceCrossValue - p2) / (p6 - p2); interpolatedValues[11] = FMath::Lerp(FVector(PosX + x, PosY + y + 1, PosZ + z), FVector(PosX + x, PosY + y + 1, PosZ + z + 1), interpolatedCrossingPoint); } crossBitMap <<= 4; int triangleIndex = 0; while (triTable[crossBitMap + triangleIndex] != -1) { // For each triangle in the look up table, create a triangle and add it to the list. int index1 = triTable[crossBitMap + triangleIndex]; int index2 = triTable[crossBitMap + triangleIndex + 1]; int index3 = triTable[crossBitMap + triangleIndex + 2]; FDynamicMeshVertex Vertex0; Vertex0.Position = TerrainTransform.TransformVector(ChunkScale * interpolatedValues[index1]); FDynamicMeshVertex Vertex1; Vertex1.Position = TerrainTransform.TransformVector(ChunkScale * interpolatedValues[index2]); FDynamicMeshVertex Vertex2; Vertex2.Position = TerrainTransform.TransformVector(ChunkScale * interpolatedValues[index3]); Vertex0.TextureCoordinate.X = Vertex0.Position.X / 100.0f; Vertex0.TextureCoordinate.Y = Vertex0.Position.Y / 100.0f; Vertex1.TextureCoordinate.X = Vertex1.Position.X / 100.0f; Vertex1.TextureCoordinate.Y = Vertex1.Position.Y / 100.0f; Vertex2.TextureCoordinate.X = Vertex2.Position.X / 100.0f; Vertex2.TextureCoordinate.Y = Vertex2.Position.Y / 100.0f; // Fill Index buffer And Vertex buffer with the generated vertices. int32 VIndex0 = Positions.Find(Vertex0.Position); if (VIndex0 < 0) { VIndex0 = Positions.Add(Vertex0.Position); Indices.Add(VIndex0); Vertices.Add(Vertex0.Position); UVs.Add(FVector2D(Vertex0.TextureCoordinate)); } else { Indices.Add(VIndex0); } int32 VIndex1 = Positions.Find(Vertex1.Position); if (VIndex1 < 0) { VIndex1 = Positions.Add(Vertex1.Position); Indices.Add(VIndex1); Vertices.Add(Vertex1.Position); UVs.Add(FVector2D(Vertex1.TextureCoordinate)); } else { Indices.Add(VIndex1); } int32 VIndex2 = Positions.Find(Vertex2.Position); if (VIndex2 < 0) { VIndex2 = Positions.Add(Vertex2.Position); Indices.Add(VIndex2); Vertices.Add(Vertex2.Position); UVs.Add(FVector2D(Vertex2.TextureCoordinate)); } else { Indices.Add(VIndex2); } ++NumTriangles; triangleIndex += 3; } } } } VertexColors.SetNum(Vertices.Num(), false); Normals.SetNum(Vertices.Num(), false); Tangents.SetNum(Vertices.Num(), false); for (int32 Index = 0; Index < Indices.Num(); Index += 3) { const FVector Edge21 = Vertices[Indices[Index + 1]] - Vertices[Indices[Index + 2]]; const FVector Edge20 = Vertices[Indices[Index + 0]] - Vertices[Indices[Index + 2]]; FVector TriNormal = (Edge21 ^ Edge20).GetSafeNormal(); FVector FaceTangentX = Edge20.GetSafeNormal(); FVector FaceTangentY = (FaceTangentX ^ TriNormal).GetSafeNormal(); FVector FaceTangentZ = TriNormal; // Use Gram-Schmidt orthogonalization to make sure X is orth with Z FaceTangentX -= FaceTangentZ * (FaceTangentZ | FaceTangentX); FaceTangentX.Normalize(); // See if we need to flip TangentY when generating from cross product const bool bFlipBitangent = ((FaceTangentZ ^ FaceTangentX) | FaceTangentY) < 0.f; TriNormal.Normalize(); FaceTangentX.Normalize(); FProcMeshTangent tangent = FProcMeshTangent(FaceTangentX, bFlipBitangent); for (int32 i = 0; i < 3; i++) { Normals[Indices[Index + i]] = TriNormal; Tangents[Indices[Index + i]] = tangent; VertexColors[Indices[Index + i]] = FColor(1, 1, 1, 1); } } //UE_LOG(LogTemp, Warning, TEXT("NumTriangles: %d => %d,%d -> %d,%d"), NumTriangles, ChunkStartSize.X, ChunkStartSize.Y, ChunkEndSize.X, ChunkEndSize.Y); return NumTriangles; }
int32 UFixupRedirectsCommandlet::Main( const FString& Params ) { // Retrieve list of all packages in .ini paths. TArray<FString> PackageList; FEditorFileUtils::FindAllPackageFiles(PackageList); if( !PackageList.Num() ) { return 0; } // process the commandline FString Token; const TCHAR* CommandLine = *Params; bool bIsQuietMode = false; bool bIsTestOnly = false; bool bShouldRestoreProgress= false; bool bIsSCCDisabled = false; bool bUpdateEnginePackages = false; bool bDeleteRedirects = true; bool bDeleteOnlyReferencedRedirects = false; bool bAutoSubmit = false; bool bSandboxed = IFileManager::Get().IsSandboxEnabled(); while (FParse::Token(CommandLine, Token, 1)) { if (Token == TEXT("-nowarn")) { bIsQuietMode = true; } else if (Token == TEXT("-testonly")) { bIsTestOnly = true; } else if (Token == TEXT("-restore")) { bShouldRestoreProgress = true; } else if (Token == TEXT("-NoAutoCheckout")) { bIsSCCDisabled = true; } else if (Token == TEXT("-AutoSubmit")) { bAutoSubmit = true; } else if (Token == TEXT("-UpdateEnginePackages")) { bUpdateEnginePackages = true; } else if (Token == TEXT("-NoDelete")) { bDeleteRedirects = false; } else if (Token == TEXT("-NoDeleteUnreferenced")) { bDeleteOnlyReferencedRedirects = true; } else if ( Token.Left(1) != TEXT("-") ) { FPackageName::SearchForPackageOnDisk(Token, &GRedirectCollector.FileToFixup); } } if (bSandboxed) { UE_LOG(LogFixupRedirectsCommandlet, Display, TEXT("Running in a sandbox.")); bIsSCCDisabled = true; bAutoSubmit = false; bDeleteRedirects = false; } bool bShouldSkipErrors = false; // Setup file Output log in the Saved Directory const FString ProjectDir = FPaths::GetPath(FPaths::GetProjectFilePath()); const FString LogFilename = FPaths::Combine(*ProjectDir, TEXT("Saved"), TEXT("FixupRedirect"), TEXT("FixupRedirect.log")); FArchive* LogOutputFile = IFileManager::Get().CreateFileWriter(*LogFilename); LogOutputFile->Logf(TEXT("[Redirects]")); ///////////////////////////////////////////////////////////////////// // Display any script code referenced redirects ///////////////////////////////////////////////////////////////////// TArray<FString> UpdatePackages; TArray<FString> RedirectorsThatCantBeCleaned; if (!bShouldRestoreProgress) { // load all string asset reference targets, and add fake redirectors for them GRedirectCollector.ResolveStringAssetReference(); for (int32 RedirIndex = 0; RedirIndex < GRedirectCollector.Redirections.Num(); RedirIndex++) { FRedirection& Redir = GRedirectCollector.Redirections[RedirIndex]; UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Boot redirector can't be cleaned: %s(%s) -> %s(%s)"), *Redir.RedirectorName, *Redir.RedirectorPackageFilename, *Redir.DestinationObjectName, *Redir.PackageFilename); RedirectorsThatCantBeCleaned.AddUnique(Redir.RedirectorName); } ///////////////////////////////////////////////////////////////////// // Build a list of packages that need to be updated ///////////////////////////////////////////////////////////////////// SET_WARN_COLOR(COLOR_WHITE); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("")); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Generating list of tasks:")); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("-------------------------")); CLEAR_WARN_COLOR(); int32 GCIndex = 0; // process script code first pass, then everything else for( int32 PackageIndex = 0; PackageIndex < PackageList.Num(); PackageIndex++ ) { const FString& Filename = PackageList[PackageIndex]; // already loaded code, skip them, and skip autosave packages if (Filename.StartsWith(AutoSaveUtils::GetAutoSaveDir(), ESearchCase::IgnoreCase)) { continue; } UE_LOG(LogFixupRedirectsCommandlet, Display, TEXT("Looking for redirects in %s..."), *Filename); // Assert if package couldn't be opened so we have no chance of messing up saving later packages. UPackage* Package = Cast<UPackage>(LoadPackage(NULL, *Filename, 0)); // load all string asset reference targets, and add fake redirectors for them GRedirectCollector.ResolveStringAssetReference(); if (!Package) { SET_WARN_COLOR(COLOR_RED); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT(" ... failed to open %s"), *Filename); CLEAR_WARN_COLOR(); // if we are not in quiet mode, and the user wants to continue, go on const FText Message = FText::Format( NSLOCTEXT("Unreal", "PackageFailedToOpen", "The package '{0}' failed to open. Should this commandlet continue operation, ignoring further load errors? Continuing may have adverse effects (object references may be lost)."), FText::FromString( Filename ) ); if (bShouldSkipErrors || (!bIsQuietMode && GWarn->YesNof( Message ))) { bShouldSkipErrors = true; continue; } else { return 1; } } // all notices here about redirects get this color SET_WARN_COLOR(COLOR_DARK_GREEN); // look for any redirects that were followed that are referenced by this package // (may have been loaded earlier if this package was loaded by script code) // any redirectors referenced by script code can't be cleaned up for (int32 RedirIndex = 0; RedirIndex < GRedirectCollector.Redirections.Num(); RedirIndex++) { FRedirection& Redir = GRedirectCollector.Redirections[RedirIndex]; if (Redir.PackageFilename == Filename) { UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT(" ... references %s [-> %s]"), *Redir.RedirectorName, *Redir.DestinationObjectName); // put the source and dest packages in the list to be updated UpdatePackages.AddUnique(Redir.PackageFilename); UpdatePackages.AddUnique(Redir.RedirectorPackageFilename); } } // clear the flag for needing to collect garbage bool bNeedToCollectGarbage = false; // if this package has any redirectors, make sure we update it if (!GRedirectCollector.FileToFixup.Len() || GRedirectCollector.FileToFixup == FPackageName::FilenameToLongPackageName(Filename)) { TArray<UObject *> ObjectsInOuter; GetObjectsWithOuter(Package, ObjectsInOuter); for( int32 Index = 0; Index < ObjectsInOuter.Num(); Index++ ) { UObject* Obj = ObjectsInOuter[Index]; UObjectRedirector* Redir = Cast<UObjectRedirector>(Obj); if (Redir) { // make sure this package is in the list of packages to update UpdatePackages.AddUnique(Filename); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT(" ... has redirect %s [-> %s]"), *Redir->GetPathName(), *Redir->DestinationObject->GetFullName()); LogOutputFile->Logf(TEXT("%s = %s"), *Redir->GetPathName(), *Redir->DestinationObject->GetFullName()); // make sure we GC if we found a redirector bNeedToCollectGarbage = true; } } } CLEAR_WARN_COLOR(); // collect garbage every N packages, or if there was any redirectors in the package // (to make sure that redirectors get reloaded properly and followed by the callback) // also, GC after loading a map package, to make sure it's unloaded so that we can track // other packages loading a map package as a dependency if (((++GCIndex) % 50) == 0 || bNeedToCollectGarbage || Package->ContainsMap()) { // collect garbage to close the package CollectGarbage(RF_Native); UE_LOG(LogFixupRedirectsCommandlet, Display, TEXT("GC...")); // reset our counter GCIndex = 0; } } // save off restore point FArchive* Ar = IFileManager::Get().CreateFileWriter(*(FPaths::GameSavedDir() + TEXT("Fixup.bin"))); *Ar << GRedirectCollector.Redirections; *Ar << UpdatePackages; *Ar << RedirectorsThatCantBeCleaned; delete Ar; } else { // load restore point FArchive* Ar = IFileManager::Get().CreateFileReader(*(FPaths::GameSavedDir() + TEXT("Fixup.bin"))); if( Ar != NULL ) { *Ar << GRedirectCollector.Redirections; *Ar << UpdatePackages; *Ar << RedirectorsThatCantBeCleaned; delete Ar; } } // unregister the callback so we stop getting redirections added FCoreUObjectDelegates::RedirectorFollowed.RemoveAll(&GRedirectCollector); ///////////////////////////////////////////////////////////////////// // Explain to user what is happening ///////////////////////////////////////////////////////////////////// SET_WARN_COLOR(COLOR_YELLOW); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("")); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Files that need to fixed up:")); SET_WARN_COLOR(COLOR_DARK_YELLOW); // print out the working set of packages for (int32 PackageIndex = 0; PackageIndex < UpdatePackages.Num(); PackageIndex++) { UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT(" %s"), *UpdatePackages[PackageIndex]); } UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("")); CLEAR_WARN_COLOR(); // if we are only testing, just just quiet before actually doing anything if (bIsTestOnly) { LogOutputFile->Close(); delete LogOutputFile; LogOutputFile = NULL; return 0; } ///////////////////////////////////////////////////////////////////// // Find redirectors that are referenced by packages we cant check out ///////////////////////////////////////////////////////////////////// bool bEngineRedirectorCantBeCleaned = false; ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider(); // initialize source control if it hasn't been initialized yet if(!bIsSCCDisabled) { SourceControlProvider.Init(); //Make sure we can check out all packages - update their state first SourceControlProvider.Execute(ISourceControlOperation::Create<FUpdateStatus>(), UpdatePackages); } for( int32 PackageIndex = 0; PackageIndex < UpdatePackages.Num(); PackageIndex++ ) { const FString& Filename = UpdatePackages[PackageIndex]; bool bCanEdit = true; if(!bIsSCCDisabled) { FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(Filename, EStateCacheUsage::ForceUpdate); if(SourceControlState.IsValid() && !SourceControlState->CanEdit()) { bCanEdit = false; } } else if(IFileManager::Get().IsReadOnly(*Filename)) { bCanEdit = false; } if(!bCanEdit) { const bool bAllowCheckout = bUpdateEnginePackages || !Filename.StartsWith( FPaths::EngineDir() ); if (!bIsSCCDisabled && bAllowCheckout) { FString PackageName(FPackageName::FilenameToLongPackageName(Filename)); FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(Filename, EStateCacheUsage::ForceUpdate); if (SourceControlState.IsValid() && SourceControlState->CanCheckout()) { SourceControlProvider.Execute(ISourceControlOperation::Create<FCheckOut>(), SourceControlHelpers::PackageFilename(PackageName)); FSourceControlStatePtr NewSourceControlState = SourceControlProvider.GetState(Filename, EStateCacheUsage::ForceUpdate); bCanEdit = NewSourceControlState.IsValid() && NewSourceControlState->CanEdit(); } } // if the checkout failed for any reason, we can't clean it up if (bAllowCheckout && !bCanEdit) { SET_WARN_COLOR(COLOR_RED); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Couldn't check out/edit %s..."), *Filename); CLEAR_WARN_COLOR(); // load all string asset reference targets, and add fake redirectors for them GRedirectCollector.ResolveStringAssetReference(); // any redirectors that are pointed to by this read-only package can't be fixed up for (int32 RedirIndex = 0; RedirIndex < GRedirectCollector.Redirections.Num(); RedirIndex++) { FRedirection& Redir = GRedirectCollector.Redirections[RedirIndex]; // any redirectors pointed to by this file we don't clean if (Redir.PackageFilename == Filename) { RedirectorsThatCantBeCleaned.AddUnique(Redir.RedirectorName); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT(" ... can't fixup references to %s"), *Redir.RedirectorName); // if this redirector is in an Engine package, we need to alert the user, because // Engine packages are shared between games, so if one game still needs the redirector // to be valid, then we can't check in Engine packages after another game has // run that could if (!bEngineRedirectorCantBeCleaned) { FString PackagePath; FPackageName::DoesPackageExist(Redir.RedirectorPackageFilename, NULL, &PackagePath); if (PackagePath.StartsWith(FPaths::EngineDir())) { bEngineRedirectorCantBeCleaned = true; } } } // any redirectors in this file can't be deleted else if (Redir.RedirectorPackageFilename == Filename) { RedirectorsThatCantBeCleaned.AddUnique(Redir.RedirectorName); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT(" ... can't delete %s"), *Redir.RedirectorName); } } } else { SET_WARN_COLOR(COLOR_DARK_GREEN); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Checked out %s..."), *Filename); CLEAR_WARN_COLOR(); } } } // warn about an engine package that can't be cleaned up (may want to revert engine packages) if (bEngineRedirectorCantBeCleaned) { UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("")); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Engine package redirectors are referenced by packages that can't be cleaned. If you have multiple games, it's recommended you revert any checked out Engine packages.")); bUpdateEnginePackages=false; } UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("")); ///////////////////////////////////////////////////////////////////// // Load and save packages to save out the proper fixed up references ///////////////////////////////////////////////////////////////////// SET_WARN_COLOR(COLOR_WHITE); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Fixing references to point to proper objects:")); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("---------------------------------------------")); CLEAR_WARN_COLOR(); // keep a list of all packages that have ObjectRedirects in them. This is not needed if we aren't deleting redirects TArray<bool> PackagesWithRedirects; // Delete these packages entirely because they are empty TArray<bool> EmptyPackagesToDelete; if ( bDeleteRedirects ) { PackagesWithRedirects.AddZeroed(UpdatePackages.Num()); EmptyPackagesToDelete.AddZeroed(PackageList.Num()); } bool bSCCEnabled = ISourceControlModule::Get().IsEnabled(); // Iterate over all packages, loading and saving to remove all references to ObjectRedirectors (can't delete the Redirects yet) for( int32 PackageIndex = 0; PackageIndex < UpdatePackages.Num(); PackageIndex++ ) { const FString& Filename = UpdatePackages[PackageIndex]; // we can't do anything with packages that are read-only or cant be edited due to source control (we don't want to fixup the redirects) if(bSCCEnabled) { FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(SourceControlHelpers::PackageFilename(Filename), EStateCacheUsage::ForceUpdate); if(SourceControlState.IsValid() && !SourceControlState->CanEdit()) { continue; } } else if(IFileManager::Get().IsReadOnly(*Filename)) { continue; } // Assert if package couldn't be opened so we have no chance of messing up saving later packages. UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Cleaning %s"), *Filename); UPackage* Package = LoadPackage( NULL, *Filename, LOAD_NoVerify ); // load all string asset reference targets, and add fake redirectors for them GRedirectCollector.ResolveStringAssetReference(); // if it failed to open, we have already dealt with quitting if we are going to, so just skip it if (!Package) { continue; } if ( bDeleteOnlyReferencedRedirects && bDeleteRedirects ) { TArray<UObject *> ObjectsInOuter; GetObjectsWithOuter(Package, ObjectsInOuter); for( int32 Index = 0; Index < ObjectsInOuter.Num(); Index++ ) { UObject* Obj = ObjectsInOuter[Index]; UObjectRedirector* Redir = Cast<UObjectRedirector>(Obj); if (Redir) { PackagesWithRedirects[PackageIndex] = 1; break; } } } // Don't save packages in the engine directory if we did not opt to update engine packages if( bUpdateEnginePackages || !Filename.StartsWith( FPaths::EngineDir() ) ) { // save out the package UWorld* World = UWorld::FindWorldInPackage(Package); GEditor->SavePackage( Package, World, World ? RF_NoFlags : RF_Standalone, *Filename, GWarn ); } // collect garbage to close the package UE_LOG(LogFixupRedirectsCommandlet, Display, TEXT("Collecting Garbage...")); CollectGarbage(RF_Native); } UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("")); if ( bDeleteRedirects ) { ///////////////////////////////////////////////////////////////////// // Delete all redirects that are no longer referenced ///////////////////////////////////////////////////////////////////// SET_WARN_COLOR(COLOR_WHITE); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Deleting redirector objects:")); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("----------------------------")); CLEAR_WARN_COLOR(); const TArray<FString>& PackagesToCleaseOfRedirects = bDeleteOnlyReferencedRedirects ? UpdatePackages : PackageList; int32 GCIndex = 0; // Again, iterate over all packages, loading and saving to and this time deleting all for( int32 PackageIndex = 0; PackageIndex < PackagesToCleaseOfRedirects.Num(); PackageIndex++ ) { const FString& Filename = PackagesToCleaseOfRedirects[PackageIndex]; if (bDeleteOnlyReferencedRedirects && PackagesWithRedirects[PackageIndex] == 0) { continue; } // The file should have already been checked out/be writable // If it is read only that means the checkout failed or we are not using source control and we can not write this file. if(bSCCEnabled) { FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(SourceControlHelpers::PackageFilename(Filename), EStateCacheUsage::ForceUpdate); if(SourceControlState.IsValid() && !SourceControlState->CanEdit()) { UE_LOG(LogFixupRedirectsCommandlet, Display, TEXT("Skipping file: source control says we cant edit the file %s..."), *Filename); continue; } } else if( IFileManager::Get().IsReadOnly( *Filename )) { UE_LOG(LogFixupRedirectsCommandlet, Display, TEXT("Skipping read-only file %s..."), *Filename); continue; } UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Wiping %s..."), *Filename); UPackage* Package = LoadPackage( NULL, *Filename, 0 ); // load all string asset reference targets, and add fake redirectors for them GRedirectCollector.ResolveStringAssetReference(); // if it failed to open, we have already dealt with quitting if we are going to, so just skip it if (!Package) { continue; } // assume that all redirs in this file are still-referenced bool bIsDirty = false; // see if this package is completely empty other than purged redirectors and metadata bool bIsEmpty = true; // delete all ObjectRedirects now TArray<UObjectRedirector*> Redirs; // find all redirectors, put into an array so delete doesn't mess up the iterator TArray<UObject *> ObjectsInOuter; GetObjectsWithOuter(Package, ObjectsInOuter); for( int32 Index = 0; Index < ObjectsInOuter.Num(); Index++ ) { UObject* Obj = ObjectsInOuter[Index]; UObjectRedirector *Redir = Cast<UObjectRedirector>(Obj); if (Redir) { int32 Dummy; // if the redirector was marked as uncleanable, skip it if (RedirectorsThatCantBeCleaned.Find(Redir->GetFullName(), Dummy)) { SET_WARN_COLOR(COLOR_DARK_RED); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT(" ... skipping still-referenced %s"), *Redir->GetFullName()); CLEAR_WARN_COLOR(); bIsEmpty = false; continue; } bIsDirty = true; SET_WARN_COLOR(COLOR_DARK_GREEN); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT(" ... deleting %s"), *Redir->GetFullName()); CLEAR_WARN_COLOR(); Redirs.Add(Redir); } else if ( (!Obj->IsA(UMetaData::StaticClass()) && !Obj->IsA(UField::StaticClass())) || Obj->IsA(UUserDefinedEnum::StaticClass())) // UserDefinedEnum should not be deleted { // This package has a real object bIsEmpty = false; } } if (bIsEmpty && !bDeleteOnlyReferencedRedirects) { EmptyPackagesToDelete[PackageIndex] = 1; } // mark them for deletion. for (int32 RedirIndex = 0; RedirIndex < Redirs.Num(); RedirIndex++) { UObjectRedirector* Redirector = Redirs[RedirIndex]; // Remove standalone flag and mark as pending kill. Redirector->ClearFlags( RF_Standalone | RF_Public ); // We don't need redirectors in the root set, the references should already be fixed up if ( Redirector->IsRooted() ) { Redirector->RemoveFromRoot(); } Redirector->MarkPendingKill(); } Redirs.Empty(); if (bIsDirty) { // Don't save packages in the engine directory if we did not opt to update engine packages if( bUpdateEnginePackages || !Filename.StartsWith( FPaths::EngineDir() ) ) { // save the package UWorld* World = UWorld::FindWorldInPackage(Package); GEditor->SavePackage( Package, World, World ? RF_NoFlags : RF_Standalone, *Filename, GWarn ); } } // collect garbage every N packages, or if there was any redirectors in the package if (((++GCIndex) % 50) == 0 || bIsDirty || Package->ContainsMap()) { // collect garbage to close the package CollectGarbage(RF_Native); UE_LOG(LogFixupRedirectsCommandlet, Display, TEXT("GC...")); // reset our counter GCIndex = 0; } } UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("")); } else { SET_WARN_COLOR(COLOR_WHITE); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("----------------------------")); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Not deleting any redirector objects:")); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("----------------------------")); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("")); CLEAR_WARN_COLOR(); } ///////////////////////////////////////////////////////////////////// // Clean up any unused trash ///////////////////////////////////////////////////////////////////// SET_WARN_COLOR(COLOR_WHITE); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Deleting empty and unused packages:")); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("---------------------------------------")); CLEAR_WARN_COLOR(); LogOutputFile->Logf(TEXT("")); LogOutputFile->Logf(TEXT("[Deleted]")); // Iterate over packages, attempting to delete unreferenced packages for( int32 PackageIndex = 0; PackageIndex < PackageList.Num(); PackageIndex++ ) { bool bDelete = false; const FString& Filename = PackageList[PackageIndex]; FString PackageName(FPackageName::FilenameToLongPackageName(Filename)); const bool bAllowDelete = bUpdateEnginePackages || !Filename.StartsWith( FPaths::EngineDir() ); if (bDeleteRedirects && !bDeleteOnlyReferencedRedirects && EmptyPackagesToDelete[PackageIndex] && bAllowDelete) { // this package is completely empty, delete it bDelete = true; } if (bDelete == true) { struct Local { static bool DeleteFromDisk(const FString& InFilename, const FString& InMessage) { SET_WARN_COLOR(COLOR_GREEN); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("%s"), *InMessage); if (!IFileManager::Get().Delete(*InFilename, false, true)) { SET_WARN_COLOR(COLOR_RED); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT(" ... failed to delete from disk."), *InFilename); CLEAR_WARN_COLOR(); return false; } CLEAR_WARN_COLOR(); return true; } }; if (!bIsSCCDisabled) { // get file SCC status FString FileName = SourceControlHelpers::PackageFilename(PackageName); FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(FileName, EStateCacheUsage::ForceUpdate); if(SourceControlState.IsValid() && (SourceControlState->IsCheckedOut() || SourceControlState->IsAdded()) ) { UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Revert '%s' from source control..."), *Filename); SourceControlProvider.Execute(ISourceControlOperation::Create<FRevert>(), FileName); SET_WARN_COLOR(COLOR_GREEN); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Deleting '%s' from source control..."), *Filename); CLEAR_WARN_COLOR(); SourceControlProvider.Execute(ISourceControlOperation::Create<FDelete>(), FileName); } else if(SourceControlState.IsValid() && SourceControlState->CanCheckout()) { SET_WARN_COLOR(COLOR_GREEN); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Deleting '%s' from source control..."), *Filename); CLEAR_WARN_COLOR(); SourceControlProvider.Execute(ISourceControlOperation::Create<FDelete>(), FileName); } else if(SourceControlState.IsValid() && SourceControlState->IsCheckedOutOther()) { SET_WARN_COLOR(COLOR_RED); UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Couldn't delete '%s' from source control, someone has it checked out, skipping..."), *Filename); CLEAR_WARN_COLOR(); } else if(SourceControlState.IsValid() && !SourceControlState->IsSourceControlled()) { if(Local::DeleteFromDisk(Filename, FString::Printf(TEXT("'%s' is not in source control, attempting to delete from disk..."), *Filename))) { LogOutputFile->Logf(*Filename); } } else { if(Local::DeleteFromDisk(Filename, FString::Printf(TEXT("'%s' is in an unknown source control state, attempting to delete from disk..."), *Filename))) { LogOutputFile->Logf(*Filename); } } } else { if(Local::DeleteFromDisk(Filename, FString::Printf(TEXT("source control disabled while deleting '%s', attempting to delete from disk..."), *Filename))) { LogOutputFile->Logf(*Filename); } } } } LogOutputFile->Close(); delete LogOutputFile; LogOutputFile = NULL; if (!bIsSCCDisabled && bAutoSubmit) { ///////////////////////////////////////////////////////////////////// // Submit the results to source control ///////////////////////////////////////////////////////////////////// UE_LOG(LogFixupRedirectsCommandlet, Display, TEXT("Submiting the results to source control")); // Work out the list of file to check in TArray <FString> FilesToSubmit; for( int32 PackageIndex = 0; PackageIndex < PackageList.Num(); PackageIndex++ ) { const FString& Filename = PackageList[PackageIndex]; FString PackageName(FPackageName::FilenameToLongPackageName(Filename)); FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(SourceControlHelpers::PackageFilename(Filename), EStateCacheUsage::ForceUpdate); if( SourceControlState.IsValid() && (SourceControlState->IsCheckedOut() || SourceControlState->IsAdded() || SourceControlState->IsDeleted()) ) { // Only submit engine packages if we're requested to if( bUpdateEnginePackages || !Filename.StartsWith( FPaths::EngineDir() ) ) { FilesToSubmit.Add(*PackageName); } } } // Check in all changed files const FText Description = NSLOCTEXT("FixupRedirectsCmdlet", "ChangelistDescription", "Fixed up Redirects"); TSharedRef<FCheckIn, ESPMode::ThreadSafe> CheckInOperation = ISourceControlOperation::Create<FCheckIn>(); CheckInOperation->SetDescription( Description ); SourceControlProvider.Execute(CheckInOperation, SourceControlHelpers::PackageFilenames(FilesToSubmit)); // toss the SCC manager ISourceControlModule::Get().GetProvider().Close(); } return 0; }
int32 Find(const void* itemPtr) const override { return Array->Find(*static_cast<const T*>(itemPtr)); }