Example #1
0
bool FPipeHandle::ReadToArray(TArray<uint8> & Output)
{
	int BytesAvailable = 0;
	if (ioctl(PipeDesc, FIONREAD, &BytesAvailable) == 0)
	{
		if (BytesAvailable > 0)
		{
			Output.SetNumUninitialized(BytesAvailable);
			int BytesRead = read(PipeDesc, Output.GetData(), BytesAvailable);
			if (BytesRead > 0)
			{
				if (BytesRead < BytesAvailable)
				{
					Output.SetNum(BytesRead);
				}

				return true;
			}
			else
			{
				Output.Empty();
			}
		}
	}

	return false;
}
void UGameplayTagReponseTable::RegisterResponseForEvents(UAbilitySystemComponent* ASC)
{
	if (RegisteredASCs.Contains(ASC))
	{
		return;
	}

	TArray<FGameplayTagResponseAppliedInfo> AppliedInfoList;
	AppliedInfoList.SetNum(Entries.Num());

	RegisteredASCs.Add(ASC, AppliedInfoList );

	for (int32 idx=0; idx < Entries.Num(); ++idx)
	{
		const FGameplayTagResponseTableEntry& Entry = Entries[idx];
		if (Entry.Positive.Tag.IsValid())
		{
			ASC->RegisterGameplayTagEvent( Entry.Positive.Tag, EGameplayTagEventType::AnyCountChange ).AddUObject(this, &UGameplayTagReponseTable::TagResponseEvent, ASC, idx);
		}
		if (Entry.Negative.Tag.IsValid())
		{
			ASC->RegisterGameplayTagEvent( Entry.Negative.Tag, EGameplayTagEventType::AnyCountChange ).AddUObject(this, &UGameplayTagReponseTable::TagResponseEvent, ASC, idx);
		}
	}
}
TArray<uint8> UMasterServerFunctions::CompressBytes(FString UncompressedString)
{
	TArray<uint8> UncompressedBinaryArray = FStringToBinaryArray(UncompressedString);
	TArray<uint8> CompressedBinaryArray;
	CompressedBinaryArray.SetNum(UncompressedBinaryArray.Num() * 1023, true);

	//int ret;
	z_stream strm;
	strm.zalloc = Z_NULL;
	strm.zfree = Z_NULL;
	strm.opaque = Z_NULL;

	strm.avail_in = UncompressedBinaryArray.Num();
	strm.next_in = (Bytef *)UncompressedBinaryArray.GetData();
	strm.avail_out = CompressedBinaryArray.Num();
	strm.next_out = (Bytef *)CompressedBinaryArray.GetData();


	// the actual compression work.
	deflateInit(&strm, Z_BEST_COMPRESSION);
	deflate(&strm, Z_FINISH);
	deflateEnd(&strm);

	// Shrink the array to minimum size
	CompressedBinaryArray.RemoveAt(strm.total_out, CompressedBinaryArray.Num() - strm.total_out, true);
	return CompressedBinaryArray;

}
void FStreamableManager::RequestAsyncLoad(const TArray<FStringAssetReference>& TargetsToStream, FStreamableDelegate DelegateToCall)
{
	// Schedule a new callback, this will get called when all related async loads are completed
	TSharedRef<FStreamableRequest> NewRequest = MakeShareable(new FStreamableRequest());
	NewRequest->CompletionDelegate = DelegateToCall;

	TArray<FStreamable *> ExistingStreamables;
	ExistingStreamables.SetNum(TargetsToStream.Num());

	for (int32 i = 0; i < TargetsToStream.Num(); i++)
	{
		FStreamable* Existing = StreamInternal(TargetsToStream[i]);
		ExistingStreamables[i] = Existing;

		if (Existing)
		{
			Existing->AddRelatedRequest(NewRequest);
		}
	}

	// Go through and complete loading anything that's already in memory, this may call the callback right away
	for (int32 i = 0; i < TargetsToStream.Num(); i++)
	{
		FStreamable* Existing = ExistingStreamables[i];

		if (Existing && Existing->Target)
		{
			CheckCompletedRequests(TargetsToStream[i], Existing);
		}
	}
}
void URuntimeMeshLibrary::CalculateTangentsForMesh(const TArray<FVector>& Vertices, const TArray<int32>& Triangles, TArray<FVector>& Normals, 
	const TArray<FVector2D>& UVs, TArray<FRuntimeMeshTangent>& Tangents, bool bCreateSmoothNormals)
{
	Normals.SetNum(Vertices.Num());
	Tangents.SetNum(Vertices.Num());
	CalculateTangentsForMesh(
		[&Triangles](int32 Index) -> int32 { return Triangles[Index]; },
		[&Vertices](int32 Index) -> FVector { return Vertices[Index]; },
		[&UVs](int32 Index) -> FVector2D { return UVs[Index]; },
		[&Normals, &Tangents](int32 Index, FVector TangentX, FVector TangentY, FVector TangentZ)
		{
			Normals[Index] = TangentZ;
			Tangents[Index].TangentX = TangentX;
			Tangents[Index].bFlipTangentY = GetBasisDeterminantSign(TangentX, TangentY, TangentZ) < 0;
		},
		Vertices.Num(), UVs.Num(), Triangles.Num(), bCreateSmoothNormals);
}
bool FBuildPatchAppManifest::SaveToFile(const FString& Filename, bool bUseBinary)
{
	bool bSuccess = false;
	FArchive* FileOut = IFileManager::Get().CreateFileWriter(*Filename);
	if (FileOut)
	{
		if (bUseBinary)
		{
			Data->ManifestFileVersion = EBuildPatchAppManifestVersion::GetLatestVersion();
			FManifestWriter ManifestData;
			Serialize(ManifestData);
			ManifestData.Finalize();
			if (!ManifestData.IsError())
			{
				int32 DataSize = ManifestData.TotalSize();
				TArray<uint8> TempCompressed;
				TempCompressed.AddUninitialized(DataSize);
				int32 CompressedSize = DataSize;
				bool bDataIsCompressed = FCompression::CompressMemory(
					static_cast<ECompressionFlags>(COMPRESS_ZLIB | COMPRESS_BiasMemory),
					TempCompressed.GetData(),
					CompressedSize,
					ManifestData.GetBytes().GetData(),
					DataSize);
				TempCompressed.SetNum(CompressedSize);

				TArray<uint8>& FileData = bDataIsCompressed ? TempCompressed : ManifestData.GetBytes();

				FManifestFileHeader Header;
				*FileOut << Header;
				Header.HeaderSize = FileOut->Tell();
				Header.StoredAs = bDataIsCompressed ? EManifestFileHeader::STORED_COMPRESSED : EManifestFileHeader::STORED_RAW;
				Header.DataSize = DataSize;
				Header.CompressedSize = bDataIsCompressed ? CompressedSize : 0;
				FSHA1::HashBuffer(FileData.GetData(), FileData.Num(), Header.SHAHash.Hash);

				FileOut->Seek(0);
				*FileOut << Header;

				FileOut->Serialize(FileData.GetData(), FileData.Num());
				bSuccess = !FileOut->IsError();
			}
		}
		else
		{
			Data->ManifestFileVersion = EBuildPatchAppManifestVersion::GetLatestJsonVersion();
			FString JSONOutput;
			SerializeToJSON(JSONOutput);
			FTCHARToUTF8 JsonUTF8(*JSONOutput);
			FileOut->Serialize((UTF8CHAR*)JsonUTF8.Get(), JsonUTF8.Length() * sizeof(UTF8CHAR));
		}
		FileOut->Close();
		delete FileOut;
		FileOut = nullptr;
	}

	return bSuccess;
}
TArray<int32> URuntimeMeshLibrary::GenerateTessellationIndexBuffer(const TArray<FVector>& Vertices, const TArray<int32>& Triangles, TArray<FVector>& Normals, const TArray<FVector2D>& UVs, TArray<FRuntimeMeshTangent>& Tangents)
{
	TArray<int32> TessellationTriangles;
	FTessellationUtilities::CalculateTessellationIndices(Vertices.Num(), Triangles.Num(),
		[&Vertices](int32 Index) -> FVector { return Vertices[Index]; },
		[&UVs](int32 Index) -> FVector2D { return UVs.Num() > Index ? UVs[Index] : FVector2D::ZeroVector; },
		[&Triangles](int32 Index) -> int32 { return Triangles[Index]; },
		[&TessellationTriangles](int32 NewSize) { TessellationTriangles.SetNum(NewSize); },
		[&TessellationTriangles]() -> int32 { return TessellationTriangles.Num(); },
		[&TessellationTriangles](int32 Index, int32 NewValue) { TessellationTriangles[Index] = NewValue; },
		[&TessellationTriangles](int32 Index) -> int32 { return TessellationTriangles[Index]; });
	return TessellationTriangles;
}
TArray<int32> URuntimeMeshLibrary::GenerateTessellationIndexBufferPacked(const TArray<FRuntimeMeshBlueprintVertexSimple>& Vertices, const TArray<int32>& Triangles)
{
	TArray<int32> TessellationTriangles;
	FTessellationUtilities::CalculateTessellationIndices(Vertices.Num(), Triangles.Num(),
		[&Vertices](int32 Index) -> FVector { return Vertices[Index].Position; },
		[&Vertices](int32 Index) -> FVector2D { return Vertices[Index].UV0; },
		[&Triangles](int32 Index) -> int32 { return Triangles[Index]; },
		[&TessellationTriangles](int32 NewSize) { TessellationTriangles.SetNum(NewSize); },
		[&TessellationTriangles]() -> int32 { return TessellationTriangles.Num(); },
		[&TessellationTriangles](int32 Index, int32 NewValue) { TessellationTriangles[Index] = NewValue; },
		[&TessellationTriangles](int32 Index) -> int32 { return TessellationTriangles[Index]; });
	return TessellationTriangles;
}
TArray<int32> URuntimeMeshLibrary::GenerateTessellationIndexBuffer(const TSharedPtr<FRuntimeMeshAccessor>& MeshAccessor)
{
	TArray<int32> TessellationTriangles;
	FTessellationUtilities::CalculateTessellationIndices(MeshAccessor->NumVertices(), MeshAccessor->NumIndices(),
		[&MeshAccessor](int32 Index) -> FVector { return MeshAccessor->GetPosition(Index); },
		[&MeshAccessor](int32 Index) -> FVector2D { return MeshAccessor->GetUV(Index); },
		[&MeshAccessor](int32 Index) -> int32 { return MeshAccessor->GetIndex(Index); },
		[&TessellationTriangles](int32 NewSize) { TessellationTriangles.SetNum(NewSize); },
		[&TessellationTriangles]() -> int32 { return TessellationTriangles.Num(); },
		[&TessellationTriangles](int32 Index, int32 NewValue) { TessellationTriangles[Index] = NewValue; },
		[&TessellationTriangles](int32 Index) -> int32 { return TessellationTriangles[Index]; });
	return TessellationTriangles;
}
Example #10
0
FString FHttpResponseWinInet::QueryHeaderString(uint32 HttpQueryInfoLevel, const FString& HeaderName) const
{
	// try to use stack allocation where possible.
	::DWORD HeaderSize = 0;
	TCHAR HeaderValue[128];
	TArray<TCHAR> HeaderValueLong;
	TCHAR* HeaderValueReal = HeaderValue;
	if (!HttpQueryInfo(Request.RequestHandle, HttpQueryInfoLevel, const_cast<TCHAR*>(*HeaderName), &HeaderSize, NULL))
	{
		uint32 ErrorCode = GetLastError();
		if (ErrorCode == ERROR_HTTP_HEADER_NOT_FOUND)
		{
			return FString();
		}
		else if (ErrorCode == ERROR_INSUFFICIENT_BUFFER)
		{
			// make sure we have enough room to supply the HeaderName and Value. If not, dynamically allocate.
			uint32 HeaderSizeChars = HeaderSize / sizeof(TCHAR) + 1;
			uint32 HeaderNameChars = HeaderName.Len() == 0 ? 0 : HeaderName.Len() + 1;
			if (HeaderSizeChars > ARRAYSIZE(HeaderValue) || HeaderNameChars > ARRAYSIZE(HeaderValue))
			{
				// we have to create a dynamic allocation to hold the result.
				UE_LOG(LogHttp, Verbose, TEXT("Having to resize default buffer for retrieving header %s. Name length: %u. Value length: %u. %p"), 
					*HeaderName, HeaderNameChars, HeaderSizeChars, &Request);
				uint32 NewBufferSizeChars = FMath::Max(HeaderSizeChars, HeaderNameChars);
				// Have to copy the HeaderName into the buffer as well for the API to work.
				if (HeaderName.Len() > 0)
				{
					HeaderValueLong = HeaderName.GetCharArray();
				}
				// Set the size of the array to hold the entire value.
				HeaderValueLong.SetNum(NewBufferSizeChars);
				HeaderSize = NewBufferSizeChars * sizeof(TCHAR);
				HeaderValueReal = HeaderValueLong.GetData();
			}
			else
			{
				// Use the stack allocated space if we have the room.
				FMemory::Memcpy(HeaderValue, *HeaderName, HeaderName.Len()*sizeof(TCHAR));
				HeaderValue[HeaderName.Len()] = 0;
			}
			if (!HttpQueryInfo(Request.RequestHandle, HttpQueryInfoLevel, HeaderValueReal, &HeaderSize, NULL))
			{
				UE_LOG(LogHttp, Warning, TEXT("HttpQueryInfo failed trying to get Header Value for Name %s: %s. %p"), 
					*HeaderName, *InternetTranslateError(GetLastError()), &Request);
				return FString();
			}
		}
	}
	return FString(HeaderValueReal);
}
Example #11
0
void SSpineWidget::Flush(int32 LayerId, FSlateWindowElementList& OutDrawElements, const FGeometry& AllottedGeometry, int &Idx, TArray<FVector> &Vertices, TArray<int32> &Indices, TArray<FVector2D> &Uvs, TArray<FColor> &Colors, TArray<FVector>& Colors2, UMaterialInstanceDynamic* Material) {
	if (Vertices.Num() == 0) return;
	SSpineWidget* self = (SSpineWidget*)this;

	self->renderData.IndexData.SetNumUninitialized(Indices.Num());
	uint32* indexData = (uint32*)renderData.IndexData.GetData();
	memcpy(indexData, Indices.GetData(), sizeof(uint32) * Indices.Num());

	self->renderData.VertexData.SetNumUninitialized(Vertices.Num());
	FSlateVertex* vertexData = (FSlateVertex*)renderData.VertexData.GetData();
	FVector2D offset = AllottedGeometry.AbsolutePosition;
	FColor white = FColor(0xffffffff);

	float width = AllottedGeometry.GetAbsoluteSize().X;
	float height = AllottedGeometry.GetAbsoluteSize().Y;

	for (size_t i = 0; i < (size_t)Vertices.Num(); i++) {
		setVertex(&vertexData[i], Vertices[i].X, Vertices[i].Y, Uvs[i].X, Uvs[i].Y, Colors[i], offset);
	}

	/*FSlateBrush brush;
	brush.SetResourceObject(Material);
	brush = widget->Brush;

	FSlateShaderResourceProxy* shaderResource = FSlateDataPayload::ResourceManager->GetShaderResource(brush);
	if (shaderResource) {
		FSlateResourceHandle resourceHandle = FSlateApplication::Get().GetRenderer()->GetResourceHandle(brush);
		FSlateDrawElement::MakeCustomVerts(OutDrawElements, LayerId, resourceHandle, renderData.VertexData, renderData.IndexData, nullptr, 0, 0);
	}*/

	Vertices.SetNum(0);
	Indices.SetNum(0);
	Uvs.SetNum(0);
	Colors.SetNum(0);
	Colors2.SetNum(0);
	Idx++;
}
void URuntimeMeshLibrary::GetStaticMeshSection(UStaticMesh* InMesh, int32 LODIndex, int32 SectionIndex, TArray<FVector>& Vertices, TArray<int32>& Triangles,
	TArray<FVector>& Normals, TArray<FVector2D>& UVs, TArray<FColor>& Colors, TArray<FRuntimeMeshTangent>& Tangents)
{
	Vertices.Empty();
	Triangles.Empty();
	Normals.Empty();
	UVs.Empty();
	Colors.Empty();
	Tangents.Empty();

	GetStaticMeshSection(InMesh, LODIndex, SectionIndex, 1,
		[&Vertices, &Normals, &Tangents](FVector Position, FVector TangentX, FVector TangentY, FVector TangentZ) -> int32
		{
			int32 NewIndex = Vertices.Add(Position);
			Normals.Add(TangentZ);
			Tangents.Add(FRuntimeMeshTangent(TangentX, GetBasisDeterminantSign(TangentX, TangentY, TangentZ) < 0));
			return NewIndex;
		},
		[&UVs](int32 Index, int32 UVIndex, FVector2D UV)
		{
			check(UVIndex == 0);
			UVs.SetNum(Index + 1);
			UVs[Index] = UV;
		},
		[&Colors](int32 Index, FColor Color)
		{
			Colors.SetNum(Index + 1);
			Colors[Index] = Color;
		},
		[&Triangles](int32 Index)
		{
			Triangles.Add(Index);
		},
		[](int32 Index)
		{
		});
}
void URuntimeMeshLibrary::CopyStaticMeshToRuntimeMesh(UStaticMeshComponent* StaticMeshComponent, int32 LODIndex, URuntimeMesh* RuntimeMesh, bool bCreateCollision)
{
	SCOPE_CYCLE_COUNTER(STAT_RuntimeMeshLibrary_CopyStaticMeshToRuntimeMesh);
	if (StaticMeshComponent != nullptr &&
		StaticMeshComponent->GetStaticMesh() != nullptr &&
		RuntimeMesh != nullptr)
	{
		UStaticMesh* StaticMesh = StaticMeshComponent->GetStaticMesh();

		RuntimeMesh->ClearAllMeshSections();

		//// MESH DATA

		int32 NumSections = StaticMesh->GetNumSections(LODIndex);
		for (int32 SectionIndex = 0; SectionIndex < NumSections; SectionIndex++)
		{
			// Buffers for copying geom data
			TSharedPtr<FRuntimeMeshBuilder> MeshData = MakeRuntimeMeshBuilder<FRuntimeMeshTangents, FVector2DHalf, uint32>();
			TArray<uint8> AdjacencyTrianglesData;
			TSharedPtr<FRuntimeMeshIndicesAccessor> AdjacencyTrianglesAccessor = MakeShared<FRuntimeMeshIndicesAccessor>(true, &AdjacencyTrianglesData);
			TArray<uint32> AdjacencyTriangles;
			AdjacencyTriangles.SetNum(AdjacencyTrianglesData.Num() / 4);
			FMemory::Memcpy(AdjacencyTriangles.GetData(), AdjacencyTrianglesData.GetData(), AdjacencyTrianglesData.Num());


			// TODO: Make this smarter to setup a mesh section to match the static mesh vertex configuration
			// This will let it pick up the additional UVs or high pri normals/tangents/uvs

			// Get geom data from static mesh
			GetStaticMeshSection(StaticMesh, LODIndex, SectionIndex, MeshData, AdjacencyTrianglesAccessor);

			// Create RuntimeMesh
			RuntimeMesh->CreateMeshSection(SectionIndex, MeshData, bCreateCollision);
			RuntimeMesh->SetSectionTessellationTriangles(SectionIndex, AdjacencyTriangles);
		}

		//// SIMPLE COLLISION
		CopyCollisionFromStaticMesh(StaticMesh, RuntimeMesh);


		//// MATERIALS

		for (int32 MatIndex = 0; MatIndex < StaticMeshComponent->GetNumMaterials(); MatIndex++)
		{
			RuntimeMesh->SetSectionMaterial(MatIndex, StaticMeshComponent->GetMaterial(MatIndex));
		}
	}
}
	bool ResamplePCM(uint32 NumChannels, const TArray<uint8>& InBuffer, uint32 InSampleRate, TArray<uint8>& OutBuffer, uint32 OutSampleRate) const
	{
		// Initialize resampler to convert to desired rate for Opus
		int32 err = 0;
		SpeexResamplerState* resampler = speex_resampler_init(NumChannels, InSampleRate, OutSampleRate, SPEEX_RESAMPLER_QUALITY_DESKTOP, &err);
		if (err != RESAMPLER_ERR_SUCCESS)
		{
			speex_resampler_destroy(resampler);
			return false;
		}

		// Calculate extra space required for sample rate
		const uint32 SampleStride = SAMPLE_SIZE * NumChannels;
		const float Duration = (float)InBuffer.Num() / (InSampleRate * SampleStride);
		const int32 SafeCopySize = (Duration + 1) * OutSampleRate * SampleStride;
		OutBuffer.Empty(SafeCopySize);
		OutBuffer.AddUninitialized(SafeCopySize);
		uint32 InSamples = InBuffer.Num() / SampleStride;
		uint32 OutSamples = OutBuffer.Num() / SampleStride;

		// Do resampling and check results
		if (NumChannels == 1)
		{
			err = speex_resampler_process_int(resampler, 0, (const short*)(InBuffer.GetData()), &InSamples, (short*)(OutBuffer.GetData()), &OutSamples);
		}
		else
		{
			err = speex_resampler_process_interleaved_int(resampler, (const short*)(InBuffer.GetData()), &InSamples, (short*)(OutBuffer.GetData()), &OutSamples);
		}

		speex_resampler_destroy(resampler);
		if (err != RESAMPLER_ERR_SUCCESS)
		{
			return false;
		}

		// reduce the size of Out Buffer if more space than necessary was allocated
		const int32 WrittenBytes = (int32)(OutSamples * SampleStride);
		if (WrittenBytes < OutBuffer.Num())
		{
			OutBuffer.SetNum(WrittenBytes, true);
		}

		return true;
	}
 FConstructorStatics()
 {
     VisemeNames.SetNum(ovrLipSyncViseme::VisemesCount);
     VisemeNames[ovrLipSyncViseme::sil] = "sil";
     VisemeNames[ovrLipSyncViseme::PP] = "PP";
     VisemeNames[ovrLipSyncViseme::FF] = "FF";
     VisemeNames[ovrLipSyncViseme::TH] = "TH";
     VisemeNames[ovrLipSyncViseme::DD] = "DD";
     VisemeNames[ovrLipSyncViseme::kk] = "kk";
     VisemeNames[ovrLipSyncViseme::CH] = "CH";
     VisemeNames[ovrLipSyncViseme::SS] = "SS";
     VisemeNames[ovrLipSyncViseme::nn] = "nn";
     VisemeNames[ovrLipSyncViseme::RR] = "RR";
     VisemeNames[ovrLipSyncViseme::aa] = "aa";
     VisemeNames[ovrLipSyncViseme::E] = "E";
     VisemeNames[ovrLipSyncViseme::ih] = "ih";
     VisemeNames[ovrLipSyncViseme::oh] = "oh";
     VisemeNames[ovrLipSyncViseme::ou] = "ou";
 }
TArray<float> UTensorFlowBlueprintLibrary::Conv_Texture2DToFloatArray(UTexture2D* InTexture)
{
	TArray<float> FloatArray;
	FloatArray.SetNum(InTexture->GetSizeX()* InTexture->GetSizeY());

	// Lock the texture so it can be read
	uint8* MipData = static_cast<uint8*>(InTexture->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_ONLY));

	for (int i = 0; i < FloatArray.Num(); i++)
	{
		int MipPointer = i * 4;
		float GreyscaleValue = (MipData[MipPointer] + MipData[MipPointer + 1] + MipData[MipPointer + 2]) / 3.f;
		FloatArray[i] = 1 - (GreyscaleValue / 255.f);	//inverse and normalize it
	}

	// Unlock the texture
	InTexture->PlatformData->Mips[0].BulkData.Unlock();
	//InTexture->UpdateResource();

	return FloatArray;
}
FString UMasterServerFunctions::DecompressBytes(TArray<uint8> CompressedBinaryArray)
{
	TArray<uint8> UncompressedBinaryArray;
	UncompressedBinaryArray.SetNum(CompressedBinaryArray.Num() * 1032);

	//int ret;
	z_stream strm;
	strm.zalloc = Z_NULL;
	strm.zfree = Z_NULL;
	strm.opaque = Z_NULL;

	strm.avail_in = CompressedBinaryArray.Num();
	strm.next_in = (Bytef *)CompressedBinaryArray.GetData();
	strm.avail_out = UncompressedBinaryArray.Num();
	strm.next_out = (Bytef *)UncompressedBinaryArray.GetData();

	// the actual DE-compression work.
	inflateInit(&strm);
	inflate(&strm, Z_FINISH);
	inflateEnd(&strm);

	return BinaryArrayToFString(UncompressedBinaryArray);
}
bool FWindowsPlatformProcess::ReadPipeToArray(void* ReadPipe, TArray<uint8> & Output)
{
	uint32 BytesAvailable = 0;
	if (::PeekNamedPipe(ReadPipe, NULL, 0, NULL, (::DWORD*)&BytesAvailable, NULL) && (BytesAvailable > 0))
	{
		Output.SetNumUninitialized(BytesAvailable);
		uint32 BytesRead = 0;
		if (::ReadFile(ReadPipe, Output.GetData(), BytesAvailable, (::DWORD*)&BytesRead, NULL))
		{
			if (BytesRead < BytesAvailable)
			{
				Output.SetNum(BytesRead);
			}

			return true;
		}
		else
		{
			Output.Empty();
		}
	}

	return false;
}
void FTextLocalizationManager::RegenerateResources( const FString& ConfigFilePath, IInternationalizationArchiveSerializer& ArchiveSerializer, IInternationalizationManifestSerializer& ManifestSerializer )
{
	// Add one to the revision index, so all FText's refresh.
	++HeadCultureRevisionIndex;
	
	FInternationalization& I18N = FInternationalization::Get();

	FString SectionName = TEXT("RegenerateResources");

	// Get source path.
	FString SourcePath;
	if( !( GConfig->GetString( *SectionName, TEXT("SourcePath"), SourcePath, ConfigFilePath ) ) )
	{
		UE_LOG(LogTextLocalizationManager, Error, TEXT("No source path specified."));
		return;
	}

	// Get destination path.
	FString DestinationPath;
	if( !( GConfig->GetString( *SectionName, TEXT("DestinationPath"), DestinationPath, ConfigFilePath ) ) )
	{
		UE_LOG(LogTextLocalizationManager, Error, TEXT("No destination path specified."));
		return;
	}

	// Get manifest name.
	FString ManifestName;
	if( !( GConfig->GetString( *SectionName, TEXT("ManifestName"), ManifestName, ConfigFilePath ) ) )
	{
		UE_LOG(LogTextLocalizationManager, Error, TEXT("No manifest name specified."));
		return;
	}

	// Get resource name.
	FString ResourceName;
	if( !( GConfig->GetString( *SectionName, TEXT("ResourceName"), ResourceName, ConfigFilePath ) ) )
	{
		UE_LOG(LogTextLocalizationManager, Error, TEXT("No resource name specified."));
		return;
	}

	TArray<FString> LocaleNames;
	{
		const FString CultureName = I18N.GetCurrentCulture()->GetName();
		LocaleNames.Add(CultureName);
		const FString BaseLanguageName = I18N.GetCurrentCulture()->GetTwoLetterISOLanguageName();
		if(BaseLanguageName != CultureName)
		{
			LocaleNames.Add(BaseLanguageName);
		}
	}

	// Source path needs to be relative to Engine or Game directory
	FString ConfigFullPath = FPaths::ConvertRelativePathToFull(ConfigFilePath);
	FString EngineFullPath = FPaths::ConvertRelativePathToFull(FPaths::EngineConfigDir());
	bool IsEngineManifest = false;
	
	if (ConfigFullPath.StartsWith(EngineFullPath))
	{
		IsEngineManifest = true;
	}

	if (IsEngineManifest)
	{
		SourcePath = FPaths::Combine(*(FPaths::EngineDir()), *SourcePath);
		DestinationPath = FPaths::Combine(*(FPaths::EngineDir()), *DestinationPath);
	}
	else
	{
		SourcePath = FPaths::Combine(*(FPaths::GameDir()), *SourcePath);
		DestinationPath = FPaths::Combine(*(FPaths::GameDir()), *DestinationPath);
	}

	TArray<TArray<uint8>> BackingBuffers;
	BackingBuffers.SetNum(LocaleNames.Num());

	for(int32 i = 0; i < BackingBuffers.Num(); ++i)
	{
		TArray<uint8>& BackingBuffer = BackingBuffers[i];
		FMemoryWriter MemoryWriter(BackingBuffer, true);

		// Read the manifest file from the source path.
		FString ManifestFilePath = (SourcePath / ManifestName);
		ManifestFilePath = FPaths::ConvertRelativePathToFull(ManifestFilePath);
		TSharedRef<FInternationalizationManifest> InternationalizationManifest = MakeShareable(new FInternationalizationManifest);

#if 0 // @todo Json: Serializing from FArchive is currently broken
		FArchive* ManifestFile = IFileManager::Get().CreateFileReader(*ManifestFilePath);

		if (ManifestFile == nullptr)
		{
			UE_LOG(LogTextLocalizationManager, Error, TEXT("No manifest found at %s."), *ManifestFilePath);
			return;
		}

		ManifestSerializer.DeserializeManifest(*ManifestFile, InternationalizationManifest);
#else
		FString ManifestContent;

		if (!FFileHelper::LoadFileToString(ManifestContent, *ManifestFilePath))
		{
			UE_LOG(LogTextLocalizationManager, Error, TEXT("Failed to load file %s."), *ManifestFilePath);
			continue;
		}

		ManifestSerializer.DeserializeManifest(ManifestContent, InternationalizationManifest);
#endif

		// Write resource.
		FTextLocalizationResourceGenerator::Generate(SourcePath, InternationalizationManifest, LocaleNames[i], &(MemoryWriter), ArchiveSerializer);

		MemoryWriter.Close();
	}

	// Prioritized array of localization entry trackers.
	TArray<FLocalizationEntryTracker> LocalizationEntryTrackers;
	for(int32 i = 0; i < BackingBuffers.Num(); ++i)
	{
		TArray<uint8>& BackingBuffer = BackingBuffers[i];
		FMemoryReader MemoryReader(BackingBuffer, true);
		const FString CulturePath = DestinationPath / LocaleNames[i];
		const FString ResourceFilePath = FPaths::ConvertRelativePathToFull(CulturePath / ResourceName);

		FLocalizationEntryTracker& CultureTracker = LocalizationEntryTrackers[LocalizationEntryTrackers.Add(FLocalizationEntryTracker())];
		CultureTracker.ReadFromArchive(MemoryReader, ResourceFilePath);
		CultureTracker.ReportCollisions();

		MemoryReader.Close();
	}

	// Don't filter updates by table name, or we can't live preview strings that had no translation originally
	UpdateLiveTable(LocalizationEntryTrackers);
}
Example #20
0
void UKUIInterfaceElement::SendEvent( FKUIInterfaceEvent& stEventInfo )
{
	if ( IsTemplate() )
		return;

	static TArray<std::function<void( UKUIInterfaceElement*, FKUIInterfaceEvent& )>> arDispatchers;

	if ( arDispatchers.Num() == 0 )
	{
		arDispatchers.SetNum( KUI_BASE_EVENT_LAST - KUI_BASE_EVENT_FIRST + 1 );

		// Can't use UStruct pointers... so this.
#pragma warning( disable : 4946 )

		arDispatchers[ EKUIInterfaceElementEventList::E_Initialize - KUI_BASE_EVENT_FIRST ] =
			[] ( UKUIInterfaceElement* oElement, FKUIInterfaceEvent& stEventInfo )
		{
			oElement->OnInitialize( *reinterpret_cast< FKUIInterfaceElementContainerEvent* >( &stEventInfo ) );
			oElement->OnInitializeBP( *reinterpret_cast< FKUIInterfaceElementContainerEvent* >( &stEventInfo ) );
		};

		arDispatchers[ EKUIInterfaceElementEventList::E_AddedToContainer - KUI_BASE_EVENT_FIRST ] =
			[] ( UKUIInterfaceElement* oElement, FKUIInterfaceEvent& stEventInfo )
		{
			oElement->OnAddedToContainer( *reinterpret_cast<FKUIInterfaceElementContainerEvent*>( &stEventInfo ) );
			oElement->OnAddedToContainerBP( *reinterpret_cast<FKUIInterfaceElementContainerEvent*>( &stEventInfo ) );
		};

		arDispatchers[ EKUIInterfaceElementEventList::E_RemovedFromContainer - KUI_BASE_EVENT_FIRST ] = 
			[] ( UKUIInterfaceElement* oElement, FKUIInterfaceEvent& stEventInfo )
		{
			oElement->OnRemovedFromContainer( *reinterpret_cast<FKUIInterfaceElementContainerEvent*>( &stEventInfo ) );
			oElement->OnRemovedFromContainerBP( *reinterpret_cast<FKUIInterfaceElementContainerEvent*>( &stEventInfo ) );
		};

		arDispatchers[ EKUIInterfaceElementEventList::E_Render - KUI_BASE_EVENT_FIRST ] = 
			[] ( UKUIInterfaceElement* oElement, FKUIInterfaceEvent& stEventInfo )
		{
			oElement->OnRender( *reinterpret_cast<FKUIInterfaceElementRenderEvent*>( &stEventInfo ) );
			oElement->OnRenderBP( *reinterpret_cast<FKUIInterfaceElementRenderEvent*>( &stEventInfo ) );
		};

		arDispatchers[ EKUIInterfaceElementEventList::E_AlignLocationCalculated - KUI_BASE_EVENT_FIRST ] = 
			[] ( UKUIInterfaceElement* oElement, FKUIInterfaceEvent& stEventInfo )
		{
			oElement->OnAlignmentLocationCalculated( stEventInfo );
			oElement->OnAlignmentLocationCalculatedBP( stEventInfo );
		};

		arDispatchers[ EKUIInterfaceElementEventList::E_AlignLocationInvalidated - KUI_BASE_EVENT_FIRST ] = 
			[] ( UKUIInterfaceElement* oElement, FKUIInterfaceEvent& stEventInfo )
		{
			oElement->OnAlignLocationInvalidated( stEventInfo );
			oElement->OnAlignLocationInvalidatedBP( stEventInfo );
		};

		arDispatchers[ EKUIInterfaceElementEventList::E_LocationChange - KUI_BASE_EVENT_FIRST ] = 
			[] ( UKUIInterfaceElement* oElement, FKUIInterfaceEvent& stEventInfo )
		{
			oElement->OnLocationChange( *reinterpret_cast<FKUIInterfaceContainerLocationChangeEvent*>( &stEventInfo ) );
			oElement->OnLocationChangeBP( *reinterpret_cast<FKUIInterfaceContainerLocationChangeEvent*>( &stEventInfo ) );
		};

		arDispatchers[ EKUIInterfaceElementEventList::E_SizeChange - KUI_BASE_EVENT_FIRST ] = 
			[] ( UKUIInterfaceElement* oElement, FKUIInterfaceEvent& stEventInfo )
		{
			oElement->OnSizeChange( *reinterpret_cast<FKUIInterfaceContainerSizeChangeEvent*>( &stEventInfo ) );
			oElement->OnSizeChangeBP( *reinterpret_cast<FKUIInterfaceContainerSizeChangeEvent*>( &stEventInfo ) );
		};

#pragma warning( default : 4946 )

	}

	if ( stEventInfo.iEventID >= KUI_BASE_EVENT_FIRST && stEventInfo.iEventID <= KUI_BASE_EVENT_LAST )
		arDispatchers[ stEventInfo.iEventID - KUI_BASE_EVENT_FIRST ]( this, stEventInfo );
}
Example #21
0
ERet FxUtil_LoadShaderLibrary( AStreamReader& stream, Clump &clump, const Resolution& screen )
{
	FxLibraryHeader_d	libraryHeader;
	mxDO(stream.Get(libraryHeader));

	// Load shader library structures.

#if mxUSE_BINARY_EFFECT_FILE_FORMAT
	UNDONE;
	//mxTRY(Serialization::LoadClumpImage(stream, clump));
#else

	ByteBuffer32	buffer;
	buffer.SetNum(libraryHeader.runtimeSize);
	stream.Read(buffer.ToPtr(), buffer.Num());

	SON::Parser		parser;
	parser.buffer = (char*)buffer.ToPtr();
	parser.length = libraryHeader.runtimeSize;
	parser.line = 1;
	parser.file = "";

	SON::Allocator	allocator;
	SON::Node* root = SON::ParseBuffer(parser, allocator);
	chkRET_X_IF_NIL(root, ERR_FAILED_TO_PARSE_DATA);

	mxTRY(SON::LoadClump( root, clump ));
#endif

	// Initialization order:
	// 1) Render targets
	// 2) State objects
	// 3) Shaders
	// 4) Input layouts
	// 5) Everything else

	// render targets should be sorted by size
	// shader resources should be sorted by size
	// constant buffers should be sorted by size

	CreateRenderTargets(screen, clump, false);

	// Ideally, render states should be sorted by state deltas (so that changes between adjacent states are minimized).

	{
		TObjectIterator< FxSamplerState >	samplerStateIt( clump );
		while( samplerStateIt.IsValid() )
		{
			FxSamplerState& samplerState = samplerStateIt.Value();
			samplerState.handle = llgl::CreateSamplerState( samplerState );
			samplerStateIt.MoveToNext();
		}
	}
	{
		TObjectIterator< FxDepthStencilState >	depthStencilStateIt( clump );
		while( depthStencilStateIt.IsValid() )
		{
			FxDepthStencilState& depthStencilState = depthStencilStateIt.Value();
			depthStencilState.handle = llgl::CreateDepthStencilState( depthStencilState );
			depthStencilStateIt.MoveToNext();
		}
	}
	{
		TObjectIterator< FxRasterizerState >	rasterizerStateIt( clump );
		while( rasterizerStateIt.IsValid() )
		{
			FxRasterizerState& rasterizerState = rasterizerStateIt.Value();
			rasterizerState.handle = llgl::CreateRasterizerState( rasterizerState );
			rasterizerStateIt.MoveToNext();
		}
	}
	{
		TObjectIterator< FxBlendState >	blendStateIt( clump );
		while( blendStateIt.IsValid() )
		{
			FxBlendState& blendState = blendStateIt.Value();
			blendState.handle = llgl::CreateBlendState( blendState );
			blendStateIt.MoveToNext();
		}
	}

	FxRenderResources* renderStates = FindSingleInstance<FxRenderResources>(clump);
	if(renderStates)
	{
		for( UINT32 iStateBlock = 0; iStateBlock < renderStates->state_blocks.Num(); iStateBlock++ )
		{
			FxStateBlock* stateBlock = renderStates->state_blocks[ iStateBlock ];
			stateBlock->blendState		= renderStates->blend_states[ stateBlock->blendState.id ]->handle;
			stateBlock->rasterizerState	= renderStates->rasterizer_states[ stateBlock->rasterizerState.id ]->handle;
			stateBlock->depthStencilState= renderStates->depth_stencil_states[ stateBlock->depthStencilState.id ]->handle;
		}
	}

	// Create constant buffers and shader resources.
	{
		TObjectIterator< FxCBuffer >	cbufferIt( clump );
		while( cbufferIt.IsValid() )
		{
			FxCBuffer& ubo = cbufferIt.Value();
			ubo.handle = llgl::CreateBuffer( Buffer_Uniform, ubo.size, NULL );
			cbufferIt.MoveToNext();
		}
	}

	CacheHeader_d	cacheHeader;
	mxDO(stream.Get(cacheHeader));

	// Create shaders.
	FxShaderHandles	shaders;
	ScopedStackAlloc	tempAlloc( gCore.frameAlloc );
	for( UINT32 shaderType = 0; shaderType < ShaderTypeCount; shaderType++ )
	{
		const UINT32 shaderCount = cacheHeader.numShaders[shaderType];
		if( shaderCount ) {
			HShader* shaderHandlesStorage = tempAlloc.AllocMany< HShader >( shaderCount );
			shaders.handles[shaderType].SetExternalStorage( shaderHandlesStorage, shaderCount );
			shaders.handles[shaderType].SetNum( shaderCount );
		}
	}
	mxDO(ShaderCache_d::CreateShaders( cacheHeader, stream, shaders ));

	// Create programs.
	TArray< HProgram >	programHandles;
	{
		const UINT32 programsCount = cacheHeader.numPrograms;
		HProgram* programHandlesStorage = tempAlloc.AllocMany< HProgram >( programsCount );
		programHandles.SetExternalStorage( programHandlesStorage, programsCount );
		programHandles.SetNum( programsCount );

		ScopedStackAlloc	programAlloc( gCore.frameAlloc );
		char *	tempBuffer = programAlloc.Alloc( cacheHeader.bufferSize );
		ByteArrayT	programBlob( tempBuffer, cacheHeader.bufferSize );

		for( UINT32 programIndex = 0; programIndex < programsCount; programIndex++ )
		{
			stream >> programBlob;

			CachedProgram_d *	program;
			mxDO(Serialization::LoadInPlace( programBlob.ToPtr(), programBlob.Num(), program ));

			HShader* shaderIds = program->pd.shaders;
			for( UINT32 shaderType = 0; shaderType < ShaderTypeCount; shaderType++ )
			{
				const UINT16 shaderIndex = shaderIds[shaderType].id;
				if( shaderIndex != (UINT16)~0 ) {
					shaderIds[shaderType] = shaders.handles[shaderType][shaderIndex];
				}
			}

			const HProgram programHandle = llgl::CreateProgram( program->pd );
			programHandles[programIndex] = programHandle;
		}
	}

	{
		TObjectIterator< FxShader >	shaderIt( clump );
		while( shaderIt.IsValid() )
		{
			FxShader& shader = shaderIt.Value();

			for( UINT32 i = 0; i < shader.programs.Num(); i++ )
			{
				int programIndex = shader.programs[i].id;
				shader.programs[i] = programHandles[programIndex];
			}

			shaderIt.MoveToNext();
		}
	}


	return ALL_OK;
}
Example #22
0
UFlareSaveGame* UFlareSaveGameSystem::LoadGame(const FString SaveName)
{
	FLOGV("UFlareSaveGameSystem::LoadGame SaveName=%s", *SaveName);

	UFlareSaveGame *SaveGame = NULL;

	// Read the saveto a string
	FString SaveString;
	bool SaveStringLoaded = false;

	TArray<uint8> Data;

	auto LoadCompressedFileToString = [&](FString& Result, const TCHAR* Filename)
	{
		TArray<uint8> DataCompressed;
		if(!FFileHelper::LoadFileToArray(DataCompressed, Filename))
		{
			FLOGV("Fail to read save '%s'", Filename);
			return false;
		}

		int b4 = DataCompressed[DataCompressed.Num()- 4];
		int b3 = DataCompressed[DataCompressed.Num()- 3];
		int b2 = DataCompressed[DataCompressed.Num()- 2];
		int b1 = DataCompressed[DataCompressed.Num()- 1];
		int UncompressedSize = (b1 << 24) | (b2 << 16) + (b3 << 8) + b4;

		Data.SetNum(UncompressedSize + 1);

		if(!FCompression::UncompressMemory((ECompressionFlags)(COMPRESS_ZLIB), Data.GetData(), UncompressedSize, DataCompressed.GetData(), DataCompressed.Num(), false, 31))
		{
			FLOGV("Fail to uncompress save '%s' with compressed size %d and uncompressed size %d", Filename, DataCompressed.Num(), UncompressedSize);
			return false;
		}

		Data[UncompressedSize] = 0; // end string

		Result = UTF8_TO_TCHAR(Data.GetData());

		return true;
	};

	if(LoadCompressedFileToString(SaveString, *GetSaveGamePath(SaveName, true)))
	{
		FLOGV("Save '%s' read", *GetSaveGamePath(SaveName, true));
		SaveStringLoaded  = true;
	}
	else if(FFileHelper::LoadFileToString(SaveString, *GetSaveGamePath(SaveName, false)))
	{
		FLOGV("Save '%s' read", *GetSaveGamePath(SaveName, false));
		SaveStringLoaded = true;
	}

	if(SaveStringLoaded)
	{
		// Deserialize a JSON object from the string
		TSharedPtr< FJsonObject > Object;
		TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(SaveString);
		if(FJsonSerializer::Deserialize(Reader, Object) && Object.IsValid())
		{
			UFlareSaveReaderV1* SaveReader = NewObject<UFlareSaveReaderV1>(this, UFlareSaveReaderV1::StaticClass());
			SaveGame = SaveReader->LoadGame(Object);
		}
		else
		{
			FLOGV("Fail to deserialize save '%s' (len: %d)", *GetSaveGamePath(SaveName, false), SaveString.Len());
		}
	}
	else
	{
		FLOGV("Fail to read save '%s' or '%s'", *GetSaveGamePath(SaveName, true), *GetSaveGamePath(SaveName, false));

	}

	return SaveGame;
}
void UEnvQueryTest_PathfindingBatch::RunTest(FEnvQueryInstance& QueryInstance) const
{
	UObject* QueryOwner = QueryInstance.Owner.Get();
	BoolValue.BindData(QueryOwner, QueryInstance.QueryID);
	PathFromContext.BindData(QueryOwner, QueryInstance.QueryID);
	SkipUnreachable.BindData(QueryOwner, QueryInstance.QueryID);
	FloatValueMin.BindData(QueryOwner, QueryInstance.QueryID);
	FloatValueMax.BindData(QueryOwner, QueryInstance.QueryID);
	ScanRangeMultiplier.BindData(QueryOwner, QueryInstance.QueryID);

	bool bWantsPath = BoolValue.GetValue();
	bool bPathToItem = PathFromContext.GetValue();
	bool bDiscardFailed = SkipUnreachable.GetValue();
	float MinThresholdValue = FloatValueMin.GetValue();
	float MaxThresholdValue = FloatValueMax.GetValue();
	float RangeMultiplierValue = ScanRangeMultiplier.GetValue();

	UNavigationSystem* NavSys = QueryInstance.World->GetNavigationSystem();
	if (NavSys == nullptr)
	{
		return;
	}
	ANavigationData* NavData = FindNavigationData(*NavSys, QueryOwner);
	ARecastNavMesh* NavMeshData = Cast<ARecastNavMesh>(NavData);
	if (NavMeshData == nullptr)
	{
		return;
	}

	TArray<FVector> ContextLocations;
	if (!QueryInstance.PrepareContext(Context, ContextLocations))
	{
		return;
	}

	TArray<FNavigationProjectionWork> TestPoints;
	TArray<float> CollectDistanceSq;
	CollectDistanceSq.Init(0.0f, ContextLocations.Num());

	FSharedNavQueryFilter NavigationFilter = FilterClass != nullptr
		? UNavigationQueryFilter::GetQueryFilter(*NavMeshData, FilterClass)->GetCopy()
		: NavMeshData->GetDefaultQueryFilter()->GetCopy();
	NavigationFilter->SetBacktrackingEnabled(!bPathToItem);
	const dtQueryFilter* NavQueryFilter = ((const FRecastQueryFilter*)NavigationFilter->GetImplementation())->GetAsDetourQueryFilter();

	{
		// scope for perf timers

		// can't use FEnvQueryInstance::ItemIterator yet, since it has built in scoring functionality
		for (int32 ItemIdx = 0; ItemIdx < QueryInstance.Items.Num(); ItemIdx++)
		{
			if (QueryInstance.Items[ItemIdx].IsValid())
			{
				const FVector ItemLocation = GetItemLocation(QueryInstance, ItemIdx);
				TestPoints.Add(FNavigationProjectionWork(ItemLocation));

				for (int32 ContextIdx = 0; ContextIdx < ContextLocations.Num(); ContextIdx++)
				{
					const float TestDistanceSq = FVector::DistSquared(ItemLocation, ContextLocations[ContextIdx]);
					CollectDistanceSq[ContextIdx] = FMath::Max(CollectDistanceSq[ContextIdx], TestDistanceSq);
				}
			}
		}

		NavMeshData->BatchProjectPoints(TestPoints, NavMeshData->GetDefaultQueryExtent(), NavigationFilter);
	}

	TArray<FRecastDebugPathfindingData> NodePoolData;
	NodePoolData.SetNum(ContextLocations.Num());

	{
		// scope for perf timer

		TArray<NavNodeRef> Polys;
		for (int32 ContextIdx = 0; ContextIdx < ContextLocations.Num(); ContextIdx++)
		{
			const float MaxPathDistance = FMath::Sqrt(CollectDistanceSq[ContextIdx]) * RangeMultiplierValue;

			Polys.Reset();
			NodePoolData[ContextIdx].Flags = ERecastDebugPathfindingFlags::PathLength;

			NavMeshData->GetPolysWithinPathingDistance(ContextLocations[ContextIdx], MaxPathDistance, Polys, NavigationFilter, nullptr, &NodePoolData[ContextIdx]);
		}
	}

	int32 ProjectedItemIdx = 0;
	if (GetWorkOnFloatValues())
	{
		NodePoolHelpers::PathParamFunc Func[] = { nullptr, NodePoolHelpers::GetPathCost, NodePoolHelpers::GetPathLength };
		FEnvQueryInstance::ItemIterator It(this, QueryInstance);
		for (It.IgnoreTimeLimit(); It; ++It, ProjectedItemIdx++)
		{
			for (int32 ContextIndex = 0; ContextIndex < ContextLocations.Num(); ContextIndex++)
			{
				const float PathValue = Func[TestMode](NodePoolData[ContextIndex], TestPoints[ProjectedItemIdx], NavQueryFilter);
				It.SetScore(TestPurpose, FilterType, PathValue, MinThresholdValue, MaxThresholdValue);

				if (bDiscardFailed && PathValue >= BIG_NUMBER)
				{
					It.ForceItemState(EEnvItemStatus::Failed);
				}
			}
		}
	}
	else
	{
		FEnvQueryInstance::ItemIterator It(this, QueryInstance);
		for (It.IgnoreTimeLimit(); It; ++It, ProjectedItemIdx++)
		{
			for (int32 ContextIndex = 0; ContextIndex < ContextLocations.Num(); ContextIndex++)
			{
				const bool bFoundPath = NodePoolHelpers::HasPath(NodePoolData[ContextIndex], TestPoints[ProjectedItemIdx]);
				It.SetScore(TestPurpose, FilterType, bFoundPath, bWantsPath);
			}
		}
	}
}
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 UGatherTextFromAssetsCommandlet::Main(const FString& Params)
{
	// Parse command line.
	TArray<FString> Tokens;
	TArray<FString> Switches;
	TMap<FString, FString> ParamVals;
	UCommandlet::ParseCommandLine(*Params, Tokens, Switches, ParamVals);

	//Set config file
	const FString* ParamVal = ParamVals.Find(FString(TEXT("Config")));
	FString GatherTextConfigPath;

	if ( ParamVal )
	{
		GatherTextConfigPath = *ParamVal;
	}
	else
	{
		UE_LOG(LogGatherTextFromAssetsCommandlet, Error, TEXT("No config specified."));
		return -1;
	}

	//Set config section
	ParamVal = ParamVals.Find(FString(TEXT("Section")));
	FString SectionName;

	if ( ParamVal )
	{
		SectionName = *ParamVal;
	}
	else
	{
		UE_LOG(LogGatherTextFromAssetsCommandlet, Error, TEXT("No config section specified."));
		return -1;
	}

	//Modules to Preload
	TArray<FString> ModulesToPreload;
	GetStringArrayFromConfig(*SectionName, TEXT("ModulesToPreload"), ModulesToPreload, GatherTextConfigPath);

	for (const FString& ModuleName : ModulesToPreload)
	{
		FModuleManager::Get().LoadModule(*ModuleName);
	}

	// IncludePathFilters
	TArray<FString> IncludePathFilters;
	GetPathArrayFromConfig(*SectionName, TEXT("IncludePathFilters"), IncludePathFilters, GatherTextConfigPath);

	// IncludePaths (DEPRECATED)
	{
		TArray<FString> IncludePaths;
		GetPathArrayFromConfig(*SectionName, TEXT("IncludePaths"), IncludePaths, GatherTextConfigPath);
		if (IncludePaths.Num())
		{
			IncludePathFilters.Append(IncludePaths);
			UE_LOG(LogGatherTextFromAssetsCommandlet, Warning, TEXT("IncludePaths detected in section %s. IncludePaths is deprecated, please use IncludePathFilters."), *SectionName);
		}
	}

	if (IncludePathFilters.Num() == 0)
	{
		UE_LOG(LogGatherTextFromAssetsCommandlet, Error, TEXT("No include path filters in section %s."), *SectionName);
		return -1;
	}

	// ExcludePathFilters
	TArray<FString> ExcludePathFilters;
	GetPathArrayFromConfig(*SectionName, TEXT("ExcludePathFilters"), ExcludePathFilters, GatherTextConfigPath);

	// ExcludePaths (DEPRECATED)
	{
		TArray<FString> ExcludePaths;
		GetPathArrayFromConfig(*SectionName, TEXT("ExcludePaths"), ExcludePaths, GatherTextConfigPath);
		if (ExcludePaths.Num())
		{
			ExcludePathFilters.Append(ExcludePaths);
			UE_LOG(LogGatherTextFromAssetsCommandlet, Warning, TEXT("ExcludePaths detected in section %s. ExcludePaths is deprecated, please use ExcludePathFilters."), *SectionName);
		}
	}

	// PackageNameFilters
	TArray<FString> PackageFileNameFilters;
	GetStringArrayFromConfig(*SectionName, TEXT("PackageFileNameFilters"), PackageFileNameFilters, GatherTextConfigPath);

	// PackageExtensions (DEPRECATED)
	{
		TArray<FString> PackageExtensions;
		GetStringArrayFromConfig(*SectionName, TEXT("PackageExtensions"), PackageExtensions, GatherTextConfigPath);
		if (PackageExtensions.Num())
		{
			PackageFileNameFilters.Append(PackageExtensions);
			UE_LOG(LogGatherTextFromAssetsCommandlet, Warning, TEXT("PackageExtensions detected in section %s. PackageExtensions is deprecated, please use PackageFileNameFilters."), *SectionName);
		}
	}

	if (PackageFileNameFilters.Num() == 0)
	{
		UE_LOG(LogGatherTextFromAssetsCommandlet, Error, TEXT("No package file name filters in section %s."), *SectionName);
		return -1;
	}

	//asset class exclude
	TArray<FString> ExcludeClasses;
	GetStringArrayFromConfig(*SectionName, TEXT("ExcludeClasses"), ExcludeClasses, GatherTextConfigPath);

	FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
	AssetRegistryModule.Get().SearchAllAssets( true );
	FARFilter Filter;

	for(const auto& ExcludeClass : ExcludeClasses)
	{
		UClass* FilterClass = FindObject<UClass>(ANY_PACKAGE, *ExcludeClass);
		if(FilterClass)
		{
			Filter.ClassNames.Add( FilterClass->GetFName() );
		}
		else
		{
			UE_LOG(LogGatherTextFromAssetsCommandlet, Warning, TEXT("Invalid exclude class %s"), *ExcludeClass);
		}
	}

	TArray<FAssetData> AssetDataArray;
	AssetRegistryModule.Get().GetAssets(Filter, AssetDataArray);

	FString UAssetPackageExtension = FPackageName::GetAssetPackageExtension();
	TSet< FString > LongPackageNamesToExclude;
	for (int Index = 0; Index < AssetDataArray.Num(); Index++)
	{
		LongPackageNamesToExclude.Add( FPackageName::LongPackageNameToFilename( AssetDataArray[Index].PackageName.ToString(), UAssetPackageExtension ) );
	}

	//Get whether we should fix broken properties that we find.
	if (!GetBoolFromConfig(*SectionName, TEXT("bFixBroken"), bFixBroken, GatherTextConfigPath))
	{
		bFixBroken = false;
	}

	// Get whether we should gather editor-only data. Typically only useful for the localization of UE4 itself.
	if (!GetBoolFromConfig(*SectionName, TEXT("ShouldGatherFromEditorOnlyData"), ShouldGatherFromEditorOnlyData, GatherTextConfigPath))
	{
		ShouldGatherFromEditorOnlyData = false;
	}

	// Add any manifest dependencies if they were provided
	TArray<FString> ManifestDependenciesList;
	GetPathArrayFromConfig(*SectionName, TEXT("ManifestDependencies"), ManifestDependenciesList, GatherTextConfigPath);

	if( !ManifestInfo->AddManifestDependencies( ManifestDependenciesList ) )
	{
		UE_LOG(LogGatherTextFromAssetsCommandlet, Error, TEXT("The GatherTextFromAssets commandlet couldn't find all the specified manifest dependencies."));
		return -1;
	}

	//The main array of files to work from.
	TArray< FString > PackageFileNamesToProcess;

	TArray<FString> PackageFilesNotInIncludePath;
	TArray<FString> PackageFilesInExcludePath;
	TArray<FString> PackageFilesExcludedByClass;

	//Fill the list of packages to work from.
	uint8 PackageFilter = NORMALIZE_DefaultFlags;
	TArray<FString> Unused;	
	for ( int32 PackageFilenameWildcardIdx = 0; PackageFilenameWildcardIdx < PackageFileNameFilters.Num(); PackageFilenameWildcardIdx++ )
	{
		const bool IsAssetPackage = PackageFileNameFilters[PackageFilenameWildcardIdx] == ( FString( TEXT("*") )+ FPackageName::GetAssetPackageExtension() );

		TArray<FString> PackageFiles;
		if ( !NormalizePackageNames( Unused, PackageFiles, PackageFileNameFilters[PackageFilenameWildcardIdx], PackageFilter) )
		{
			UE_LOG(LogGatherTextFromAssetsCommandlet, Display, TEXT("No packages found with extension %i: '%s'"), PackageFilenameWildcardIdx, *PackageFileNameFilters[PackageFilenameWildcardIdx]);
			continue;
		}
		else
		{
			UE_LOG(LogGatherTextFromAssetsCommandlet, Display, TEXT("Found %i packages with extension %i: '%s'"), PackageFiles.Num(), PackageFilenameWildcardIdx, *PackageFileNameFilters[PackageFilenameWildcardIdx]);
		}

		//Run through all the files found and add any that pass the include, exclude and filter constraints to OrderedPackageFilesToLoad
		for (FString& PackageFile : PackageFiles)
		{
			PackageFile = FPaths::ConvertRelativePathToFull(PackageFile);

			bool bExclude = false;
			//Ensure it matches the include paths if there are some.
			for (FString& IncludePath : IncludePathFilters)
			{
				bExclude = true;
				if( PackageFile.MatchesWildcard(IncludePath) )
				{
					bExclude = false;
					break;
				}
			}

			if ( bExclude )
			{
				PackageFilesNotInIncludePath.Add(PackageFile);
			}

			//Ensure it does not match the exclude paths if there are some.
			for (const FString& ExcludePath : ExcludePathFilters)
			{
				if (PackageFile.MatchesWildcard(ExcludePath))
				{
					bExclude = true;
					PackageFilesInExcludePath.Add(PackageFile);
					break;
				}
			}

			//Check that this is not on the list of packages that we don't care about e.g. textures.
			if ( !bExclude && IsAssetPackage && LongPackageNamesToExclude.Contains( PackageFile ) )
			{
				bExclude = true;
				PackageFilesExcludedByClass.Add(PackageFile);
			}

			//If we haven't failed one of the above checks, add it to the array of packages to process.
			if(!bExclude)
			{
				PackageFileNamesToProcess.Add(PackageFile);
			}
		}
	}

	if ( PackageFileNamesToProcess.Num() == 0 )
	{
		UE_LOG(LogGatherTextFromAssetsCommandlet, Warning, TEXT("No files found or none passed the include/exclude criteria."));
	}

	bool bSkipGatherCache = FParse::Param(FCommandLine::Get(), TEXT("SkipGatherCache"));
	if (!bSkipGatherCache)
	{
		GetBoolFromConfig(*SectionName, TEXT("SkipGatherCache"), bSkipGatherCache, GatherTextConfigPath);
	}
	UE_LOG(LogGatherTextFromAssetsCommandlet, Log, TEXT("SkipGatherCache: %s"), bSkipGatherCache ? TEXT("true") : TEXT("false"));

	TArray< FString > PackageFileNamesToLoad;
	for (FString& PackageFile : PackageFileNamesToProcess)
	{
		TScopedPointer< FArchive > FileReader( IFileManager::Get().CreateFileReader( *PackageFile ) );
		if( FileReader )
		{
			// Read package file summary from the file
			FPackageFileSummary PackageFileSummary;
			(*FileReader) << PackageFileSummary;

			bool MustLoadForGather = false;

			// Have we been asked to skip the cache of text that exists in the header of newer packages?
			if (bSkipGatherCache && PackageFileSummary.GetFileVersionUE4() >= VER_UE4_SERIALIZE_TEXT_IN_PACKAGES)
			{
				// Fallback on the old package flag check.
				if (PackageFileSummary.PackageFlags & PKG_RequiresLocalizationGather)
				{
					MustLoadForGather = true;
				}
			}

			const FCustomVersion* const EditorVersion = PackageFileSummary.GetCustomVersionContainer().GetVersion(FEditorObjectVersion::GUID);

			// Packages not resaved since localization gathering flagging was added to packages must be loaded.
			if (PackageFileSummary.GetFileVersionUE4() < VER_UE4_PACKAGE_REQUIRES_LOCALIZATION_GATHER_FLAGGING)
			{
				MustLoadForGather = true;
			}
			// Package not resaved since gatherable text data was added to package headers must be loaded, since their package header won't contain pregathered text data.
			else if (PackageFileSummary.GetFileVersionUE4() < VER_UE4_SERIALIZE_TEXT_IN_PACKAGES)
			{
				// Fallback on the old package flag check.
				if (PackageFileSummary.PackageFlags & PKG_RequiresLocalizationGather)
				{
					MustLoadForGather = true;
				}
			}
			else if (PackageFileSummary.GetFileVersionUE4() < VER_UE4_DIALOGUE_WAVE_NAMESPACE_AND_CONTEXT_CHANGES)
			{
				IAssetRegistry& AssetRegistry = AssetRegistryModule.Get();
				TArray<FAssetData> AssetDataInPackage;
				AssetRegistry.GetAssetsByPackageName(*FPackageName::FilenameToLongPackageName(PackageFile), AssetDataInPackage);
				for (const FAssetData& AssetData : AssetDataInPackage)
				{
					if (AssetData.AssetClass == UDialogueWave::StaticClass()->GetFName())
					{
						MustLoadForGather = true;
					}
				}
			}
				 
			// Add package to list of packages to load fully and process.
			if (MustLoadForGather)
			{
				PackageFileNamesToLoad.Add(PackageFile);
			}
			// Process immediately packages that don't require loading to process.
			else if (PackageFileSummary.GatherableTextDataOffset > 0)
			{
				FileReader->Seek(PackageFileSummary.GatherableTextDataOffset);

				TArray<FGatherableTextData> GatherableTextDataArray;
				GatherableTextDataArray.SetNum(PackageFileSummary.GatherableTextDataCount);

				for (int32 GatherableTextDataIndex = 0; GatherableTextDataIndex < PackageFileSummary.GatherableTextDataCount; ++GatherableTextDataIndex)
				{
					(*FileReader) << GatherableTextDataArray[GatherableTextDataIndex];
				}

				ProcessGatherableTextDataArray(PackageFile, GatherableTextDataArray);
			}
		}
	}

	CollectGarbage(RF_NoFlags);

	//Now go through the remaining packages in the main array and process them in batches.
	int32 PackagesPerBatchCount = 100;
	TArray< UPackage* > LoadedPackages;
	TArray< FString > LoadedPackageFileNames;
	TArray< FString > FailedPackageFileNames;
	TArray< UPackage* > LoadedPackagesToProcess;

	const int32 PackageCount = PackageFileNamesToLoad.Num();
	const int32 BatchCount = PackageCount / PackagesPerBatchCount + (PackageCount % PackagesPerBatchCount > 0 ? 1 : 0); // Add an extra batch for any remainder if necessary
	if(PackageCount > 0)
	{
		UE_LOG(LogGatherTextFromAssetsCommandlet, Log, TEXT("Loading %i packages in %i batches of %i."), PackageCount, BatchCount, PackagesPerBatchCount);
	}

	FLoadPackageLogOutputRedirector LogOutputRedirector;

	//Load the packages in batches
	int32 PackageIndex = 0;
	for( int32 BatchIndex = 0; BatchIndex < BatchCount; ++BatchIndex )
	{
		int32 PackagesInThisBatch = 0;
		int32 FailuresInThisBatch = 0;
		for( ; PackageIndex < PackageCount && PackagesInThisBatch < PackagesPerBatchCount; ++PackageIndex )
		{
			FString PackageFileName = PackageFileNamesToLoad[PackageIndex];

			UE_LOG(LogGatherTextFromAssetsCommandlet, Verbose, TEXT("Loading package: '%s'."), *PackageFileName);

			UPackage *Package = nullptr;
			{
				FString LongPackageName;
				if (!FPackageName::TryConvertFilenameToLongPackageName(PackageFileName, LongPackageName))
				{
					LongPackageName = FPaths::GetCleanFilename(PackageFileName);
				}

				FLoadPackageLogOutputRedirector::FScopedCapture ScopedCapture(&LogOutputRedirector, LongPackageName);
				Package = LoadPackage( NULL, *PackageFileName, LOAD_NoWarn | LOAD_Quiet );
			}

			if( Package )
			{
				LoadedPackages.Add(Package);
				LoadedPackageFileNames.Add(PackageFileName);

				// Because packages may not have been resaved after this flagging was implemented, we may have added packages to load that weren't flagged - potential false positives.
				// The loading process should have reflagged said packages so that only true positives will have this flag.
				if( Package->RequiresLocalizationGather() )
				{
					LoadedPackagesToProcess.Add( Package );
				}
			}
			else
			{
				FailedPackageFileNames.Add( PackageFileName );
				++FailuresInThisBatch;
				continue;
			}

			++PackagesInThisBatch;
		}

		UE_LOG(LogGatherTextFromAssetsCommandlet, Log, TEXT("Loaded %i packages in batch %i of %i. %i failed."), PackagesInThisBatch, BatchIndex + 1, BatchCount, FailuresInThisBatch);

		ProcessPackages(LoadedPackagesToProcess);
		LoadedPackagesToProcess.Empty(PackagesPerBatchCount);

		if( bFixBroken )
		{
			for( int32 LoadedPackageIndex=0; LoadedPackageIndex < LoadedPackages.Num() ; ++LoadedPackageIndex )
			{
				UPackage *Package = LoadedPackages[LoadedPackageIndex];
				const FString PackageName = LoadedPackageFileNames[LoadedPackageIndex];

				//Todo - link with source control.
				if( Package )
				{
					if( Package->IsDirty() )
					{
						if( SavePackageHelper( Package, *PackageName ) )
						{
							UE_LOG(LogGatherTextFromAssetsCommandlet, Log, TEXT("Saved Package %s."),*PackageName);
						}
						else
						{
							//TODO - Work out how to integrate with source control. The code from the source gatherer doesn't work.
							UE_LOG(LogGatherTextFromAssetsCommandlet, Log, TEXT("Could not save package %s. Probably due to source control. "),*PackageName);
						}
					}
				}
				else
				{
					UE_LOG(LogGatherTextFromAssetsCommandlet, Warning, TEXT("Failed to find one of the loaded packages."));
				}
			}
		}

		CollectGarbage(RF_NoFlags);
		LoadedPackages.Empty(PackagesPerBatchCount);	
		LoadedPackageFileNames.Empty(PackagesPerBatchCount);
	}

	return 0;
}
void UGameplayDebuggingComponent::CollectEQSData()
{
#if USE_EQS_DEBUGGER
    if (!ShouldReplicateData(EAIDebugDrawDataView::EQS))
    {
        return;
    }

    UWorld* World = GetWorld();
    UEnvQueryManager* QueryManager = World ? UEnvQueryManager::GetCurrent(World) : NULL;
    const AActor* Owner = GetSelectedActor();
    AGameplayDebuggingReplicator* Replicator = Cast<AGameplayDebuggingReplicator>(GetOwner());

    if (QueryManager == NULL || Owner == NULL)
    {
        return;
    }

    auto AllQueries = QueryManager->GetDebugger().GetAllQueriesForOwner(Owner);
    const class APawn* OwnerAsPawn = Cast<class APawn>(Owner);
    if (OwnerAsPawn != NULL && OwnerAsPawn->GetController())
    {
        const auto& AllControllerQueries = QueryManager->GetDebugger().GetAllQueriesForOwner(OwnerAsPawn->GetController());
        AllQueries.Append(AllControllerQueries);
    }
    struct FEnvQueryInfoSort
    {
        FORCEINLINE bool operator()(const FEQSDebugger::FEnvQueryInfo& A, const FEQSDebugger::FEnvQueryInfo& B) const
        {
            return (A.Timestamp < B.Timestamp);
        }
    };
    TArray<FEQSDebugger::FEnvQueryInfo> QueriesToSort = AllQueries;
    QueriesToSort.Sort(FEnvQueryInfoSort()); //sort queries by timestamp
    QueriesToSort.SetNum(FMath::Min<int32>(Replicator->MaxEQSQueries, AllQueries.Num()));

    for (int32 Index = AllQueries.Num() - 1; Index >= 0; --Index)
    {
        auto &CurrentQuery = AllQueries[Index];
        if (QueriesToSort.Find(CurrentQuery) == INDEX_NONE)
        {
            AllQueries.RemoveAt(Index);
        }
    }


    EQSLocalData.Reset();
    for (int32 Index = 0; Index < FMath::Min<int32>(Replicator->MaxEQSQueries, AllQueries.Num()); ++Index)
    {
        EQSDebug::FQueryData* CurrentLocalData = NULL;
        CachedQueryInstance = AllQueries[Index].Instance;
        const float CachedTimestamp = AllQueries[Index].Timestamp;

        if (!CurrentLocalData)
        {
            EQSLocalData.AddZeroed();
            CurrentLocalData = &EQSLocalData[EQSLocalData.Num()-1];
        }

        UEnvQueryDebugHelpers::QueryToDebugData(CachedQueryInstance.Get(), *CurrentLocalData);
        CurrentLocalData->Timestamp = AllQueries[Index].Timestamp;
    }

    TArray<uint8> UncompressedBuffer;
    FMemoryWriter ArWriter(UncompressedBuffer);

    ArWriter << EQSLocalData;

    const int32 UncompressedSize = UncompressedBuffer.Num();
    const int32 HeaderSize = sizeof(int32);
    EQSRepData.Init(0, HeaderSize + FMath::TruncToInt(1.1f * UncompressedSize));

    int32 CompressedSize = EQSRepData.Num() - HeaderSize;
    uint8* DestBuffer = EQSRepData.GetData();
    FMemory::Memcpy(DestBuffer, &UncompressedSize, HeaderSize);
    DestBuffer += HeaderSize;

    FCompression::CompressMemory((ECompressionFlags)(COMPRESS_ZLIB | COMPRESS_BiasMemory), (void*)DestBuffer, CompressedSize, (void*)UncompressedBuffer.GetData(), UncompressedSize);

    EQSRepData.SetNum(CompressedSize + HeaderSize, false);

    if (World && World->GetNetMode() != NM_DedicatedServer)
    {
        OnRep_UpdateEQS();
    }
#endif
}