FNA-VSCode-Template/project_name/T4Templates/ContentPathGenerator.tt
2019-09-21 17:00:44 -05:00

258 lines
7.7 KiB
Plaintext

<#@ template language="C#" hostSpecific="true" #>
<#@ assembly name="System.Core.dll" #>
<#@ assembly name="System.dll" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Globalization" #>
<#@ import namespace="System.Text.RegularExpressions" #>
namespace Nez
{
public static class Content
{
public static class Nez
{
<# PrintNezContent(); #>
}
public static class Audio
{
<# PrintAudio(); #>
}
public static class Fonts
{
<# PrintFonts(); #>
}
public static class Materials
{
<# PrintMaterials(); #>
}
public static class Particles
{
<# PrintParticles(); #>
}
public static class Shaders
{
<# PrintShaders(); #>
}
public static class Tilemaps
{
<# PrintTilemaps(); #>
}
public static class Textures
{
<# PrintTextures(); #>
}
public static class Atlases
{
<# PrintAtlases(); #>
}
public static class Compiled
{
<# PrintCompiledContent(); #>
}
}
}
<#+
// all the valid file extensions we should copy for each root folder
private string[] validAudioExtensions = new string[] { ".ogg", ".wav" };
private string[] validFontExtensions = new string[] { ".fnt" };
private string[] validMaterialExtensions = new string[] { ".mat" };
private string[] validParticleExtensions = new string[] { ".pex" };
private string[] validShaderExtensions = new string[] { ".fxb" };
private string[] validTilemapExtensions = new string[] { ".tmx" };
private string[] validTextureExtensions = new string[] { ".png", ".jpg" };
private string[] validAtlasExtensions = new string[] { ".atlas" };
// C# reserved keywords
private System.Collections.Generic.List<string> keywords = new System.Collections.Generic.List<string>
{
"abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char", "checked", "class", "const", "continue", "decimal", "default", "delegate",
"do", "double", "else", "enum", "event", "explicit", "extern", "false", "finally", "fixed", "float", "for", "foreach", "goto", "if", "implicit", "in",
"int", "interface", "internal", "is", "lock", "long", "namespace", "new", "null", "object", "operator", "out", "override", "params", "private",
"protected", "public", "readonly", "ref", "return", "sbyte", "sealed", "short", "sizeof", "stackalloc", "static", "string", "struct", "switch", "this",
"throw", "true", "try", "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort", "using", "virtual", "void", "volatile", "while"
};
void PrintNezContent()
{
PrintSpecialFolderAndSubfolders("../Nez/DefaultContent", new string[] { ".xnb", ".fxb" }, true);
}
void PrintAudio()
{
PrintSpecialFolderAndSubfolders("Content/Audio", validAudioExtensions);
}
void PrintFonts()
{
PrintSpecialFolderAndSubfolders("Content/Fonts", validFontExtensions);
}
void PrintMaterials()
{
PrintSpecialFolderAndSubfolders("Content/Materials", validMaterialExtensions);
}
void PrintParticles()
{
PrintSpecialFolderAndSubfolders("Content/Particles", validParticleExtensions);
}
void PrintShaders()
{
PrintSpecialFolderAndSubfolders("Content/Shaders", validShaderExtensions);
}
void PrintTextures()
{
PrintSpecialFolderAndSubfolders("Content/Textures", validTextureExtensions);
}
void PrintAtlases()
{
PrintSpecialFolderAndSubfolders("Content/Atlases", validAtlasExtensions);
}
void PrintTilemaps()
{
PrintSpecialFolderAndSubfolders("Content/Tilemaps", validTilemapExtensions);
}
void PrintCompiledContent()
{
PrintSpecialFolderAndSubfolders("CompiledContent/bin/DesktopGL", new string[] { ".xnb" }, true);
}
void PrintSpecialFolderAndSubfolders(string source, string[] validExtensions, bool isCompiledFolder = false)
{
var stripPath = isCompiledFolder ? source : "";
PrintContentFiles(source, 3, stripPath, validExtensions);
// loop through all the directories in our sourceFolder
foreach (var dir in Directory.GetDirectories(source))
{
var dirName = new DirectoryInfo(dir).Name.ToLower();
PrintDirectoryClass(dir, 3, stripPath, validExtensions, isCompiledFolder);
}
}
// recursively creates a class for each directory
void PrintDirectoryClass(string dir, int depth, string sourceFolder, string[] validFileExtensions, bool isCompiledFolder)
{
var dirInfo = new DirectoryInfo(dir);
var firstIndent = new string(' ', depth * 4);
var className = GenerateClassName(dirInfo.Name, true);
if (!FolderHasContent(dir, validFileExtensions))
return;
// fix our class name if this is the FNAEffects folder
if (dir.Contains("Nez/DefaultContent") && className == "FNAEffects")
className = "Effects";
WriteLine("{0}public static class {1}\n{2}{{", firstIndent, className, firstIndent);
// handle subdirectories
foreach (var subdir in Directory.GetDirectories(dir))
PrintDirectoryClass(subdir, depth + 1, sourceFolder, validFileExtensions, isCompiledFolder);
// handle files
PrintContentFiles(dir, depth + 1, sourceFolder, validFileExtensions);
WriteLine("{0}}}\n", firstIndent);
}
// prints a const string for each file in the directory
void PrintContentFiles(string dir, int depth, string sourceFolder, string[] validFileExtensions)
{
var firstIndent = new string('\t', depth);
var files = Directory.EnumerateFiles(dir)
.Where( s => Array.IndexOf(validFileExtensions, Path.GetExtension(s)) >= 0);
foreach (var file in files)
{
// clear out all of the path up to the sourceFolder so we get just the relative path to the Content folder
var finalPath = file.Substring(file.IndexOf(sourceFolder) + sourceFolder.Length);
var fileInfo = new FileInfo(file);
var fileName = fileInfo.Name;
// clean the extension
foreach (var extension in validFileExtensions)
fileName = fileName.Replace(extension, string.Empty);
var className = GenerateClassName(fileName, false);
if (finalPath[0] == '/' || finalPath[0] == '\\')
finalPath = finalPath.Substring(1);
// remove xnb extensions to avoid issues with loading
finalPath = finalPath.Replace(".xnb", string.Empty);
// deal with built-in Nez content pathing
if (dir.Contains("Nez/DefaultContent"))
{
if (dir.Contains("FNAEffects"))
{
finalPath = finalPath.Replace("FNAEffects", "Effects");
finalPath = "Content/Nez/" + finalPath;
}
else if(dir.Contains("Textures"))
{
finalPath = "Nez/" + finalPath;
}
}
// if file name is reserved insert a leading '@'
if (keywords.Contains(className))
className = className.Insert( 0, "@" );
WriteLine("{0}public const string {1} = @\"{2}\";", firstIndent, className, finalPath);
}
if (files.Count() > 0)
WriteLine("");
}
// attempts to generate a proper path name
string GenerateClassName(string className, bool uppercaseFirstChar)
{
// handle upper or lower casing the first char in the className
if (uppercaseFirstChar && char.IsLower(className[0]))
className = char.ToUpper(className[0]) + className.Substring(1);
className = className.Replace("-", "_");
// remove invalid characters
var regex = new Regex(@"[^\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Nl}\p{Mn}\p{Mc}\p{Cf}\p{Pc}\p{Lm}]");
className = regex.Replace(className, "");
// class name doesn't begin with a letter, insert an underscore
if (!char.IsLetter(className, 0))
className = className.Insert(0, "_");
return className.Replace(" ", string.Empty);
}
// returns true if the folder or any subfolder has some content with a valid file extension
bool FolderHasContent(string dir, string[] validFileExtensions)
{
var files = Directory.EnumerateFiles(dir)
.Where( s => Array.IndexOf(validFileExtensions, Path.GetExtension(s)) >= 0);
return files.Count() > 0;
}
#>