/** * Debug spew for components * @param Object object to dump component spew for */ void DumpComponents(UObject *Object) { for ( FObjectIterator It; It; ++It ) { It->UnMark(EObjectMark(OBJECTMARK_TagImp | OBJECTMARK_TagExp)); } if (FPlatformMisc::IsDebuggerPresent() ) { // if we have a debugger attached, the watch window won't be able to display the full output if we attempt to log it as a single string // so pass in GLog instead so that each line is sent separately; this causes the output to have an extra line break between each log statement, // but at least we'll be able to see the full output in the debugger's watch window UE_LOG(LogExporter, Log, TEXT("Components for '%s':"), *Object->GetFullName()); ExportProperties( NULL, *GLog, Object->GetClass(), (uint8*)Object, 0, NULL, NULL, Object, PPF_SubobjectsOnly ); UE_LOG(LogExporter, Log, TEXT("<--- DONE!")); } else { FStringOutputDevice Output; Output.Logf(TEXT("Components for '%s':\r\n"), *Object->GetFullName()); ExportProperties( NULL, Output, Object->GetClass(), (uint8*)Object, 2, NULL, NULL, Object, PPF_SubobjectsOnly ); Output.Logf(TEXT("<--- DONE!\r\n")); UE_LOG(LogExporter, Log, TEXT("%s"), *Output); } }
FString DumpComponentsToString(UObject *Object) { UnMarkAllObjects(EObjectMark(OBJECTMARK_TagExp | OBJECTMARK_TagImp)); FStringOutputDevice Output; Output.Logf(TEXT("Components for '%s':\r\n"), *Object->GetFullName()); ExportProperties(NULL, Output, Object->GetClass(), (uint8*)Object, 2, NULL, NULL, Object, PPF_SubobjectsOnly); Output.Logf(TEXT("<--- DONE!\r\n")); return Output; }
bool GenerateProjectFiles(const FString& ProjectFileName) { IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get(); // Check it's a code project FString SourceDir = FPaths::GetPath(ProjectFileName) / TEXT("Source"); if(!IPlatformFile::GetPlatformPhysical().DirectoryExists(*SourceDir)) { FPlatformMisc::MessageBoxExt(EAppMsgType::Ok, TEXT("This project does not have any source code. You need to add C++ source files to the project from the Editor before you can generate project files."), TEXT("Error")); return false; } // Get the engine root directory FString RootDir; if (!GetValidatedEngineRootDir(ProjectFileName, RootDir)) { return false; } // Build the argument list FString Arguments = TEXT("-game"); if (FDesktopPlatformModule::Get()->IsSourceDistribution(RootDir)) { Arguments += TEXT(" -engine"); } // Start capturing the log output FStringOutputDevice LogCapture; LogCapture.SetAutoEmitLineTerminator(true); GLog->AddOutputDevice(&LogCapture); // Generate project files FFeedbackContext* Warn = DesktopPlatform->GetNativeFeedbackContext(); bool bResult = DesktopPlatform->GenerateProjectFiles(RootDir, ProjectFileName, Warn); GLog->RemoveOutputDevice(&LogCapture); // Display an error dialog if we failed if(!bResult) { FPlatformInstallation::ErrorDialog(TEXT("Failed to generate project files."), LogCapture); return false; } return true; }
void LogIncludeCount(const TArray<FString>& IncludesInPCH, const TMap<FString, int32>& IncludeHeaderCount, int32 FileCount, float IncludePercentageThreshold) { for (const auto& FilenameAbsolutePath : IncludesInPCH) { auto IncludeCount = GetIncludeCount(IncludeHeaderCount, FilenameAbsolutePath); auto IncludePercentage = static_cast<float>(IncludeCount) / static_cast<float>(FileCount); if (IncludePercentage < IncludePercentageThreshold) { OutputFileContents.Logf(TEXT("%s %i(%f%%) with threshold %f%%"), *FilenameAbsolutePath, IncludeCount, IncludePercentage, IncludePercentageThreshold); } } }
bool UDiffAssetsCommandlet::ExportFile(const FString& Filename, const TArray<UObject *>& LoadedObjects) { FString Extension = TEXT("t3d"); FStringOutputDevice Buffer; const FExportObjectInnerContext Context; for (int32 Index = 0; Index < LoadedObjects.Num(); Index++) { UExporter* Exporter = UExporter::FindExporter( LoadedObjects[Index], *Extension ); if (!Exporter) { UE_LOG(LogDiffAssetsCommandlet, Warning, TEXT("Could not find exporter.")); return false; } UExporter::ExportToOutputDevice( &Context, LoadedObjects[Index], Exporter, Buffer, *Extension, 0, PPF_ExportsNotFullyQualified, false ); TMap<FString,FString> NativePropertyValues; if ( LoadedObjects[Index]->GetNativePropertyValues(NativePropertyValues) && NativePropertyValues.Num()) { int32 LargestKey = 0; for ( TMap<FString,FString>::TIterator It(NativePropertyValues); It; ++It ) { LargestKey = FMath::Max(LargestKey, It.Key().Len()); } for ( TMap<FString,FString>::TIterator It(NativePropertyValues); It; ++It ) { Buffer.Logf(TEXT(" %s=%s"), *It.Key().RightPad(LargestKey), *It.Value()); } } } if (!Buffer.Len()) { UE_LOG(LogDiffAssetsCommandlet, Warning, TEXT("No text was exported!")); return false; } if( !FFileHelper::SaveStringToFile( Buffer, *Filename ) ) { UE_LOG(LogDiffAssetsCommandlet, Warning, TEXT("Could not write %s"), *Filename); return false; } return true; }
FString FUnrealSourceFile::GetFileId() const { FString StdFilename = Filename; FPaths::MakeStandardFilename(StdFilename); bool RelativePath = FPaths::IsRelative(StdFilename); if (!RelativePath) { // If path is still absolute that means MakeStandardFilename has failed // In this case make it relative to the current project. RelativePath = FPaths::MakePathRelativeTo(StdFilename, *FPaths::GetPath(FPaths::GetProjectFilePath())); } // If the path has passed either MakeStandardFilename or MakePathRelativeTo it should be using internal path seperators if (RelativePath) { // Remove any preceding parent directory paths while (StdFilename.RemoveFromStart(TEXT("../"))); } FStringOutputDevice Out; for (auto Char : StdFilename) { if (FChar::IsAlnum(Char)) { Out.AppendChar(Char); } else { Out.AppendChar('_'); } } return Out; }
int AnalyzePCHFile(const FString& CmdLine) { auto IncludePercentageThreshold = ParseUsageThreshold(*CmdLine); auto IncludeSearchPaths = ParseIncludeSearchPaths(*CmdLine); FString IncludesDirectory; FParse::Value(*CmdLine, TEXT("-HeaderDataPath="), IncludesDirectory); int32 FileCount = 0; TMap<FString, int32> IncludeHeaderCount; GatherModuleHeaderData(*IncludesDirectory, FileCount, IncludeHeaderCount); // Open PCH file FString PCHFilePath; FParse::Value(*CmdLine, TEXT("-PCHFile="), PCHFilePath); TArray<FString> IncludesInPCH = GetIncludesInPCH(PCHFilePath, IncludeSearchPaths); OutputFileContents.Logf(TEXT("Remove the following #includes from %s"), *PCHFilePath); LogIncludeCount(IncludesInPCH, IncludeHeaderCount, FileCount, IncludePercentageThreshold); OutputFileContents.Logf(TEXT("Add the following #includes to %s"), *PCHFilePath); for (auto KVP : IncludeHeaderCount) { const auto& Filename = KVP.Key; const auto& HeaderIncludeCount = KVP.Value; auto IncludePercentage = static_cast<float>(HeaderIncludeCount) / static_cast<float>(FileCount); if (IncludePercentage > IncludePercentageThreshold) { OutputFileContents.Logf(TEXT("%s (%i/%i)%f%%"), *Filename, HeaderIncludeCount, FileCount, IncludePercentage); } } return 0; }
// // If analysis/clang compilation gives an error, we still can provide some meaningful data to user, // which is why we return 0 in such cases. We return error only when -OutputFile is not provided and // when saving output file fails. // int main(int32 ArgC, const char* ArgV[]) { FString CmdLine = CreateCommandLine(ArgC, ArgV); FString ShortCmdLine = FCommandLine::RemoveExeName(*CmdLine); ShortCmdLine = ShortCmdLine.Trim(); GEngineLoop.PreInit(*ShortCmdLine); if (!FParse::Value(*CmdLine, TEXT("-OutputFile="), OutputFileName)) { return 1; } OutputFileContents.SetAutoEmitLineTerminator(true); if (FParse::Param(*CmdLine, TEXT("AnalyzePCHFile"))) { AnalyzePCHFile(CmdLine); } if (FParse::Param(*CmdLine, TEXT("CreateIncludeFiles"))) { CreateIncludeFiles(ArgC, ArgV); } if (FParse::Param(*CmdLine, TEXT("CheckThreadSafety"))) { CheckThreadSafety(ArgC, ArgV); } if (!FFileHelper::SaveStringToFile(OutputFileContents, *OutputFileName)) { return 2; } return 0; }
int32 UExporter::ExportToFile( UObject* Object, UExporter* InExporter, const TCHAR* Filename, bool InSelectedOnly, bool NoReplaceIdentical, bool Prompt ) { #if WITH_EDITOR check(Object); CurrentFilename = Filename; UExporter* Exporter = InExporter; int32 Result = 0; FString Extension; if (!Exporter) { // look for an exporter with all possible extensions, so an exporter can have something like *.xxx.yyy as an extension int32 SearchStart = 0; int32 DotLocation; while (!Exporter && (DotLocation = CurrentFilename.Find(TEXT("."), ESearchCase::CaseSensitive, ESearchDir::FromStart, SearchStart)) != INDEX_NONE) { // get everything after the current . Extension = CurrentFilename.Mid(DotLocation + 1); // try to find an exporter with it Exporter = FindExporter( Object, *Extension ); // skip past the dot in case we look again SearchStart = DotLocation + 1; } } if( !Exporter ) { UE_LOG(LogExporter, Warning, TEXT("No %s exporter found for %s"), *Extension, *Object->GetFullName() ); CurrentFilename = TEXT(""); return 0; } Exporter->bSelectedOnly = InSelectedOnly; if( Exporter->bText ) { FStringOutputDevice Buffer; const FExportObjectInnerContext Context; ExportToOutputDevice( &Context, Object, Exporter, Buffer, *Extension, 0, PPF_ExportsNotFullyQualified, InSelectedOnly ); if ( Buffer.Len() == 0 ) { Result = -1; } else { if( NoReplaceIdentical ) { FString FileBytes; if ( FFileHelper::LoadFileToString(FileBytes,Filename) && FCString::Strcmp(*Buffer,*FileBytes) == 0 ) { UE_LOG(LogExporter, Log, TEXT("Not replacing %s because identical"), Filename ); Result = 1; goto Done; } if( Prompt ) { if( !GWarn->YesNof( FText::Format( NSLOCTEXT("Core", "Overwrite", "The file '{0}' needs to be updated. Do you want to overwrite the existing version?"), FText::FromString( Filename ) ) ) ) { Result = 1; goto Done; } } } if( !FFileHelper::SaveStringToFile( Buffer, Filename ) ) { #if 0 if( GWarn->YesNof( FText::Format( NSLOCTEXT("Core", "OverwriteReadOnly", "'{0}' is marked read-only. Would you like to try to force overwriting it?"), FText::FromString( Filename ) ) ) ) { IFileManager::Get().Delete( Filename, 0, 1 ); if( FFileHelper::SaveStringToFile( Buffer, Filename ) ) { Result = 1; goto Done; } } #endif UE_LOG(LogExporter, Error, TEXT("Error exporting %s: couldn't open file '%s'"), *Object->GetFullName(), Filename); goto Done; } Result = 1; } } else { for( int32 i = 0; i < Exporter->GetFileCount(); i++ ) { FBufferArchive Buffer; if( ExportToArchive( Object, Exporter, Buffer, *Extension, i ) ) { FString UniqueFilename = Exporter->GetUniqueFilename( Filename, i ); if( NoReplaceIdentical ) { TArray<uint8> FileBytes; if( FFileHelper::LoadFileToArray( FileBytes, *UniqueFilename ) && FileBytes.Num() == Buffer.Num() && FMemory::Memcmp( &FileBytes[ 0 ], &Buffer[ 0 ], Buffer.Num() ) == 0 ) { UE_LOG(LogExporter, Log, TEXT( "Not replacing %s because identical" ), *UniqueFilename ); Result = 1; goto Done; } if( Prompt ) { if( !GWarn->YesNof( FText::Format( NSLOCTEXT("Core", "Overwrite", "The file '{0}' needs to be updated. Do you want to overwrite the existing version?"), FText::FromString( UniqueFilename ) ) ) ) { Result = 1; goto Done; } } } if( !FFileHelper::SaveArrayToFile( Buffer, *UniqueFilename ) ) { UE_LOG(LogExporter, Error, TEXT("Error exporting %s: couldn't open file '%s'"), *Object->GetFullName(), *UniqueFilename); goto Done; } } } Result = 1; } Done: CurrentFilename = TEXT(""); return Result; #else return 0; #endif }
bool ANUTActor::NotifyControlMessage(UNetConnection* Connection, uint8 MessageType, FInBunch& Bunch) { bool bHandledMessage = false; if (MessageType == NMT_NUTControl) { uint8 CmdType = 0; FString Command; FNetControlMessage<NMT_NUTControl>::Receive(Bunch, CmdType, Command); // Console command if (CmdType == ENUTControlCommand::Command_NoResult || CmdType == ENUTControlCommand::Command_SendResult) { UE_LOG(LogUnitTest, Log, TEXT("NMT_NUTControl: Executing command: %s"), *Command); FStringOutputDevice CmdResult; CmdResult.SetAutoEmitLineTerminator(true); bool bCmdSuccess = false; bCmdSuccess = GEngine->Exec(GetWorld(), *Command, CmdResult); UE_LOG(LogUnitTest, Log, TEXT("NMT_NUTControl: Command result: %s"), *CmdResult); bool bSendResult = CmdType == ENUTControlCommand::Command_SendResult; if (bSendResult) { uint8 ReturnCmdType = (bCmdSuccess ? ENUTControlCommand::CommandResult_Success : ENUTControlCommand::CommandResult_Failed); FNetControlMessage<NMT_NUTControl>::Send(Connection, ReturnCmdType, CmdResult); } } // Console command result else if (CmdType == ENUTControlCommand::CommandResult_Failed || CmdType == ENUTControlCommand::CommandResult_Success) { bool bCmdSuccess = CmdType == ENUTControlCommand::CommandResult_Success; if (bCmdSuccess) { UE_LOG(LogUnitTest, Log, TEXT("NMT_NUTControl: Got command result:")); UE_LOG(LogUnitTest, Log, TEXT("%s"), *Command); } else { UE_LOG(LogUnitTest, Log, TEXT("NMT_NUTControl: Failed to execute command")); } } // Ping request else if (CmdType == ENUTControlCommand::Ping) { uint8 TempCmdType = ENUTControlCommand::Pong; FString Dud; FNetControlMessage<NMT_NUTControl>::Send(Connection, TempCmdType, Dud); } // Pong reply - this should only be implemented by custom unit tests; hence the assert else if (CmdType == ENUTControlCommand::Pong) { UNIT_ASSERT(false); } // Custom implemented events, with the result triggered through 'NotifyEvent' else if (CmdType == ENUTControlCommand::WatchEvent) { // NOTE: Only the last NetConnection to request a WatchEvent, will receive notifications EventWatcher = Connection; // Watch for the end of seamless travel if (Command == TEXT("SeamlessTravelEnd")) { FCoreUObjectDelegates::PostLoadMap.AddStatic(&ANUTActor::NotifyPostLoadMap); } } // Event watch notification - should only be implemented by custom unit tests else if (CmdType == ENUTControlCommand::NotifyEvent) { UNIT_ASSERT(false); } // Create an actor instance (the 'summon' console command, doesn't work without a cheat manager) else if (CmdType == ENUTControlCommand::Summon) { const TCHAR* Cmd = *Command; FString SpawnClassName = FParse::Token(Cmd, false); bool bForceBeginPlay = FParse::Param(Cmd, TEXT("ForceBeginPlay")); // Hack specifically for getting the GameplayDebugger working - think the mainline code is broken bool bGameplayDebuggerHack = FParse::Param(Cmd, TEXT("GameplayDebuggerHack")); UClass* SpawnClass = FindObject<UClass>(NULL, *SpawnClassName); if (SpawnClass != NULL) { FActorSpawnParameters SpawnParms; SpawnParms.Owner = GetOwner(); AActor* NewActor = GetWorld()->SpawnActor<AActor>(SpawnClass, SpawnParms); if (NewActor != NULL) { UE_LOG(LogUnitTest, Log, TEXT("Successfully summoned actor of class '%s'"), *SpawnClassName); if (bForceBeginPlay && !NewActor->HasActorBegunPlay()) { UE_LOG(LogUnitTest, Log, TEXT("Forcing call to 'BeginPlay' on newly spawned actor.")); NewActor->BeginPlay(); } if (bGameplayDebuggerHack) { // Assign the LocalPlayerOwner property, to the PC owning this NUTActor, using reflection (to avoid dependency) UObjectProperty* LocalPlayerOwnerProp = FindField<UObjectProperty>(NewActor->GetClass(), TEXT("LocalPlayerOwner")); if (LocalPlayerOwnerProp != NULL) { LocalPlayerOwnerProp->SetObjectPropertyValue( LocalPlayerOwnerProp->ContainerPtrToValuePtr<UObject*>(NewActor), GetOwner()); } else { UE_LOG(LogUnitTest, Log, TEXT("WARNING: Failed to find 'LocalPlayerOwner' property. Unit test broken.")); } // Also hack-disable ticking, so that the replicator doesn't spawn a second replicator NewActor->SetActorTickEnabled(false); } } else { UE_LOG(LogUnitTest, Log, TEXT("SpawnActor failed for class '%s'"), *Command); } } else { UE_LOG(LogUnitTest, Log, TEXT("Could not find actor class '%s'"), *Command); } } // Suspend the game, until a resume request is received (used for giving time, to attach a debugger) else if (CmdType == ENUTControlCommand::SuspendProcess) { UE_LOG(LogUnitTest, Log, TEXT("Suspend start.")); // Setup a named pipe, to monitor for the resume request FString ResumePipeName = FString::Printf(TEXT("%s%u"), NUT_SUSPEND_PIPE, FPlatformProcess::GetCurrentProcessId()); FPlatformNamedPipe ResumePipe; bool bPipeCreated = ResumePipe.Create(ResumePipeName, true, false); if (bPipeCreated) { if (!ResumePipe.OpenConnection()) { UE_LOG(LogUnitTest, Log, TEXT("WARNING: Failed to open pipe connection.")); } } else { UE_LOG(LogUnitTest, Log, TEXT("WARNING: Failed to create resume pipe.")); } // Spin/sleep (effectively suspended) until a resume request is received while (true) { if (bPipeCreated && ResumePipe.IsReadyForRW()) { int32 ResumeVal = 0; if (ResumePipe.ReadInt32(ResumeVal) && !!ResumeVal) { UE_LOG(LogUnitTest, Log, TEXT("Got resume request.")); break; } } FPlatformProcess::Sleep(1.0f); } ResumePipe.Destroy(); UE_LOG(LogUnitTest, Log, TEXT("Suspend end.")); } bHandledMessage = true; } return bHandledMessage; }
bool FPerfCounters::ProcessRequest(uint8* Buffer, int32 BufferLen, FResponse& Response) { bool bSuccess = false; // scan the buffer for a line FUTF8ToTCHAR WideBuffer(reinterpret_cast<const ANSICHAR*>(Buffer)); const TCHAR* BufferEnd = FCString::Strstr(WideBuffer.Get(), TEXT("\r\n")); if (BufferEnd != nullptr) { // crack into pieces FString MainLine(BufferEnd - WideBuffer.Get(), WideBuffer.Get()); TArray<FString> Tokens; MainLine.ParseIntoArrayWS(Tokens); if (Tokens.Num() >= 2) { FString ContentType(TEXT("application/json")); Response.Code = 200; // handle the request if (Tokens[0] != TEXT("GET")) { Response.Body = FString::Printf(TEXT("{ \"error\": \"Method %s not allowed\" }"), *Tokens[0]); Response.Code = 405; } else if (Tokens[1].StartsWith(TEXT("/stats"))) { Response.Body = GetAllCountersAsJson(); } else if (Tokens[1].StartsWith(TEXT("/exec?c="))) { FString ExecCmd = Tokens[1].Mid(8); FString ExecCmdDecoded = FPlatformHttp::UrlDecode(ExecCmd); FStringOutputDevice StringOutDevice; StringOutDevice.SetAutoEmitLineTerminator(true); bool bResult = false; if (ExecCmdCallback.IsBound()) { bResult = ExecCmdCallback.Execute(ExecCmdDecoded, StringOutDevice); Response.Body = StringOutDevice; ContentType = TEXT("text/text"); } else { Response.Body = FString::Printf(TEXT("{ \"error\": \"exec handler not found\" }")); } Response.Code = bResult ? 200 : 404; } else { Response.Body = FString::Printf(TEXT("{ \"error\": \"%s not found\" }"), *Tokens[1]); Response.Code = 404; } // send the response headers Response.Header = FString::Printf(TEXT("HTTP/1.0 %d\r\nContent-Length: %d\r\nContent-Type: %s\r\n\r\n"), Response.Code, Response.Body.Len(), *ContentType); bSuccess = true; } else { UE_LOG(LogPerfCounters, Warning, TEXT("Unable to parse HTTP request header: %s"), *MainLine); } } else { UE_LOG(LogPerfCounters, Warning, TEXT("Unable to immediately receive full request header")); } return bSuccess; }