Files
Nerfed/Nerfed.Builder/Builder/Builder.cs
T
2026-04-28 19:17:23 +02:00

177 lines
6.8 KiB
C#

using System.Diagnostics;
using System.Text.Json;
using Nerfed.Builder.Meta;
namespace Nerfed.Builder;
public class Builder : IDisposable
{
private readonly Dictionary<string, IImporter> importers = new Dictionary<string, IImporter>();
private readonly RawFileImporter rawFileImporter;
public Builder()
{
rawFileImporter = new RawFileImporter();
importers.Add(".vert", new ShaderImporter(ShaderStage.Vertex)); // Vertex shader
importers.Add(".frag", new ShaderImporter(ShaderStage.Fragment)); // Fragment shader
//importers.Add(".tesc", shaderImporter); // Tessellation control shader
//importers.Add(".tese", shaderImporter); // Tessellation evaluation shader
//importers.Add(".geom", shaderImporter); // Geometry shader
//importers.Add(".comp", shaderImporter); // Compute shader
}
public void Run(BuildArgs args)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
//CopyLibs(args.ResourcePath);
List<string> contentFiles = args.ResourceFiles;
// If no files are provided, build all content.
if (args.ResourceFiles == null)
{
contentFiles = [];
CollectAssetFiles(args.ResourcePath, args.ResourcePath, ref contentFiles);
}
if (contentFiles.Count > 0)
{
ParallelOptions parallelOptions = new ParallelOptions
{
MaxDegreeOfParallelism = contentFiles.Count
};
Parallel.ForEach(contentFiles, parallelOptions, relativeFile =>
{
try
{
string inFile = $"{args.ResourcePath}/{relativeFile}";
if (!File.Exists(inFile))
{
Console.Error.WriteLine($"Asset file '{relativeFile}' not found");
return;
}
string outFile = $"{args.ResourceOutPath}/{relativeFile}{PathUtil.ImportedFileExtension}";
FileInfo inFileInfo = new FileInfo(inFile);
// =========================================================================
// STEP 1: GUID META FILE SYNC
// Ensure the source file has a backing .meta file generating its Guid
// =========================================================================
string metaFile = inFile + ".meta";
AssetMeta metaData;
if (!File.Exists(metaFile))
{
// Generate a brand new meta file to track this asset permanently
metaData = new AssetMeta(Guid.NewGuid());
string json = JsonSerializer.Serialize(metaData, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(metaFile, json);
Console.WriteLine($"[Meta] Generated new tracking ID '{metaData.Id}' for {relativeFile}");
}
else
{
// Load the existing guid
metaData = JsonSerializer.Deserialize<AssetMeta>(File.ReadAllText(metaFile))!;
}
// Change output file from Name.ext.bin -> /GUID.bin to completely anonymize the actual game package!
string cacheOutFile = $"{args.ResourceOutPath}/{metaData.Id}.bin";
FileInfo outFileInfo = new FileInfo(cacheOutFile);
// Rebuild if the source file changed, or if the meta file changed!
FileInfo metaFileInfo = new FileInfo(metaFile);
bool requiresCompile = !outFileInfo.Exists ||
FileUtil.IsNewer(inFileInfo, outFileInfo) ||
FileUtil.IsNewer(metaFileInfo, outFileInfo);
if (!requiresCompile)
{
// File has not changed since last build, no need to build this one.
return;
}
string outDir = Path.GetDirectoryName(cacheOutFile)!;
if (!Directory.Exists(outDir))
{
Directory.CreateDirectory(outDir);
}
string ext = Path.GetExtension(inFile).ToLower();
if (importers.TryGetValue(ext, out IImporter importer))
{
importer.Import(inFile, cacheOutFile); // Compile source directly to hash.bin
}
else
{
rawFileImporter.Import(inFile, cacheOutFile);
}
Console.WriteLine($"Compiled {relativeFile} -> {metaData.Id}.bin");
}
catch (Exception e)
{
Console.Error.WriteLine($"Import error on asset '{relativeFile}': {e.Message}");
}
});
}
Console.WriteLine($"Build content completed in {stopwatch.Elapsed.TotalSeconds:F2} seconds");
}
/*private void CopyLibs(string projectPath)
{
string libDir = $"{AppDomain.CurrentDomain.BaseDirectory}/../../Native/";
if (OperatingSystem.IsWindows())
{
libDir += "x64";
}
else if (OperatingSystem.IsLinux())
{
libDir += "lib64";
}
else if (OperatingSystem.IsMacOS())
{
libDir += "osx";
}
libDir = Path.GetFullPath(libDir);
foreach (string libFile in Directory.EnumerateFiles(libDir))
{
FileInfo srcFileInfo = new FileInfo(libFile);
FileInfo dstFileInfo = new FileInfo($"{projectPath}/{PathUtil.BuildFolderName}/{Path.GetFileName(libFile)}");
if (FileUtil.IsNewer(srcFileInfo, dstFileInfo))
{
FileUtil.Copy(srcFileInfo, dstFileInfo);
}
}
}*/
private void CollectAssetFiles(string assetDir, string dir, ref List<string> files)
{
foreach (string file in Directory.EnumerateFiles(dir))
{
string relativeFile = file.Substring(assetDir.Length, file.Length - assetDir.Length);
if (relativeFile[0] == Path.DirectorySeparatorChar || relativeFile[0] == Path.AltDirectorySeparatorChar)
{
relativeFile = relativeFile.Substring(1, relativeFile.Length - 1);
}
files.Add(relativeFile);
}
foreach (string subDir in Directory.EnumerateDirectories(dir))
{
CollectAssetFiles(assetDir, subDir, ref files);
}
}
public void Dispose() { }
}