FString FChunkManifestGenerator::CreateCookerFileOrderString(const TMap<FName, FAssetData*>& InAssetData, const TArray<FName>& InMaps) { FString FileOrderString; TArray<FAssetData*> TopLevelNodes; for (auto Asset : InAssetData) { auto PackageName = Asset.Value->PackageName; TArray<FName> Referencers; AssetRegistry.GetReferencers(PackageName, Referencers); bool bIsTopLevel = true; bool bIsMap = InMaps.Contains(PackageName); if (!bIsMap && Referencers.Num() > 0) { for (auto ReferencerName : Referencers) { if (InAssetData.Contains(ReferencerName)) { bIsTopLevel = false; break; } } } if (bIsTopLevel) { if (bIsMap) { TopLevelNodes.Insert(Asset.Value, 0); } else { TopLevelNodes.Insert(Asset.Value, TopLevelNodes.Num()); } } } TArray<FName> FileOrder; TArray<FName> EncounteredNames; for (auto Asset : TopLevelNodes) { AddAssetToFileOrderRecursive(Asset, FileOrder, EncounteredNames, InAssetData, InMaps); } int32 CurrentIndex = 0; for (auto PackageName : FileOrder) { auto Asset = InAssetData[PackageName]; bool bIsMap = InMaps.Contains(Asset->PackageName); auto Filename = FPackageName::LongPackageNameToFilename(Asset->PackageName.ToString(), bIsMap ? FPackageName::GetMapPackageExtension() : FPackageName::GetAssetPackageExtension()); ConvertFilenameToPakFormat(Filename); auto Line = FString::Printf(TEXT("\"%s\" %i\n"), *Filename, CurrentIndex++); FileOrderString.Append(Line); } return FileOrderString; }
/** * Returns true if the specified level is locked for edit, false otherwise. * * @param Level The level to query. * @return true if the level is locked, false otherwise. */ bool FLevelUtils::IsLevelLocked(ULevel* Level) { //We should not check file status on disk if we are not running the editor #if WITH_EDITOR // Don't permit spawning in read only levels if they are locked if ( GIsEditor && !GIsEditorLoadingPackage ) { if ( GEngine && GEngine->bLockReadOnlyLevels ) { if (!LevelReadOnlyCache.Contains(Level)) { LevelReadOnlyCache.Add(Level, FLevelReadOnlyData()); } check(LevelReadOnlyCache.Contains(Level)); FLevelReadOnlyData &LevelData = LevelReadOnlyCache[Level]; //Make sure we test if the level file on disk is readonly only once a frame, //when the frame time get updated. if (LevelData.LastUpdateTime < Level->OwningWorld->GetRealTimeSeconds()) { LevelData.LastUpdateTime = Level->OwningWorld->GetRealTimeSeconds(); //If we dont find package we dont consider it as readonly LevelData.IsReadOnly = false; const UPackage* pPackage = Cast<UPackage>(Level->GetOutermost()); if (pPackage) { FString PackageFileName; if (FPackageName::DoesPackageExist(pPackage->GetName(), NULL, &PackageFileName)) { LevelData.IsReadOnly = IFileManager::Get().IsReadOnly(*PackageFileName); } } } if (LevelData.IsReadOnly) { return true; } } } #endif //#if WITH_EDITOR // PIE levels, the persistent level, and transient move levels are usually never locked. if ( Level->RootPackageHasAnyFlags(PKG_PlayInEditor) || Level->IsPersistentLevel() || Level->GetName() == TEXT("TransLevelMoveBuffer") ) { return false; } ULevelStreaming* StreamingLevel = FindStreamingLevel( Level ); if ( StreamingLevel != NULL ) { return StreamingLevel->bLocked; } else { return Level->bLocked; } }
virtual bool Visit(const TCHAR* FilenameOrDirectory, bool bIsDirectory) override { auto Filename = FString(FilenameOrDirectory); if (!Filename.EndsWith(".cpp.includes")) { return true; } ++FileCount; TSet<FString> IncludePaths; FString FileContents; TArray<FString> OutStrings; FFileHelper::LoadANSITextFileToStrings(*Filename, &IFileManager::Get(), OutStrings); IncludePaths.Reserve(OutStrings.Num()); for (auto& IncludePath : OutStrings) { IncludePaths.Add(MoveTemp(IncludePath)); } for (const auto& IncludePath : IncludePaths) { if (!IncludeHeaderCount.Contains(IncludePath)) { IncludeHeaderCount.Add(IncludePath, 1); } else { ++IncludeHeaderCount[IncludePath]; } } return true; }
void UFaceFXMatineeControl::GetTrackKeyForTime(float InTime, TArray<TPair<int32, const FFaceFXTrackKey*>>& OutResult, TArray<FFaceFXSkelMeshComponentId>* OutNoTracks) const { //build a list of all keys for all skelmesh component ids TMap<int32, TArray<const FFaceFXTrackKey*>> SkelMeshTracks; TMap<int32, FFaceFXSkelMeshComponentId> SkelMeshIds; for(const FFaceFXTrackKey& Key : Keys) { SkelMeshTracks.FindOrAdd(Key.SkelMeshComponentId.Index).Add(&Key); if(OutNoTracks && !SkelMeshIds.Contains(Key.SkelMeshComponentId.Index)) { SkelMeshIds.Add(Key.SkelMeshComponentId.Index, Key.SkelMeshComponentId); } } //then generate the pair results for each skelmesh component for(auto It = SkelMeshTracks.CreateConstIterator(); It; ++It) { const TArray<const FFaceFXTrackKey*>& SkelMeshKeys = It.Value(); const int32 IndexMax = SkelMeshKeys.Num()-1; int32 Index = INDEX_NONE; for(; Index < IndexMax && SkelMeshKeys[Index+1]->Time <= InTime; ++Index); if(Index != INDEX_NONE) { OutResult.Add(TPairInitializer<int32, const FFaceFXTrackKey*>(Index, SkelMeshKeys[Index])); } else if(OutNoTracks) { OutNoTracks->Add(SkelMeshIds.FindChecked(It.Key())); } } }
void FSourceControlSettings::LoadSettings() { // make sure we load the global ini first const FString& GlobalIniFile = SourceControlHelpers::GetGlobalSettingsIni(); GConfig->GetBool(*SourceControlSettingsConstants::SettingsSection, TEXT("UseGlobalSettings"), bUseGlobalSettings, GlobalIniFile); TArray<FString> Tokens; TArray<FString> Switches; FCommandLine::Parse( FCommandLine::Get(), Tokens, Switches ); TMap<FString, FString> SwitchPairs; for (int32 SwitchIdx = Switches.Num() - 1; SwitchIdx >= 0; --SwitchIdx) { FString& Switch = Switches[SwitchIdx]; TArray<FString> SplitSwitch; if (2 == Switch.ParseIntoArray(SplitSwitch, TEXT("="), true)) { SwitchPairs.Add(SplitSwitch[0], SplitSwitch[1].TrimQuotes()); Switches.RemoveAt(SwitchIdx); } } if( SwitchPairs.Contains( TEXT("SCCProvider") ) ) { Provider = SwitchPairs[TEXT("SCCProvider")]; } else { const FString& IniFile = SourceControlHelpers::GetSettingsIni(); GConfig->GetString(*SourceControlSettingsConstants::SettingsSection, TEXT("Provider"), Provider, IniFile); } }
bool FDataScannerImpl::FindExistingChunk(const TMap<uint64, TSet<FGuid>>& ChunkLookup, TMap<FGuid, FSHAHash>& ChunkShaHashes, uint64 ChunkHash, const FRollingHash<WindowSize>& RollingHash, FGuid& OutMatchedChunk) { FStatsScopedTimer FindTimer(StatFindMatchTime); bool bFoundChunkMatch = false; if (ChunkLookup.Contains(ChunkHash)) { FSHAHash ChunkSha; RollingHash.GetWindowData().GetShaHash(ChunkSha); for (FGuid& PotentialMatch : ChunkLookup.FindRef(ChunkHash)) { // Use sha if we have it if (ChunkShaHashes.Contains(PotentialMatch)) { if(ChunkSha == ChunkShaHashes[PotentialMatch]) { bFoundChunkMatch = true; OutMatchedChunk = PotentialMatch; break; } } else { // Otherwise compare data TArray<uint8> SerialBuffer; FStatsScopedTimer DataMatchTimer(StatDataMatchTime); FStatsCollector::Accumulate(StatChunkDataChecks, 1); SerialBuffer.AddUninitialized(WindowSize); RollingHash.GetWindowData().Serialize(SerialBuffer.GetData()); bool ChunkFound = false; if (DataMatcher->CompareData(PotentialMatch, ChunkHash, SerialBuffer, ChunkFound)) { FStatsCollector::Accumulate(StatChunkDataMatches, 1); ChunkShaHashes.Add(PotentialMatch, ChunkSha); bFoundChunkMatch = true; OutMatchedChunk = PotentialMatch; break; } else if(!ChunkFound) { FStatsCollector::Accumulate(StatMissingChunks, 1); } } FStatsCollector::Accumulate(StatHashCollisions, 1); } } return bFoundChunkMatch; }
/******************** HasResourcesAvailable *************************/ bool APOTLStructure::HasResourcesAvailable(TMap<FString, int32>& Request, bool IncludeAllocations, int32 Sequence) { bool RequestMet = true; TMap<FString, int32> ResourceAvailable = FreeResources; //~~ Copy resources ~~// //~~ Append all allocated resources with lower sequence to available resources ~~// if (IncludeAllocations) { for (auto& AllocatedResource : AllocatedResources) { FST_ResourceAllocation& Allocation = AllocatedResource.Value; if (Allocation.Sequence < Sequence && Allocation.Type == EAllocationType::FactoryProduction && Allocation.To == this && Allocation.Quantity > 0) //~~ If allocation has a lower sequence than the check and is allocated to this structure ~~// { if (ResourceAvailable.Contains(Allocation.ResourceKey)) ResourceAvailable[Allocation.ResourceKey] = ResourceAvailable[Allocation.ResourceKey] + Allocation.Quantity; else ResourceAvailable.Add(Allocation.ResourceKey, Allocation.Quantity); } } } for (auto& ResourceRequest : Request) { if (ResourceAvailable.Contains(ResourceRequest.Key)) { int32 Remaining = ResourceRequest.Value; if (Remaining > ResourceAvailable[ResourceRequest.Key]) //~~ If request is larger than the resource pool ~~// { RequestMet = false; break; } } else { RequestMet = false; break; } } return RequestMet; }
// DEPRECATED void ADEPRECATED_VolumeAdaptiveBuilder::ExpandFrontierTowardsTarget(UDoNNavigationVolumeComponent* current, UDoNNavigationVolumeComponent* neighbor, DoNNavigation::PriorityQueue<UDoNNavigationVolumeComponent*> &frontier, TMap<UDoNNavigationVolumeComponent*, FVector> &entryPointMap, bool &goalFound, UDoNNavigationVolumeComponent* start, UDoNNavigationVolumeComponent* goal, FVector origin, FVector destination, TMap<UDoNNavigationVolumeComponent*, int>& VolumeVsCostMap, bool DrawDebug, TMap<UDoNNavigationVolumeComponent*, TArray<UDoNNavigationVolumeComponent*>> &PathVolumeSolutionMap) { if (DrawDebug) { DisplayDebugVolume(current, FColor::Red); DisplayDebugVolume(neighbor, FColor::Blue); } float SegmentDist = 0; FVector nextEntryPoint; TArray<UDoNNavigationVolumeComponent*> PathSolutionSoFar = PathVolumeSolutionMap.FindOrAdd(current); nextEntryPoint = NavEntryPointsForTraversal(*entryPointMap.Find(current), current, neighbor, SegmentDist, DrawDebug); entryPointMap.Add(neighbor, nextEntryPoint); if (nextEntryPoint == *entryPointMap.Find(current)) // i.e. no traversal solution exists { if (DrawDebug) { DisplayDebugVolume(current, FColor::Red); DisplayDebugVolume(neighbor, FColor::Blue); } UE_LOG(LogTemp, Log, TEXT("Skipping neighbor due to lack of traversal solution")); return; } //int new_cost = *VolumeVsCostMap.Find(current) + graph.cost(current, next); int new_cost = *VolumeVsCostMap.Find(current) + SegmentDist; if (!VolumeVsCostMap.Contains(neighbor) || new_cost < *VolumeVsCostMap.Find(neighbor)) { PathSolutionSoFar.Add(neighbor); PathVolumeSolutionMap.Add(neighbor, PathSolutionSoFar); VolumeVsCostMap.Add(neighbor, new_cost); float heuristic = FVector::Dist(nextEntryPoint, destination); int priority = new_cost + heuristic; if (DrawDebug) { DrawDebugLine(GetWorld(), nextEntryPoint, destination, FColor::Red, true, -1.f, 0, 10.f); FString priorityText = FString::Printf(TEXT("Priority: %d"), priority); UE_LOG(LogTemp, Log, TEXT("%s"), *priorityText); } frontier.put(neighbor, priority); } }
FName FNativeClassHierarchy::GetClassPathRootForModule(const FName& InModuleName, const TSet<FName>& InGameModules, const TMap<FName, FName>& InPluginModules) { static const FName EngineRootNodeName = "Classes_Engine"; static const FName GameRootNodeName = "Classes_Game"; // Work out which root this class should go under (anything that isn't a game or plugin module goes under engine) FName RootNodeName = EngineRootNodeName; if(InGameModules.Contains(InModuleName)) { RootNodeName = GameRootNodeName; } else if(InPluginModules.Contains(InModuleName)) { const FName PluginName = InPluginModules.FindRef(InModuleName); RootNodeName = FName(*(FString(TEXT("Classes_")) + PluginName.ToString())); } return RootNodeName; }
// Determine whether or not scene components in the new object set can be attached to the given scene root component bool CanAttachComponentsTo(USceneComponent* InRootComponent) { check(InRootComponent); // For each component in the set, check against the given root component and break if we fail to validate bool bCanAttachToRoot = true; for (auto NewComponentIt = NewObjectMap.CreateConstIterator(); NewComponentIt && bCanAttachToRoot; ++NewComponentIt) { // If this is a scene component, and it does not already have a parent within the set USceneComponent* SceneComponent = Cast<USceneComponent>(NewComponentIt->Value); if (SceneComponent != NULL && !ParentMap.Contains(SceneComponent->GetFName())) { // Determine if we are allowed to attach the scene component to the given root component bCanAttachToRoot = InRootComponent->CanAttachAsChild(SceneComponent, NAME_None) && SceneComponent->Mobility >= InRootComponent->Mobility && ( !InRootComponent->IsEditorOnly() || SceneComponent->IsEditorOnly() ); } } return bCanAttachToRoot; }
void FChunkManifestGenerator::AddAssetToFileOrderRecursive(FAssetData* InAsset, TArray<FName>& OutFileOrder, TArray<FName>& OutEncounteredNames, const TMap<FName, FAssetData*>& InAssets, const TArray<FName>& InMapList) { if (!OutEncounteredNames.Contains(InAsset->PackageName)) { OutEncounteredNames.Add(InAsset->PackageName); TArray<FName> Dependencies; AssetRegistry.GetDependencies(InAsset->PackageName, Dependencies); for (auto DependencyName : Dependencies) { if (InAssets.Contains(DependencyName) && !OutFileOrder.Contains(DependencyName)) { if (!InMapList.Contains(DependencyName)) { auto Dependency = InAssets[DependencyName]; AddAssetToFileOrderRecursive(Dependency, OutFileOrder, OutEncounteredNames, InAssets, InMapList); } } } OutFileOrder.Add(InAsset->PackageName); } }
/******************** GetResourceAlteration *************************/ TArray<FST_ResourceAlteration> APOTLStructure::GetResourceAlteration() { TArray<FST_ResourceAlteration> List; TMap<FString, FST_ResourceAlteration> TMapList; //~~ Make complete list of resource from FreeResources and allocations ~~// for (auto& FreeResource : FreeResources) { FST_ResourceAlteration ResourceAlteration; ResourceAlteration.Id = FreeResource.Key; ResourceAlteration.Storage = FreeResource.Value; //ResourceAlteration.Alteration = GetAllocationTotal(FreeResource.Key); TMapList.Add(FreeResource.Key, ResourceAlteration); } for (auto& AllocatedResource : AllocatedResources) { //~~ Add alteration if allocation key isn't in free resources ~~// if (AllocatedResource.Value.From == this || AllocatedResource.Value.To == this) //~~~ If either outgoing or incomming, then create an alteration struct ~~// { if (!TMapList.Contains(AllocatedResource.Value.ResourceKey)) { FST_ResourceAlteration ResourceAlteration; ResourceAlteration.Id = AllocatedResource.Value.ResourceKey; TMapList.Add(AllocatedResource.Value.ResourceKey, ResourceAlteration); } } //~~ Outgoing resources from root ~~// if (AllocatedResource.Value.From == this) { if (AllocatedResource.Value.Type == EAllocationType::Decay) { TMapList[AllocatedResource.Value.ResourceKey].Decay -= AllocatedResource.Value.Quantity; TMapList[AllocatedResource.Value.ResourceKey].Storage += AllocatedResource.Value.Quantity; } else if (AllocatedResource.Value.Type == EAllocationType::FactoryBilling) { TMapList[AllocatedResource.Value.ResourceKey].Alteration -= AllocatedResource.Value.Quantity; TMapList[AllocatedResource.Value.ResourceKey].Storage += AllocatedResource.Value.Quantity; } } //~~ Incomming resources to root ~~// if (AllocatedResource.Value.To == this) { if (AllocatedResource.Value.Type == EAllocationType::ProductionDecay) { TMapList[AllocatedResource.Value.ResourceKey].Alteration += AllocatedResource.Value.Quantity; TMapList[AllocatedResource.Value.ResourceKey].Decay -= AllocatedResource.Value.Quantity; } else { TMapList[AllocatedResource.Value.ResourceKey].Alteration += AllocatedResource.Value.Quantity; } } } /* if (TMapList.Contains(AllocatedResource.Value.ResourceKey)) { if (AllocatedResource.Value.Type == EAllocationType::FactoryBilling) { TMapList[AllocatedResource.Value.ResourceKey].Storage = TMapList[AllocatedResource.Value.ResourceKey].Storage + TMapList[AllocatedResource.Value.ResourceKey].Alteration; } } else { FST_ResourceAlteration ResourceAlteration; ResourceAlteration.Id = AllocatedResource.Value.ResourceKey; ResourceAlteration.Alteration = GetAllocationTotal(AllocatedResource.Value.ResourceKey); TMapList.Add(AllocatedResource.Value.ResourceKey, ResourceAlteration); } */ for (auto& TMapItem : TMapList) { List.Add(TMapItem.Value); } //~~ Sort the list by sort sequence ~~// /* List.Sort([](const FString& One, const FString& Two) { return One > Two; }); List.Sort([](const FString& A, const FString& B) { return A.Len() < B.Len(); }); */ //GameInstance->DATA_Recipes List.Sort([](const FST_ResourceAlteration& A, const FST_ResourceAlteration& B) { return A.Id.Len() < B.Id.Len(); //return A.Id.Len() < B.Id.Len(); }); //List.Sort(); return List; }
void FComponentEditorUtils::CopyComponents(const TArray<UActorComponent*>& ComponentsToCopy) { FStringOutputDevice Archive; const FExportObjectInnerContext Context; // Clear the mark state for saving. UnMarkAllObjects(EObjectMark(OBJECTMARK_TagExp | OBJECTMARK_TagImp)); // Duplicate the selected component templates into temporary objects that we can modify TMap<FName, FName> ParentMap; TMap<FName, UActorComponent*> ObjectMap; for (UActorComponent* Component : ComponentsToCopy) { // Duplicate the component into a temporary object UObject* DuplicatedComponent = StaticDuplicateObject(Component, GetTransientPackage(), Component->GetFName(), RF_AllFlags & ~RF_ArchetypeObject); if (DuplicatedComponent) { // If the duplicated component is a scene component, wipe its attach parent (to prevent log warnings for referencing a private object in an external package) if (auto DuplicatedCompAsSceneComp = Cast<USceneComponent>(DuplicatedComponent)) { DuplicatedCompAsSceneComp->AttachParent = nullptr; } // Find the closest parent component of the current component within the list of components to copy USceneComponent* ClosestSelectedParent = FindClosestParentInList(Component, ComponentsToCopy); if (ClosestSelectedParent) { // If the parent is included in the list, record it into the node->parent map ParentMap.Add(Component->GetFName(), ClosestSelectedParent->GetFName()); } // Record the temporary object into the name->object map ObjectMap.Add(Component->GetFName(), CastChecked<UActorComponent>(DuplicatedComponent)); } } // Export the component object(s) to text for copying for (auto ObjectIt = ObjectMap.CreateIterator(); ObjectIt; ++ObjectIt) { // Get the component object to be copied UActorComponent* ComponentToCopy = ObjectIt->Value; check(ComponentToCopy); // If this component object had a parent within the selected set if (ParentMap.Contains(ComponentToCopy->GetFName())) { // Get the name of the parent component FName ParentName = ParentMap[ComponentToCopy->GetFName()]; if (ObjectMap.Contains(ParentName)) { // Ensure that this component is a scene component USceneComponent* SceneComponent = Cast<USceneComponent>(ComponentToCopy); if (SceneComponent) { // Set the attach parent to the matching parent object in the temporary set. This allows us to preserve hierarchy in the copied set. SceneComponent->AttachParent = Cast<USceneComponent>(ObjectMap[ParentName]); } } } // Export the component object to the given string UExporter::ExportToOutputDevice(&Context, ComponentToCopy, NULL, Archive, TEXT("copy"), 0, PPF_ExportsNotFullyQualified | PPF_Copy | PPF_Delimited, false, ComponentToCopy->GetOuter()); } // Copy text to clipboard FString ExportedText = Archive; FPlatformMisc::ClipboardCopy(*ExportedText); }
bool FFileAttributesParserImpl::FileAttributesMetaToMap(const FString& AttributesList, TMap<FString, FFileAttributes>& FileAttributesMap) { const TCHAR Quote = TEXT('\"'); const TCHAR EOFile = TEXT('\0'); const TCHAR EOLine = TEXT('\n'); bool Successful = true; bool FoundFilename = false; const TCHAR* CharPtr = *AttributesList; while (*CharPtr != EOFile) { // Parse filename while (*CharPtr != Quote && *CharPtr != EOFile){ ++CharPtr; } if (*CharPtr == EOFile) { if (!FoundFilename) { UE_LOG(LogFileAttributesParser, Error, TEXT("Did not find opening quote for filename!")); return false; } break; } const TCHAR* FilenameStart = ++CharPtr; while (*CharPtr != Quote && *CharPtr != EOFile && *CharPtr != EOLine){ ++CharPtr; } // Check we didn't run out of file if (*CharPtr == EOFile) { UE_LOG(LogFileAttributesParser, Error, TEXT("Unexpected end of file before next quote! Pos:%d"), CharPtr - *AttributesList); return false; } // Check we didn't run out of line if(*CharPtr == EOLine) { UE_LOG(LogFileAttributesParser, Error, TEXT("Unexpected end of line before next quote! Pos:%d"), CharPtr - *AttributesList); return false; } // Save positions const TCHAR* FilenameEnd = CharPtr++; const TCHAR* AttributesStart = CharPtr; // Parse keywords while (*CharPtr != Quote && *CharPtr != EOFile && *CharPtr != EOLine){ ++CharPtr; } // Check we hit the end of the line or file, another quote it wrong if (*CharPtr == Quote) { UE_LOG(LogFileAttributesParser, Error, TEXT("Unexpected Quote before end of keywords! Pos:%d"), CharPtr - *AttributesList); return false; } FoundFilename = true; // Save position const TCHAR* EndOfLine = CharPtr; // Grab info FString Filename = FString(FilenameEnd - FilenameStart, FilenameStart).Replace(TEXT("\\"), TEXT("/")); FFileAttributes& FileAttributes = FileAttributesMap.FindOrAdd(Filename); TArray<FString> AttributeParamsArray; FString AttributeParams(EndOfLine - AttributesStart, AttributesStart); AttributeParams.ParseIntoArrayWS(AttributeParamsArray); for (const FString& AttributeParam : AttributeParamsArray) { FString Key, Value; if(!AttributeParam.Split(TEXT(":"), &Key, &Value)) { Key = AttributeParam; } if (AttributeSetters.Contains(Key)) { AttributeSetters[Key](FileAttributes, MoveTemp(Value)); } else { UE_LOG(LogFileAttributesParser, Error, TEXT("Unrecognised attribute %s for %s"), *AttributeParam, *Filename); Successful = false; } } } return Successful; }
void FixUpChunkBoneMaps( FSkelMeshChunk & Chunk, const TMap<FBoneIndexType, FBoneIndexType> &BonesToRepair ) override { // now you have list of bones, remove them from vertex influences { TMap<uint8, uint8> BoneMapRemapTable; // first go through bone map and see if this contains BonesToRemove int32 BoneMapSize = Chunk.BoneMap.Num(); int32 AdjustIndex=0; for (int32 BoneMapIndex=0; BoneMapIndex < BoneMapSize; ++BoneMapIndex ) { // look for this bone to be removed or not? const FBoneIndexType* ParentBoneIndex = BonesToRepair.Find(Chunk.BoneMap[BoneMapIndex]); if ( ParentBoneIndex ) { // this should not happen, I don't ever remove root check (*ParentBoneIndex!=INDEX_NONE); // if Parent already exists in the current BoneMap, we just have to fix up the mapping int32 ParentBoneMapIndex = Chunk.BoneMap.Find(*ParentBoneIndex); // if it exists if (ParentBoneMapIndex != INDEX_NONE) { // if parent index is higher, we have to decrease it to match to new index if (ParentBoneMapIndex > BoneMapIndex) { --ParentBoneMapIndex; } // remove current chunk count, will replace with parent Chunk.BoneMap.RemoveAt(BoneMapIndex); } else { // if parent doens't exists, we have to add one // this doesn't change bone map size Chunk.BoneMap.RemoveAt(BoneMapIndex); ParentBoneMapIndex = Chunk.BoneMap.Add(*ParentBoneIndex); } // first fix up all indices of BoneMapRemapTable for the indices higher than BoneMapIndex, since BoneMapIndex is being removed for (auto Iter = BoneMapRemapTable.CreateIterator(); Iter; ++Iter) { uint8& Value = Iter.Value(); check (Value != BoneMapIndex); if (Value > BoneMapIndex) { --Value; } } int32 OldIndex = BoneMapIndex+AdjustIndex; int32 NewIndex = ParentBoneMapIndex; // you still have to add no matter what even if same since indices might change after added { // add to remap table check (OldIndex < 256 && OldIndex >= 0); check (NewIndex < 256 && NewIndex >= 0); check (BoneMapRemapTable.Contains((uint8)OldIndex) == false); BoneMapRemapTable.Add((uint8)OldIndex, (uint8)NewIndex); } // reduce index since the item is removed --BoneMapIndex; --BoneMapSize; // this is to adjust the later indices. We need to refix their indices ++AdjustIndex; } else if (AdjustIndex > 0) { int32 OldIndex = BoneMapIndex+AdjustIndex; int32 NewIndex = BoneMapIndex; check (OldIndex < 256 && OldIndex >= 0); check (NewIndex < 256 && NewIndex >= 0); check (BoneMapRemapTable.Contains((uint8)OldIndex) == false); BoneMapRemapTable.Add((uint8)OldIndex, (uint8)NewIndex); } } if ( BoneMapRemapTable.Num() > 0 ) { // fix up rigid verts for (int32 VertIndex=0; VertIndex < Chunk.RigidVertices.Num(); ++VertIndex) { FRigidSkinVertex & Vert = Chunk.RigidVertices[VertIndex]; uint8 *RemappedBone = BoneMapRemapTable.Find(Vert.Bone); if (RemappedBone) { Vert.Bone = *RemappedBone; } } // fix up soft verts for (int32 VertIndex=0; VertIndex < Chunk.SoftVertices.Num(); ++VertIndex) { FSoftSkinVertex & Vert = Chunk.SoftVertices[VertIndex]; bool ShouldRenormalize = false; for(int32 InfluenceIndex = 0;InfluenceIndex < MAX_TOTAL_INFLUENCES;InfluenceIndex++) { uint8 *RemappedBone = BoneMapRemapTable.Find(Vert.InfluenceBones[InfluenceIndex]); if (RemappedBone) { Vert.InfluenceBones[InfluenceIndex] = *RemappedBone; ShouldRenormalize = true; } } if (ShouldRenormalize) { // should see if same bone exists for(int32 InfluenceIndex = 0;InfluenceIndex < MAX_TOTAL_INFLUENCES;InfluenceIndex++) { for(int32 InfluenceIndex2 = InfluenceIndex+1;InfluenceIndex2 < MAX_TOTAL_INFLUENCES;InfluenceIndex2++) { // cannot be 0 because we don't allow removing root if (Vert.InfluenceBones[InfluenceIndex] != 0 && Vert.InfluenceBones[InfluenceIndex] == Vert.InfluenceBones[InfluenceIndex2]) { Vert.InfluenceWeights[InfluenceIndex] += Vert.InfluenceWeights[InfluenceIndex2]; // reset Vert.InfluenceBones[InfluenceIndex2] = 0; Vert.InfluenceWeights[InfluenceIndex2] = 0; } } } } } } // @todo fix up RequiredBones/ActiveBoneIndices? } }
void SSizeMap::GatherDependenciesRecursively( FAssetRegistryModule& AssetRegistryModule, TSharedPtr<FAssetThumbnailPool>& InAssetThumbnailPool, TMap<FName, TSharedPtr<FTreeMapNodeData>>& VisitedAssetPackageNames, const TArray<FName>& AssetPackageNames, const TSharedPtr<FTreeMapNodeData>& Node, TSharedPtr<FTreeMapNodeData>& SharedRootNode, int32& NumAssetsWhichFailedToLoad ) { for( const FName AssetPackageName : AssetPackageNames ) { // Have we already added this asset to the tree? If so, we'll either move it to a "shared" group or (if it's referenced again by the same // root-level asset) ignore it if( VisitedAssetPackageNames.Contains( AssetPackageName ) ) { // OK, we've determined that this asset has already been referenced by something else in our tree. We'll move it to a "shared" group // so all of the assets that are referenced in multiple places can be seen together. TSharedPtr<FTreeMapNodeData> ExistingNode = VisitedAssetPackageNames[ AssetPackageName ]; // Is the existing node not already under the "shared" group? Note that it might still be (indirectly) under // the "shared" group, in which case we'll still want to move it up to the root since we've figured out that it is // actually shared between multiple assets which themselves may be shared if( ExistingNode->Parent != SharedRootNode.Get() ) { // Don't bother moving any of the assets at the root level into a "shared" bucket. We're only trying to best // represent the memory used when all of the root-level assets have become loaded. It's OK if root-level assets // are referenced by other assets in the set -- we don't need to indicate they are shared explicitly FTreeMapNodeData* ExistingNodeParent = ExistingNode->Parent; check( ExistingNodeParent != nullptr ); const bool bExistingNodeIsAtRootLevel = ExistingNodeParent->Parent == nullptr || RootAssetPackageNames.Contains( AssetPackageName ); if( !bExistingNodeIsAtRootLevel ) { // OK, the current asset (AssetPackageName) is definitely not a root level asset, but its already in the tree // somewhere as a non-shared, non-root level asset. We need to make sure that this Node's reference is not from the // same root-level asset as the ExistingNodeInTree. Otherwise, there's no need to move it to a 'shared' group. FTreeMapNodeData* MyParentNode = Node.Get(); check( MyParentNode != nullptr ); FTreeMapNodeData* MyRootLevelAssetNode = MyParentNode; while( MyRootLevelAssetNode->Parent != nullptr && MyRootLevelAssetNode->Parent->Parent != nullptr ) { MyRootLevelAssetNode = MyRootLevelAssetNode->Parent; } if( MyRootLevelAssetNode->Parent == nullptr ) { // No root asset (Node must be a root level asset itself!) MyRootLevelAssetNode = nullptr; } // Find the existing node's root level asset node FTreeMapNodeData* ExistingNodeRootLevelAssetNode = ExistingNodeParent; while( ExistingNodeRootLevelAssetNode->Parent->Parent != nullptr ) { ExistingNodeRootLevelAssetNode = ExistingNodeRootLevelAssetNode->Parent; } // If we're being referenced by another node within the same asset, no need to move it to a 'shared' group. if( MyRootLevelAssetNode != ExistingNodeRootLevelAssetNode ) { // This asset was already referenced by something else (or was in our top level list of assets to display sizes for) if( !SharedRootNode.IsValid() ) { // Find the root-most tree node FTreeMapNodeData* RootNode = MyParentNode; while( RootNode->Parent != nullptr ) { RootNode = RootNode->Parent; } SharedRootNode = MakeShareable( new FTreeMapNodeData() ); RootNode->Children.Add( SharedRootNode ); SharedRootNode->Parent = RootNode; // Keep back-pointer to parent node } // Reparent the node that we've now determined to be shared ExistingNode->Parent->Children.Remove( ExistingNode ); SharedRootNode->Children.Add( ExistingNode ); ExistingNode->Parent = SharedRootNode.Get(); } } } } else { // This asset is new to us so far! Let's add it to the tree. Later as we descend through references, we might find that the // asset is referenced by something else as well, in which case we'll pull it out and move it to a "shared" top-level box // Don't bother showing code references const FString AssetPackageNameString = AssetPackageName.ToString(); if( !AssetPackageNameString.StartsWith( TEXT( "/Script/" ) ) ) { FTreeMapNodeDataRef ChildTreeMapNode = MakeShareable( new FTreeMapNodeData() ); Node->Children.Add( ChildTreeMapNode ); ChildTreeMapNode->Parent = Node.Get(); // Keep back-pointer to parent node VisitedAssetPackageNames.Add( AssetPackageName, ChildTreeMapNode ); FNodeSizeMapData& NodeSizeMapData = NodeSizeMapDataMap.Add( ChildTreeMapNode ); // Set some defaults for this node. These will be used if we can't actually locate the asset. // @todo sizemap urgent: We need a better indication in the UI when there are one or more missing assets. Because missing assets have a size // of zero, they are nearly impossible to zoom into. At the least, we should have some Output Log spew when assets cannot be loaded NodeSizeMapData.AssetData.AssetName = AssetPackageName; NodeSizeMapData.AssetData.AssetClass = FName( *LOCTEXT( "MissingAsset", "MISSING!" ).ToString() ); NodeSizeMapData.AssetSize = 0; NodeSizeMapData.bHasKnownSize = false; // Find the asset using the asset registry // @todo sizemap: Asset registry-based reference gathering is faster but possibly not as exhaustive (no PostLoad created references, etc.) Maybe should be optional? // @todo sizemap: With AR-based reference gathering, sometimes the size map is missing root level dependencies until you reopen it a few times (Buggy BP) // @todo sizemap: With AR-based reference gathering, reference changes at editor-time do not appear in the Size Map until you restart // @todo sizemap: With AR-based reference gathering, opening the size map for all engine content caused the window to not respond until a restart // @todo sizemap: We don't really need the asset registry given we need to load the objects to figure out their size, unless we make that AR-searchable. // ---> This would allow us to not have to wait for AR initialization. But if we made size AR-searchable, we could run very quickly for large data sets! const bool bUseAssetRegistryForDependencies = false; const FString AssetPathString = AssetPackageNameString + TEXT(".") + FPackageName::GetLongPackageAssetName( AssetPackageNameString ); const FAssetData FoundAssetData = AssetRegistryModule.Get().GetAssetByObjectPath( FName( *AssetPathString ) ); if( FoundAssetData.IsValid() ) { NodeSizeMapData.AssetData = FoundAssetData; // Now actually load up the asset. We need it in memory in order to accurately determine its size. // @todo sizemap: We could async load these packages to make the editor experience a bit nicer (smoother progress) UObject* Asset = StaticLoadObject( UObject::StaticClass(), nullptr, *AssetPathString ); if( Asset != nullptr ) { TArray<FName> ReferencedAssetPackageNames; if( bUseAssetRegistryForDependencies ) { AssetRegistryModule.Get().GetDependencies( AssetPackageName, ReferencedAssetPackageNames ); } else { SizeMapInternals::FAssetReferenceFinder References( Asset ); for( UObject* Object : References.GetReferencedAssets() ) { ReferencedAssetPackageNames.Add( FName( *Object->GetOutermost()->GetPathName() ) ); } } // For textures, make sure we're getting the worst case size, not the size of the currently loaded set of mips // @todo sizemap: We should instead have a special EResourceSizeMode that asks for the worst case size. Some assets (like UTextureCube) currently always report resident mip size, even when asked for inclusive size if( Asset->IsA( UTexture2D::StaticClass() ) ) { NodeSizeMapData.AssetSize = Asset->GetResourceSize( EResourceSizeMode::Inclusive ); } else { NodeSizeMapData.AssetSize = Asset->GetResourceSize( EResourceSizeMode::Exclusive ); } NodeSizeMapData.bHasKnownSize = NodeSizeMapData.AssetSize != UObject::RESOURCE_SIZE_NONE && NodeSizeMapData.AssetSize != 0; if( !NodeSizeMapData.bHasKnownSize ) { // Asset has no meaningful size NodeSizeMapData.AssetSize = 0; // @todo sizemap urgent: Try to serialize to figure out how big it is (not into sub-assets though!) // FObjectMemoryAnalyzer ObjectMemoryAnalyzer( Asset ); } // Now visit all of the assets that we are referencing GatherDependenciesRecursively( AssetRegistryModule, InAssetThumbnailPool, VisitedAssetPackageNames, ReferencedAssetPackageNames, ChildTreeMapNode, SharedRootNode, NumAssetsWhichFailedToLoad ); } else { ++NumAssetsWhichFailedToLoad; } } else { ++NumAssetsWhichFailedToLoad; } } } } }
void SVisualLoggerReport::GenerateReportText() { FString OutString; TArray<FVisualLogEvent> GlobalEventsStats; TMap<FString, TArray<FString> > EventToObjectsMap; OutString.Append(TEXT("<RichText.HeaderText1>Report Details</>\n")); for (TSharedPtr<class SLogVisualizerTimeline> LogItem : SelectedItems) { TArray<FVisualLogEvent> AllEvents; for (const FVisualLogDevice::FVisualLogEntryItem& CurrentEntry : LogItem->GetEntries()) { for (const FVisualLogEvent& Event : CurrentEntry.Entry.Events) { int32 Index = AllEvents.Find(FVisualLogEvent(Event)); if (Index != INDEX_NONE) { for (auto& CurrentEventTag : Event.EventTags) { if (AllEvents[Index].EventTags.Contains(CurrentEventTag.Key)) { AllEvents[Index].EventTags[CurrentEventTag.Key] += CurrentEventTag.Value; } else { AllEvents[Index].EventTags.Add(CurrentEventTag.Key, CurrentEventTag.Value); } } AllEvents[Index].Counter++; } else { AllEvents.Add(Event); } } } bool bPrintNextLine = false; if (AllEvents.Num() > 0) { OutString.Append(FString::Printf(TEXT(" <RichText.HeaderText2>%s</>"), *LogItem->GetName().ToString())); } for (auto& CurrentEvent : AllEvents) { for (auto& CurrentEventTag : CurrentEvent.EventTags) { OutString.Append(FString::Printf(TEXT(" \n \u2022 <a id=\"%s\" style=\"RichText.Hyperlink\">%s</> with <RichText.TextBold>%s</> tag occurred <RichText.TextBold>%d times</>"), *CurrentEvent.Name, *CurrentEvent.Name, *CurrentEventTag.Key.ToString(), CurrentEventTag.Value)); } OutString.Append(FString::Printf(TEXT("\n \u2022 <a id=\"%s\" style=\"RichText.Hyperlink\">%s</> occurred <RichText.TextBold>%d times</>"), *CurrentEvent.Name, *CurrentEvent.Name, CurrentEvent.Counter)); bool bJustAdded = false; int32 Index = GlobalEventsStats.Find(FVisualLogEvent(CurrentEvent)); if (Index != INDEX_NONE) { GlobalEventsStats[Index].Counter += CurrentEvent.Counter; EventToObjectsMap[CurrentEvent.Name].AddUnique(LogItem->GetName().ToString()); } else { bJustAdded = true; GlobalEventsStats.Add(CurrentEvent); EventToObjectsMap.FindOrAdd(CurrentEvent.Name).Add(LogItem->GetName().ToString()); } Index = GlobalEventsStats.Find(FVisualLogEvent(CurrentEvent)); for (auto& CurrentEventTag : CurrentEvent.EventTags) { if (!bJustAdded) { GlobalEventsStats[Index].EventTags.FindOrAdd(CurrentEventTag.Key) += CurrentEventTag.Value; } if (EventToObjectsMap.Contains(CurrentEvent.Name + CurrentEventTag.Key.ToString())) { EventToObjectsMap[CurrentEvent.Name + CurrentEventTag.Key.ToString()].AddUnique(LogItem->GetName().ToString()); } else { EventToObjectsMap.FindOrAdd(CurrentEvent.Name + CurrentEventTag.Key.ToString()).AddUnique(LogItem->GetName().ToString()); } } OutString.Append(TEXT("\n")); } OutString.Append(TEXT("\n")); } OutString.Append(TEXT("\n\n<RichText.HeaderText1>Report Summary</>\n")); CollectedEvents.Reset(); for (auto& CurrentEvent : GlobalEventsStats) { CollectedEvents.Add(*CurrentEvent.Name); OutString.Append(FString::Printf(TEXT(" <a id=\"%s\" style=\"RichText.Hyperlink\">%s</> occurred <RichText.TextBold>%d times</> by %d owners (%s)\n"), *CurrentEvent.Name, *CurrentEvent.Name, CurrentEvent.Counter, EventToObjectsMap.Contains(CurrentEvent.Name) ? EventToObjectsMap[CurrentEvent.Name].Num() : 0, *CurrentEvent.UserFriendlyDesc)); for (auto& CurrentEventTag : CurrentEvent.EventTags) { const int32 ObjectsNumber = EventToObjectsMap.Contains(CurrentEvent.Name + CurrentEventTag.Key.ToString()) ? EventToObjectsMap[CurrentEvent.Name + CurrentEventTag.Key.ToString()].Num() : 0; OutString.Append(FString::Printf(TEXT(" \u2022 %s to <RichText.TextBold>%s</> tag occurred <RichText.TextBold>%d times</> by %d owners (average %.2f times each)\n"), *CurrentEvent.Name, *CurrentEventTag.Key.ToString(), CurrentEventTag.Value, ObjectsNumber, ObjectsNumber > 0 ? float(CurrentEventTag.Value) / ObjectsNumber : -1)); } OutString.Append(TEXT("\n")); } ReportText = FText::FromString(OutString); }
UObject* USspjFactory::FactoryCreateBinary(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, const TCHAR* Type, const uint8*& Buffer, const uint8* InBufferEnd, FFeedbackContext* Warn) { bool bReimport = this->IsA(UReimportSspjFactory::StaticClass()); TMap<FString, UTexture*>* ExistImages = NULL; if(bReimport) { ExistImages = &(Cast<UReimportSspjFactory>(this)->ExistImages); } FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools"); FString ProjectNameStr = InName.ToString(); FName ProjectName = InName; UPackage* InParentPackage = Cast<UPackage>(InParent); if(InParentPackage && !bReimport) { FString ProjectPackageName; FString BasePackageName = FPackageName::GetLongPackagePath(InParent->GetOutermost()->GetName()) / ProjectNameStr; AssetToolsModule.Get().CreateUniqueAssetName(BasePackageName, TEXT(""), ProjectPackageName, ProjectNameStr); InParentPackage->Rename(*ProjectPackageName); } // インポート設定の取得 const USsImportSettings* ImportSettings = GetDefault<USsImportSettings>(); // インポート開始 FEditorDelegates::OnAssetPreImport.Broadcast(this, InClass, InParent, ProjectName, Type); // sspj USsProject* NewProject = FSsLoader::LoadSsProject(InParent, ProjectName, Flags, Buffer, (InBufferEnd - Buffer) + 1); NewProject->SetFilepath( GetCurrentFilename() ); if(NewProject) { if(NewProject->AssetImportData == nullptr) { NewProject->AssetImportData = NewObject<UAssetImportData>(NewProject); } NewProject->AssetImportData->Update(CurrentFilename); FString CurPath = FPaths::GetPath(GetCurrentFilename()); TArray<FString> ImagePaths; TArray<SsTexWrapMode::Type> ImageWrapModes; TArray<SsTexFilterMode::Type> ImageFilterModes; // ssce NewProject->CellmapList.Empty(); NewProject->CellmapList.AddZeroed(NewProject->CellmapNames.Num()); for(int i = 0; i < NewProject->CellmapNames.Num(); ++i) { FString FileName = GetFilePath(CurPath, NewProject->Settings.CellMapBaseDirectory, NewProject->CellmapNames[i].ToString()); TArray<uint8> Data; if(FFileHelper::LoadFileToArray(Data, *FileName)) { const uint8* BufferBegin = Data.GetData(); const uint8* BufferEnd = BufferBegin + Data.Num() - 1; if(FSsLoader::LoadSsCellMap(&(NewProject->CellmapList[i]), BufferBegin, (BufferEnd - BufferBegin) + 1)) { NewProject->CellmapList[i].FileName = NewProject->CellmapNames[i]; if(0 < NewProject->CellmapList[i].ImagePath.Len()) { if(INDEX_NONE == ImagePaths.Find(NewProject->CellmapList[i].ImagePath)) { ImagePaths.Add(NewProject->CellmapList[i].ImagePath); if(NewProject->CellmapList[i].OverrideTexSettings) { ImageWrapModes.Add(NewProject->CellmapList[i].WrapMode); ImageFilterModes.Add(NewProject->CellmapList[i].FilterMode); } else { ImageWrapModes.Add(NewProject->Settings.WrapMode); ImageFilterModes.Add(NewProject->Settings.FilterMode); } } } } } } // ssae NewProject->AnimeList.Empty(); NewProject->AnimeList.AddZeroed(NewProject->AnimepackNames.Num()); for(int i = 0; i < NewProject->AnimepackNames.Num(); ++i) { FString FileName = GetFilePath(CurPath, NewProject->Settings.AnimeBaseDirectory, NewProject->AnimepackNames[i].ToString()); TArray<uint8> Data; if(FFileHelper::LoadFileToArray(Data, *FileName)) { const uint8* BufferBegin = Data.GetData(); const uint8* BufferEnd = BufferBegin + Data.Num() - 1; FSsLoader::LoadSsAnimePack(&(NewProject->AnimeList[i]), BufferBegin, (BufferEnd - BufferBegin) + 1); } } // texture for(int i = 0; i < ImagePaths.Num(); ++i) { FString FileName = GetFilePath(CurPath, NewProject->Settings.ImageBaseDirectory, ImagePaths[i]); UTexture* ImportedTexture = NULL; if(ExistImages && ExistImages->Contains(ImagePaths[i])) { ImportedTexture = ExistImages->FindChecked(ImagePaths[i]); } TArray<uint8> Data; if(FFileHelper::LoadFileToArray(Data, *FileName)) { UTextureFactory* TextureFact = NewObject<UTextureFactory>(); TextureFact->AddToRoot(); FString TextureName = FPaths::GetBaseFilename(ImagePaths[i]); UPackage* TexturePackage = NULL; if(ImportedTexture) { TexturePackage = ImportedTexture->GetOutermost(); } else { FString TexturePackageName; FString BasePackageName = FPackageName::GetLongPackagePath(InParent->GetOutermost()->GetName()) / TextureName; AssetToolsModule.Get().CreateUniqueAssetName(BasePackageName, TEXT(""), TexturePackageName, TextureName); TexturePackage = CreatePackage(NULL, *TexturePackageName); } const uint8* BufferBegin = Data.GetData(); const uint8* BufferEnd = BufferBegin + Data.Num(); UTexture2D* NewTexture = (UTexture2D*)TextureFact->FactoryCreateBinary( UTexture2D::StaticClass(), TexturePackage, FName(*TextureName), Flags, NULL, *FPaths::GetExtension(ImagePaths[i]), BufferBegin, BufferEnd, Warn ); if(NewTexture) { if(ImportSettings->bOverwriteMipGenSettings) { NewTexture->MipGenSettings = TMGS_NoMipmaps; } if(ImportSettings->bOverwriteTextureGroup) { NewTexture->LODGroup = ImportSettings->TextureGroup; } if(ImportSettings->bOverwriteCompressionSettings) { NewTexture->CompressionSettings = TextureCompressionSettings::TC_EditorIcon; } if(ImportSettings->bOverwriteTilingMethodFromSspj) { switch(ImageWrapModes[i]) { case SsTexWrapMode::Clamp: { NewTexture->AddressX = NewTexture->AddressY = TA_Clamp; } break; case SsTexWrapMode::Repeat: { NewTexture->AddressX = NewTexture->AddressY = TA_Wrap; } break; case SsTexWrapMode::Mirror: { NewTexture->AddressX = NewTexture->AddressY = TA_Mirror; } break; } } if(ImportSettings->bOverwriteNeverStream) { NewTexture->NeverStream = true; } if(ImportSettings->bOverwriteFilterFromSspj) { switch(ImageFilterModes[i]) { case SsTexFilterMode::Nearest: { NewTexture->Filter = TF_Nearest; } break; case SsTexFilterMode::Linear: { NewTexture->Filter = TF_Bilinear; } break; } } NewTexture->UpdateResource(); FAssetRegistryModule::AssetCreated(NewTexture); TexturePackage->SetDirtyFlag(true); TextureFact->RemoveFromRoot(); ImportedTexture = NewTexture; } } if(ImportedTexture) { for(int ii = 0; ii < NewProject->CellmapList.Num(); ++ii) { if(NewProject->CellmapList[ii].ImagePath == ImagePaths[i]) { NewProject->CellmapList[ii].Texture = ImportedTexture; } } } } } // インポート終了 FEditorDelegates::OnAssetPostImport.Broadcast(this, NewProject); return NewProject; }
void AActor::RerunConstructionScripts() { checkf(!HasAnyFlags(RF_ClassDefaultObject), TEXT("RerunConstructionScripts should never be called on a CDO as it can mutate the transient data on the CDO which then propagates to instances!")); FEditorScriptExecutionGuard ScriptGuard; // don't allow (re)running construction scripts on dying actors bool bAllowReconstruction = !IsPendingKill() && !HasAnyFlags(RF_BeginDestroyed|RF_FinishDestroyed); #if WITH_EDITOR if(bAllowReconstruction && GIsEditor) { // Generate the blueprint hierarchy for this actor TArray<UBlueprint*> ParentBPStack; bAllowReconstruction = UBlueprint::GetBlueprintHierarchyFromClass(GetClass(), ParentBPStack); if(bAllowReconstruction) { for(int i = ParentBPStack.Num() - 1; i > 0 && bAllowReconstruction; --i) { const UBlueprint* ParentBP = ParentBPStack[i]; if(ParentBP && ParentBP->bBeingCompiled) { // don't allow (re)running construction scripts if a parent BP is being compiled bAllowReconstruction = false; } } } } #endif if(bAllowReconstruction) { // Set global flag to let system know we are reconstructing blueprint instances TGuardValue<bool> GuardTemplateNameFlag(GIsReconstructingBlueprintInstances, true); // Temporarily suspend the undo buffer; we don't need to record reconstructed component objects into the current transaction ITransaction* CurrentTransaction = GUndo; GUndo = NULL; // Create cache to store component data across rerunning construction scripts #if WITH_EDITOR FActorTransactionAnnotation* ActorTransactionAnnotation = CurrentTransactionAnnotation.Get(); #endif FComponentInstanceDataCache* InstanceDataCache; FTransform OldTransform = FTransform::Identity; FName SocketName; AActor* Parent = NULL; USceneComponent* ParentComponent = NULL; bool bUseRootComponentProperties = true; // Struct to store info about attached actors struct FAttachedActorInfo { AActor* AttachedActor; FName AttachedToSocket; bool bSetRelativeTransform; FTransform RelativeTransform; }; // Save info about attached actors TArray<FAttachedActorInfo> AttachedActorInfos; #if WITH_EDITOR if (ActorTransactionAnnotation) { InstanceDataCache = &ActorTransactionAnnotation->ComponentInstanceData; if (ActorTransactionAnnotation->bRootComponentDataCached) { OldTransform = ActorTransactionAnnotation->RootComponentData.Transform; Parent = ActorTransactionAnnotation->RootComponentData.AttachedParentInfo.Actor.Get(); if (Parent) { USceneComponent* AttachParent = ActorTransactionAnnotation->RootComponentData.AttachedParentInfo.AttachParent.Get(); ParentComponent = (AttachParent ? AttachParent : FindObjectFast<USceneComponent>(Parent, ActorTransactionAnnotation->RootComponentData.AttachedParentInfo.AttachParentName)); SocketName = ActorTransactionAnnotation->RootComponentData.AttachedParentInfo.SocketName; DetachRootComponentFromParent(); } for (const auto& CachedAttachInfo : ActorTransactionAnnotation->RootComponentData.AttachedToInfo) { AActor* AttachedActor = CachedAttachInfo.Actor.Get(); if (AttachedActor) { FAttachedActorInfo Info; Info.AttachedActor = AttachedActor; Info.AttachedToSocket = CachedAttachInfo.SocketName; Info.bSetRelativeTransform = true; Info.RelativeTransform = CachedAttachInfo.RelativeTransform; AttachedActorInfos.Add(Info); AttachedActor->DetachRootComponentFromParent(); } } bUseRootComponentProperties = false; } } else #endif { InstanceDataCache = new FComponentInstanceDataCache(this); // If there are attached objects detach them and store the socket names TArray<AActor*> AttachedActors; GetAttachedActors(AttachedActors); for (AActor* AttachedActor : AttachedActors) { USceneComponent* EachRoot = AttachedActor->GetRootComponent(); // If the component we are attached to is about to go away... if (EachRoot && EachRoot->AttachParent && EachRoot->AttachParent->IsCreatedByConstructionScript()) { // Save info about actor to reattach FAttachedActorInfo Info; Info.AttachedActor = AttachedActor; Info.AttachedToSocket = EachRoot->AttachSocketName; Info.bSetRelativeTransform = false; AttachedActorInfos.Add(Info); // Now detach it AttachedActor->Modify(); EachRoot->DetachFromParent(true); } } } if (bUseRootComponentProperties && RootComponent != nullptr) { // Do not need to detach if root component is not going away if (RootComponent->AttachParent != NULL && RootComponent->IsCreatedByConstructionScript()) { Parent = RootComponent->AttachParent->GetOwner(); // Root component should never be attached to another component in the same actor! if (Parent == this) { UE_LOG(LogActor, Warning, TEXT("RerunConstructionScripts: RootComponent (%s) attached to another component in this Actor (%s)."), *RootComponent->GetPathName(), *Parent->GetPathName()); Parent = NULL; } ParentComponent = RootComponent->AttachParent; SocketName = RootComponent->AttachSocketName; //detach it to remove any scaling RootComponent->DetachFromParent(true); } OldTransform = RootComponent->ComponentToWorld; OldTransform.SetTranslation(RootComponent->GetComponentLocation()); // take into account any custom location } #if WITH_EDITOR // Save the current construction script-created components by name TMap<const FName, UObject*> DestroyedComponentsByName; TInlineComponentArray<UActorComponent*> PreviouslyAttachedComponents; GetComponents(PreviouslyAttachedComponents); for (auto Component : PreviouslyAttachedComponents) { if (Component) { if (Component->IsCreatedByConstructionScript()) { DestroyedComponentsByName.Add(Component->GetFName(), Component); } else { UActorComponent* OuterComponent = Component->GetTypedOuter<UActorComponent>(); while (OuterComponent) { if (OuterComponent->IsCreatedByConstructionScript()) { DestroyedComponentsByName.Add(Component->GetFName(), Component); break; } OuterComponent = OuterComponent->GetTypedOuter<UActorComponent>(); } } } } #endif // Destroy existing components DestroyConstructedComponents(); // Reset random streams ResetPropertiesForConstruction(); // Exchange net roles before running construction scripts UWorld *OwningWorld = GetWorld(); if (OwningWorld && !OwningWorld->IsServer()) { ExchangeNetRoles(true); } // Run the construction scripts ExecuteConstruction(OldTransform, InstanceDataCache); if(Parent) { USceneComponent* ChildRoot = GetRootComponent(); if (ParentComponent == NULL) { ParentComponent = Parent->GetRootComponent(); } if (ChildRoot != NULL && ParentComponent != NULL) { ChildRoot->AttachTo(ParentComponent, SocketName, EAttachLocation::KeepWorldPosition); } } // If we had attached children reattach them now - unless they are already attached for(FAttachedActorInfo& Info : AttachedActorInfos) { // If this actor is no longer attached to anything, reattach if (!Info.AttachedActor->IsPendingKill() && Info.AttachedActor->GetAttachParentActor() == NULL) { USceneComponent* ChildRoot = Info.AttachedActor->GetRootComponent(); if (ChildRoot && ChildRoot->AttachParent != RootComponent) { ChildRoot->AttachTo(RootComponent, Info.AttachedToSocket, EAttachLocation::KeepWorldPosition); if (Info.bSetRelativeTransform) { ChildRoot->SetRelativeTransform(Info.RelativeTransform); } ChildRoot->UpdateComponentToWorld(); } } } // Restore the undo buffer GUndo = CurrentTransaction; #if WITH_EDITOR // Create the mapping of old->new components and notify the editor of the replacements TMap<UObject*, UObject*> OldToNewComponentMapping; TInlineComponentArray<UActorComponent*> NewComponents; GetComponents(NewComponents); for (auto NewComp : NewComponents) { const FName NewCompName = NewComp->GetFName(); if (DestroyedComponentsByName.Contains(NewCompName)) { OldToNewComponentMapping.Add(DestroyedComponentsByName[NewCompName], NewComp); } } if (GEditor && (OldToNewComponentMapping.Num() > 0)) { GEditor->NotifyToolsOfObjectReplacement(OldToNewComponentMapping); } if (ActorTransactionAnnotation) { CurrentTransactionAnnotation = NULL; } else #endif { delete InstanceDataCache; } } }
/******************** ProcessResourceRequests *************************/ void APOTLStructure::ProcessResourceRequests() { int32 i; int32 HighestSequence = -1; TMap<int32, TArray<FST_ResourceRequest>> SortedResourceRequests; //~~ Get highest sequence from all of the requests ~~// for (i = 0; i < ResourceRequests.Num(); i++) { FST_ResourceRequest& ResourceRequest = ResourceRequests[i]; if (ResourceRequest.Sequence > HighestSequence) { HighestSequence = ResourceRequest.Sequence; } } //~~ Init SortedResourceRequests. Make empty arrays ~~// for (i = 0; i <= HighestSequence; i++) { TArray<FST_ResourceRequest> List; SortedResourceRequests.Add(i, List); } //~~ Add resource request to sorted tmap ~~// for (i = 0; i < ResourceRequests.Num(); i++) { FST_ResourceRequest& ResourceRequest = ResourceRequests[i]; int32 Sequence = ResourceRequest.Sequence; if (SortedResourceRequests.Contains(Sequence)) { SortedResourceRequests[Sequence].Add(ResourceRequest); } else { GEngine->AddOnScreenDebugMessage(-1, 30.0f, FColor::Red, "ERROR: SortedResourceRequests could not recivce request with a sequence not found "); } } //~~ Allocate and process the requests ~~// for (i = 0; i <= HighestSequence; i++) //~~ Handle the request from sequence zero and up ~~// { TArray<FST_ResourceRequest>& RequestList = SortedResourceRequests[i]; for (int32 ii = 0; ii < RequestList.Num(); ii++) // Loop through sequence row list. Ex 0[{R}, {R}, {R}] { FST_ResourceRequest& ResourceRequest = RequestList[ii]; if (ResourceRequest.Request.Num() > 1) { FString Sasdsa; } if (HasResourcesAvailable(ResourceRequest.Request, true, i)) //~~ If self has the resources required. (i) is the sequence, not (ii), it is just a list index for the nested array. ~~// { TArray<int32> AllocationIndexes; //~~ Requirements ~~// for (auto& ReqResource : ResourceRequest.Request) //~~ Loop each resource in request ~~// { //? AllocateResource with group id for grouping multiple allocations? if (FreeResources.Contains(ReqResource.Key)) { int32 AvailableQuantity = FreeResources[ReqResource.Key]; if (AvailableQuantity > ReqResource.Value) { AvailableQuantity = ReqResource.Value; } //int32 AllocationIndex = AllocateResource(ResourceRequest.From, ReqResource.Key, AvailableQuantity, EAllocationType::FactoryBilling, ii, true, -1); int32 AllocationIndex = AllocateResource(ResourceRequest.From, ReqResource.Key, AvailableQuantity, EAllocationType::FactoryBilling, i, true, -1); AllocationIndexes.Add(AllocationIndex); ReqResource.Value = ReqResource.Value - AvailableQuantity; } if (ReqResource.Value > 0) //~~ If freeresources couldn't meet the requiement of the resource quantity, then make reallocations ~~// { for (auto& AllocatedResource : AllocatedResources) { FST_ResourceAllocation& Allocation = AllocatedResource.Value; if (Allocation.ResourceKey == ReqResource.Key && Allocation.Sequence < ResourceRequest.Sequence && Allocation.To == this && Allocation.Type == EAllocationType::FactoryProduction && Allocation.Quantity > 0) { //!! BUG BEGIN if (ReqResource.Value < Allocation.Quantity) //~~ If request if less than allocation quantity, then split allocation ~~// { //Allocation.Quantity = Allocation.Quantity - ReqResource.Value; //~~ Subtract resource request quantity from the allocation, and then let it be ~~// //int32 NewAllocationAmount = Allocation.Quantity - ReqResource.Value; int32 NewAllocationAmount = ReqResource.Value; Allocation.Quantity = Allocation.Quantity - ReqResource.Value; //~~ Subtract resource request quantity from the allocation, and then let it be ~~// //Split logic //~~ Make new allocation with ~~// //int32 AllocationIndex = Allocation.From->AllocateResource(ResourceRequest.From, ReqResource.Key, ReqResource.Value, EAllocationType::FactoryBilling, ii, false, -1); int32 AllocationIndex = Allocation.From->AllocateResource(ResourceRequest.From, ReqResource.Key, NewAllocationAmount, EAllocationType::FactoryBilling, Allocation.Sequence, false, -1); AllocationIndexes.Add(AllocationIndex); ReqResource.Value = 0; } else if (ReqResource.Value >= Allocation.Quantity) //~~ If request is more or equal to allocation quantity, then just change allocation to target ~~// { Allocation.To = ResourceRequest.From; Allocation.Type = EAllocationType::FactoryBilling; //! Maybe it needs to be a unique type, like FactoryProductionReallocation or something. //ReqResource.Value = ReqResource.Value - AvailableQuantity; //ReqResource.Value = ReqResource.Value - Allocation.Quantity; FString TestValue = FString::FromInt(Allocation.Quantity); ReqResource.Value = ReqResource.Value - Allocation.Quantity; // 3 ? = 4 - 4 // ? = 4 - 2; } //!! BUG END } if (ReqResource.Value == 0) { break; } } if (ReqResource.Value > 0) { FString Bug; } } } //~~ Payoff ~~// for (auto& Resource : ResourceRequest.Payoff) //~~ Loop each resource in payoff ~~// { //~~ Add resource payoff to the keeper of the factory, and then allocate it to root afterwards ~~// //ResourceRequest.From->AddResource(Resource.Key, Resource.Value, EResourceList::Free); //~~ Add Resources and then consume them with AllocateResource(true) ~~// //!~~ No need for adding them, and then consuming them anymore. AllocateResource can not be called with consume: false ~~// //int32 AllocationIndex = ResourceRequest.From->AllocateResource(this, Resource.Key, Resource.Value, EAllocationType::FactoryProduction, ii, false, -1); // Maybe ii + 1 ? I think not. Are checked if sequence is lower, not lower or equal int32 AllocationIndex = ResourceRequest.From->AllocateResource(this, Resource.Key, Resource.Value, EAllocationType::FactoryProduction, i, false, -1); // Maybe ii + 1 ? I think not. Are checked if sequence is lower, not lower or equal if (ResourceRequest.Factory) { ResourceRequest.Factory->AllocationIndex = AllocationIndex; } AllocationIndexes.Add(AllocationIndex); } ResourceRequest.RequestMet = true; } else { } } } }
/** * 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. TMap<UObject*, TSharedPtr<ITransactionObjectAnnotation>> ChangedObjects; for( int32 i=Start; i!=End; i+=Inc ) { FObjectRecord& Record = Records[i]; Record.bRestored = false; UObject* Object = Record.Object.Get(); if (!ChangedObjects.Contains(Object)) { Object->CheckDefaultSubobjects(); Object->PreEditUndo(); } ChangedObjects.Add(Object, Record.ObjectAnnotation); } for( int32 i=Start; i!=End; i+=Inc ) { Records[i].Restore( this ); } // An Actor's components must always get its PostEditUndo before the owning Actor so do a quick sort ChangedObjects.KeySort([](UObject& A, UObject& B) { UActorComponent* BAsComponent = Cast<UActorComponent>(&B); return (BAsComponent ? (BAsComponent->GetOwner() != &A) : true); }); NumModelsModified = 0; // Count the number of UModels that were changed. for (auto ChangedObjectIt : ChangedObjects) { UObject* ChangedObject = ChangedObjectIt.Key; UModel* Model = Cast<UModel>(ChangedObject); if (Model && Model->Nodes.Num()) { FBSPOps::bspBuildBounds(Model); ++NumModelsModified; } TSharedPtr<ITransactionObjectAnnotation> ChangedObjectTransactionAnnotation = ChangedObjectIt.Value; if (ChangedObjectTransactionAnnotation.IsValid()) { ChangedObject->PostEditUndo(ChangedObjectTransactionAnnotation); } else { ChangedObject->PostEditUndo(); } } // Flip it. if (bFlip) { Inc *= -1; } for (auto ChangedObjectIt : ChangedObjects) { UObject* ChangedObject = ChangedObjectIt.Key; ChangedObject->CheckDefaultSubobjects(); } }