Last active
July 13, 2016 08:33
-
-
Save maxmcguire/911e445324ffb97a61f8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This is a small Unity utility that will add a new menu item which can be used to force | |
// shaders to be rebuilt when an included file is updated (Unity will only automatically do | |
// this if the #including file is in the same directory). | |
// To use it, simply select the Assets/Shaders/Rebuild Shaders menu option. Any shader file | |
// which #includes a file that has a newer timestamp will be trivially modified to force it | |
// to be rebuilt. | |
using UnityEngine; | |
using UnityEditor; | |
using System.IO; | |
using System.Collections; | |
using System.Text.RegularExpressions; | |
using System.Collections.Generic; | |
public class RebuildShaders | |
{ | |
[MenuItem("Assets/Shaders/Rebuild Shaders")] | |
private static void RebuildShadersAction() | |
{ | |
var projectFolder = System.IO.Directory.GetCurrentDirectory(); | |
var shaderGuids = AssetDatabase.FindAssets("t:shader"); | |
// Build a list of dependenices starting from the shaders. | |
Hashtable lastChangeTimes = new Hashtable(); | |
foreach (var guid in shaderGuids) | |
{ | |
string fileName = projectFolder + "/" + AssetDatabase.GUIDToAssetPath(guid); | |
ExtractDependencies(projectFolder, fileName, lastChangeTimes); | |
} | |
// Check if a shader is older than any of its dependencies. | |
foreach (var guid in shaderGuids) | |
{ | |
string fileName = projectFolder + "/" + AssetDatabase.GUIDToAssetPath(guid); | |
long lastChangeTime = File.GetLastWriteTime(fileName).ToFileTime(); | |
if (lastChangeTime < (long)lastChangeTimes[fileName]) | |
{ | |
Debug.Log("Need to rebuild" + fileName); | |
ForceRebuild(fileName); | |
} | |
} | |
AssetDatabase.Refresh(); | |
} | |
private static void ForceRebuild(string fileName) | |
{ | |
// Updating the file modification time doesn't seem to be enough to get Unity to rebuild it, | |
// so we need to actually modify the file. | |
using (FileStream file = File.Open(fileName, FileMode.Open, FileAccess.ReadWrite)) | |
{ | |
bool hasNewLineAtEnd = false; | |
long length = file.Length; | |
if (length > 0) | |
{ | |
file.Seek(-1, SeekOrigin.End); | |
int c = file.ReadByte(); | |
hasNewLineAtEnd = (c == '\n'); | |
} | |
if (hasNewLineAtEnd) | |
{ | |
// Remove the new line at the end. | |
file.SetLength(length - 1); | |
} | |
else | |
{ | |
// Add a new line at the end. | |
file.Seek(0, SeekOrigin.End); | |
file.WriteByte((byte)'\n'); | |
} | |
} | |
} | |
private static long ExtractDependencies(string projectFolder, string fileName, Hashtable lastChangeTimes) | |
{ | |
if (!File.Exists(fileName)) | |
{ | |
return 0; | |
} | |
if (lastChangeTimes.Contains(fileName)) | |
{ | |
// We've already parsed the dependenices for this file. | |
return (long)lastChangeTimes[fileName]; | |
} | |
long lastChangeTime = File.GetLastWriteTime(fileName).ToFileTime(); | |
// Store right away, just in case we have circular dependencies. This will prevent an infinite loop. | |
lastChangeTimes[fileName] = lastChangeTime; | |
string fileFolder = Path.GetDirectoryName(fileName); | |
using (StreamReader reader = File.OpenText(fileName)) | |
{ | |
string line; | |
while ((line = reader.ReadLine()) != null) | |
{ | |
// This doesn't properly handly #include being inside a string or inside a comment, but it won't have | |
// any negative effects. | |
Match match = Regex.Match(line, "#include\\s\"(.+)\""); | |
if (match.Success) | |
{ | |
string includeFileName = match.Groups[1].Value; | |
// The include file name could be relative to the current file's path, or it could be "absolute" in | |
// the project, so try both possibilities. | |
string absoluteFileName = Path.Combine(projectFolder, includeFileName); | |
string relativeFileName = Path.Combine(fileFolder, includeFileName); | |
long dependencyLastChangeTime = ExtractDependencies(projectFolder, absoluteFileName, lastChangeTimes); | |
if (dependencyLastChangeTime > lastChangeTime) | |
{ | |
lastChangeTime = dependencyLastChangeTime; | |
} | |
dependencyLastChangeTime = ExtractDependencies(projectFolder, relativeFileName, lastChangeTimes); | |
if (dependencyLastChangeTime > lastChangeTime) | |
{ | |
lastChangeTime = dependencyLastChangeTime; | |
} | |
} | |
} | |
} | |
lastChangeTimes[fileName] = lastChangeTime; | |
return lastChangeTime; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment