Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* ShaderTargetCompileTool.cs */
- /* Place this file in Assets/Editor/ */
- using System.Collections.Generic;
- using System.IO;
- using UnityEditor;
- using UnityEngine;
- using UnityEngine.Rendering;
- public class ShaderTargetCompileTool : EditorWindow
- {
- /* We validate shaders against the selected build target */
- private BuildTarget target = BuildTarget.PSP2;
- /* We keep generated probe assets isolated and disposable */
- private string tempRoot = "Assets/__ShaderCompileProbe";
- private string bundleName = "shader_compile_probe";
- /* We write a clean shader error report after the compile probe runs */
- private string reportPath = "Temp/ShaderCompileProbeReport.txt";
- private bool generateErrorReport = true;
- private bool reportAvailable = false;
- /* We control compile coverage */
- private bool includeVariants = true;
- private bool scrapeShaderPragmas = true;
- private bool includeUnityBuiltInPragmas = true;
- private bool includeVertexLightmapSafetyCombos = true;
- private bool exhaustiveMode = false;
- /* We cap generated variants in practical mode so compile time does not explode */
- private int maxGeneratedCombosPerShader = 256;
- private Vector2 scroll;
- private readonly List<string> log = new List<string>();
- /*
- We keep explicit known-good safety-net combos here.
- These are not the main variant source anymore; they are extra protection for Vita lighting cases.
- */
- private readonly string[][] vertexLightmapSafetyCombos =
- {
- new string[] { "VERTEXLIGHT_ON", "LIGHTMAP_ON" },
- new string[] { "VERTEXLIGHT_ON", "LIGHTMAP_ON", "DIRLIGHTMAP_COMBINED" },
- new string[] { "VERTEXLIGHT_ON", "LIGHTMAP_ON", "_NORMALMAP" },
- new string[] { "VERTEXLIGHT_ON", "LIGHTMAP_ON", "_METALLICGLOSSMAP" },
- new string[] { "VERTEXLIGHT_ON", "LIGHTMAP_ON", "_NORMALMAP", "_METALLICGLOSSMAP" },
- new string[] { "LIGHTMAP_ON", "_NORMALMAP" },
- new string[] { "LIGHTMAP_ON", "_METALLICGLOSSMAP" },
- new string[] { "LIGHTMAP_ON", "_NORMALMAP", "_METALLICGLOSSMAP" },
- new string[] { "VERTEXLIGHT_ON", "_NORMALMAP" },
- new string[] { "VERTEXLIGHT_ON", "_METALLICGLOSSMAP" },
- new string[] { "VERTEXLIGHT_ON", "_NORMALMAP", "_METALLICGLOSSMAP" }
- };
- /*
- We compile across common pass types.
- Unsupported pass/shader pairs are skipped safely.
- */
- private readonly PassType[] commonPasses =
- {
- PassType.Normal,
- PassType.ForwardBase,
- PassType.ForwardAdd,
- PassType.ShadowCaster,
- PassType.Meta,
- PassType.Vertex,
- PassType.Deferred,
- PassType.LightPrePassBase,
- PassType.LightPrePassFinal
- };
- [MenuItem("Tools/Vita/Compile Project Shaders")]
- public static void Open()
- {
- GetWindow<ShaderTargetCompileTool>("Shader Compile Probe");
- }
- private void OnEnable()
- {
- reportAvailable = File.Exists(reportPath);
- }
- private void OnGUI()
- {
- target = (BuildTarget)EditorGUILayout.EnumPopup("Build Target", target);
- EditorGUILayout.Space();
- includeVariants = EditorGUILayout.Toggle("Create Variant Collection", includeVariants);
- scrapeShaderPragmas = EditorGUILayout.Toggle("Scrape Shader Pragmas", scrapeShaderPragmas);
- includeUnityBuiltInPragmas = EditorGUILayout.Toggle("Expand Unity Built-In Pragmas", includeUnityBuiltInPragmas);
- includeVertexLightmapSafetyCombos = EditorGUILayout.Toggle("Include Vertex/Lightmap Safety Combos", includeVertexLightmapSafetyCombos);
- exhaustiveMode = EditorGUILayout.Toggle("Exhaustive Mode", exhaustiveMode);
- generateErrorReport = EditorGUILayout.Toggle("Generate Error Report", generateErrorReport);
- if (!exhaustiveMode)
- {
- maxGeneratedCombosPerShader = EditorGUILayout.IntField(
- "Max Combos / Shader",
- maxGeneratedCombosPerShader
- );
- if (maxGeneratedCombosPerShader < 1)
- maxGeneratedCombosPerShader = 1;
- }
- EditorGUILayout.Space();
- if (GUILayout.Button("Compile Project Shaders For Target", GUILayout.Height(32)))
- CompileShaders();
- EditorGUILayout.Space();
- GUI.enabled = reportAvailable && File.Exists(reportPath);
- if (GUILayout.Button("Open Shader Compile Report", GUILayout.Height(26)))
- OpenShaderCompileReport();
- GUI.enabled = true;
- EditorGUILayout.Space();
- scroll = EditorGUILayout.BeginScrollView(scroll);
- for (int i = 0; i < log.Count; i++)
- EditorGUILayout.LabelField(log[i], EditorStyles.wordWrappedLabel);
- EditorGUILayout.EndScrollView();
- }
- private void CompileShaders()
- {
- log.Clear();
- reportAvailable = false;
- long editorLogStart = 0;
- if (generateErrorReport)
- editorLogStart = GetEditorLogLength();
- try
- {
- CleanupTempAssets();
- Directory.CreateDirectory(tempRoot);
- AssetDatabase.Refresh();
- string[] shaderGuids = AssetDatabase.FindAssets("t:Shader");
- int materialCount = 0;
- int variantCount = 0;
- ShaderVariantCollection svc = null;
- if (includeVariants)
- svc = new ShaderVariantCollection();
- for (int i = 0; i < shaderGuids.Length; i++)
- {
- string shaderPath = AssetDatabase.GUIDToAssetPath(shaderGuids[i]);
- if (shaderPath.StartsWith("Packages/"))
- continue;
- Shader shader = AssetDatabase.LoadAssetAtPath<Shader>(shaderPath);
- if (shader == null)
- continue;
- /*
- We create one dummy material per shader.
- This forces Unity to include the shader in the temporary AssetBundle compile.
- */
- Material mat = new Material(shader);
- string safeName = MakeSafeAssetName(shader.name);
- string matPath = tempRoot + "/" + safeName + ".mat";
- AssetDatabase.CreateAsset(mat, matPath);
- AssetImporter importer = AssetImporter.GetAtPath(matPath);
- importer.assetBundleName = bundleName;
- materialCount++;
- log.Add("Queued shader: " + shaderPath);
- if (includeVariants && svc != null)
- variantCount += AddVariantsForShader(svc, shader, shaderPath);
- }
- if (includeVariants && svc != null)
- {
- string svcPath = tempRoot + "/GeneratedShaderVariants.shadervariants";
- AssetDatabase.CreateAsset(svc, svcPath);
- AssetImporter importer = AssetImporter.GetAtPath(svcPath);
- importer.assetBundleName = bundleName;
- log.Add("");
- log.Add("Generated ShaderVariantCollection variants: " + variantCount);
- }
- AssetDatabase.SaveAssets();
- AssetDatabase.Refresh();
- string outputPath = "Temp/ShaderCompileProbeBundles";
- if (!Directory.Exists(outputPath))
- Directory.CreateDirectory(outputPath);
- log.Add("");
- log.Add("Building temporary AssetBundle for: " + target);
- log.Add("Materials generated: " + materialCount);
- /*
- We use StrictMode so shader errors fail loudly.
- This makes the probe useful as a pre-build validation step.
- */
- BuildAssetBundleOptions options =
- BuildAssetBundleOptions.ForceRebuildAssetBundle |
- BuildAssetBundleOptions.StrictMode;
- AssetBundleManifest manifest = BuildPipeline.BuildAssetBundles(
- outputPath,
- options,
- target
- );
- log.Add("");
- if (manifest != null)
- log.Add("Shader compile probe completed. Check Console / report for errors.");
- else
- log.Add("AssetBundle build failed. Check Console / report for shader errors.");
- }
- finally
- {
- if (generateErrorReport)
- {
- string newLogText = ReadEditorLogFrom(editorLogStart);
- WriteShaderCompileReport(newLogText);
- reportAvailable = File.Exists(reportPath);
- log.Add("");
- log.Add("Shader compile report written to:");
- log.Add(reportPath);
- }
- CleanupTempAssets();
- AssetDatabase.Refresh();
- Repaint();
- }
- }
- private int AddVariantsForShader(ShaderVariantCollection svc, Shader shader, string shaderPath)
- {
- int added = 0;
- List<string[]> combos = new List<string[]>();
- if (scrapeShaderPragmas)
- {
- ShaderVariantScanResult scan = ScanShaderAndIncludes(shaderPath);
- combos.AddRange(BuildKeywordCombos(scan));
- log.Add(" Pragmas found: " + scan.keywordGroups.Count + " groups, " + scan.skipKeywords.Count + " skipped keywords");
- log.Add(" Generated pragma combos: " + combos.Count);
- }
- if (includeVertexLightmapSafetyCombos)
- {
- for (int i = 0; i < vertexLightmapSafetyCombos.Length; i++)
- combos.Add(vertexLightmapSafetyCombos[i]);
- }
- combos = DeduplicateCombos(combos);
- for (int p = 0; p < commonPasses.Length; p++)
- {
- PassType passType = commonPasses[p];
- added += TryAddVariant(svc, shader, passType, new string[0]);
- for (int c = 0; c < combos.Count; c++)
- added += TryAddVariant(svc, shader, passType, combos[c]);
- }
- return added;
- }
- private ShaderVariantScanResult ScanShaderAndIncludes(string shaderPath)
- {
- ShaderVariantScanResult result = new ShaderVariantScanResult();
- HashSet<string> visited = new HashSet<string>();
- ScanFileRecursive(shaderPath, result, visited);
- return result;
- }
- private void ScanFileRecursive(
- string assetPath,
- ShaderVariantScanResult result,
- HashSet<string> visited
- )
- {
- if (string.IsNullOrEmpty(assetPath))
- return;
- if (visited.Contains(assetPath))
- return;
- visited.Add(assetPath);
- string fullPath = Path.GetFullPath(assetPath);
- if (!File.Exists(fullPath))
- return;
- string directory = Path.GetDirectoryName(assetPath);
- string[] lines = File.ReadAllLines(fullPath);
- bool inBlockComment = false;
- for (int i = 0; i < lines.Length; i++)
- {
- string line = StripComments(lines[i], ref inBlockComment).Trim();
- if (string.IsNullOrEmpty(line))
- continue;
- if (line.StartsWith("#include"))
- {
- string includePath = ExtractIncludePath(line);
- if (!string.IsNullOrEmpty(includePath))
- {
- string resolved = ResolveIncludeAssetPath(directory, includePath);
- if (!string.IsNullOrEmpty(resolved))
- ScanFileRecursive(resolved, result, visited);
- }
- continue;
- }
- if (!line.StartsWith("#pragma"))
- continue;
- ParsePragmaLine(line, result);
- }
- }
- private void ParsePragmaLine(string line, ShaderVariantScanResult result)
- {
- string[] tokens = SplitTokens(line);
- if (tokens.Length < 2)
- return;
- string pragmaType = tokens[1];
- if (pragmaType == "skip_variants")
- {
- for (int i = 2; i < tokens.Length; i++)
- {
- if (!string.IsNullOrEmpty(tokens[i]))
- result.skipKeywords.Add(tokens[i]);
- }
- return;
- }
- if (includeUnityBuiltInPragmas && IsUnityBuiltInVariantPragma(pragmaType))
- {
- AddUnityBuiltInKeywordGroups(pragmaType, result);
- return;
- }
- if (!IsExplicitVariantPragma(pragmaType))
- return;
- List<string> keywords = new List<string>();
- for (int i = 2; i < tokens.Length; i++)
- {
- string token = tokens[i];
- if (string.IsNullOrEmpty(token))
- continue;
- if (token == "_")
- continue;
- if (IsIgnoredPragmaToken(token))
- continue;
- keywords.Add(token);
- }
- if (keywords.Count > 0)
- result.keywordGroups.Add(keywords.ToArray());
- }
- private List<string[]> BuildKeywordCombos(ShaderVariantScanResult scan)
- {
- List<string[]> combos = new List<string[]>();
- /*
- We add single-keyword variants first.
- This gives useful coverage even when capped mode stops full expansion early.
- */
- for (int g = 0; g < scan.keywordGroups.Count; g++)
- {
- for (int k = 0; k < scan.keywordGroups[g].Length; k++)
- {
- string keyword = scan.keywordGroups[g][k];
- if (!scan.skipKeywords.Contains(keyword))
- combos.Add(new string[] { keyword });
- }
- }
- List<string[]> generated = new List<string[]>();
- BuildKeywordCrossProduct(scan.keywordGroups, scan.skipKeywords, 0, new List<string>(), generated);
- for (int i = 0; i < generated.Count; i++)
- {
- combos.Add(generated[i]);
- if (!exhaustiveMode && combos.Count >= maxGeneratedCombosPerShader)
- break;
- }
- return DeduplicateCombos(combos);
- }
- private void BuildKeywordCrossProduct(
- List<string[]> groups,
- HashSet<string> skipKeywords,
- int groupIndex,
- List<string> current,
- List<string[]> output
- )
- {
- if (!exhaustiveMode && output.Count >= maxGeneratedCombosPerShader)
- return;
- if (groupIndex >= groups.Count)
- {
- if (current.Count > 0)
- output.Add(current.ToArray());
- return;
- }
- /*
- We include the no-keyword option for each group.
- This approximates shader_feature and keeps multi_compile coverage practical.
- */
- BuildKeywordCrossProduct(groups, skipKeywords, groupIndex + 1, current, output);
- string[] group = groups[groupIndex];
- for (int i = 0; i < group.Length; i++)
- {
- string keyword = group[i];
- if (skipKeywords.Contains(keyword))
- continue;
- current.Add(keyword);
- BuildKeywordCrossProduct(groups, skipKeywords, groupIndex + 1, current, output);
- current.RemoveAt(current.Count - 1);
- if (!exhaustiveMode && output.Count >= maxGeneratedCombosPerShader)
- return;
- }
- }
- private bool IsExplicitVariantPragma(string pragmaType)
- {
- return
- pragmaType == "multi_compile" ||
- pragmaType == "multi_compile_local" ||
- pragmaType == "shader_feature" ||
- pragmaType == "shader_feature_local";
- }
- private bool IsUnityBuiltInVariantPragma(string pragmaType)
- {
- return
- pragmaType == "multi_compile_fwdbase" ||
- pragmaType == "multi_compile_fwdadd" ||
- pragmaType == "multi_compile_fwdadd_fullshadows" ||
- pragmaType == "multi_compile_shadowcaster" ||
- pragmaType == "multi_compile_fog";
- }
- private void AddUnityBuiltInKeywordGroups(string pragmaType, ShaderVariantScanResult result)
- {
- if (pragmaType == "multi_compile_fwdbase")
- {
- result.keywordGroups.Add(new string[] { "DIRECTIONAL" });
- result.keywordGroups.Add(new string[] { "LIGHTMAP_ON" });
- result.keywordGroups.Add(new string[] { "DIRLIGHTMAP_COMBINED" });
- result.keywordGroups.Add(new string[] { "DYNAMICLIGHTMAP_ON" });
- result.keywordGroups.Add(new string[] { "VERTEXLIGHT_ON" });
- result.keywordGroups.Add(new string[] { "SHADOWS_SCREEN", "SHADOWS_DEPTH" });
- return;
- }
- if (pragmaType == "multi_compile_fwdadd")
- {
- result.keywordGroups.Add(new string[] { "POINT", "DIRECTIONAL", "SPOT" });
- return;
- }
- if (pragmaType == "multi_compile_fwdadd_fullshadows")
- {
- result.keywordGroups.Add(new string[] { "POINT", "DIRECTIONAL", "SPOT" });
- result.keywordGroups.Add(new string[] { "SHADOWS_DEPTH", "SHADOWS_CUBE", "SHADOWS_SCREEN" });
- return;
- }
- if (pragmaType == "multi_compile_shadowcaster")
- {
- result.keywordGroups.Add(new string[] { "SHADOWS_DEPTH", "SHADOWS_CUBE" });
- return;
- }
- if (pragmaType == "multi_compile_fog")
- {
- result.keywordGroups.Add(new string[] { "FOG_LINEAR", "FOG_EXP", "FOG_EXP2" });
- return;
- }
- }
- private bool IsIgnoredPragmaToken(string token)
- {
- if (token.StartsWith("//"))
- return true;
- if (token == "nolightmap")
- return true;
- if (token == "nodirlightmap")
- return true;
- if (token == "nodynlightmap")
- return true;
- if (token == "noforwardadd")
- return true;
- if (token == "novertexlight")
- return true;
- if (token == "noambient")
- return true;
- if (token == "interpolateview")
- return true;
- if (token == "halfasview")
- return true;
- if (token == "addshadow")
- return true;
- if (token == "fullforwardshadows")
- return true;
- return false;
- }
- private List<string[]> DeduplicateCombos(List<string[]> combos)
- {
- List<string[]> result = new List<string[]>();
- HashSet<string> seen = new HashSet<string>();
- for (int i = 0; i < combos.Count; i++)
- {
- string[] combo = NormalizeCombo(combos[i]);
- string key = string.Join(" ", combo);
- if (string.IsNullOrEmpty(key))
- continue;
- if (seen.Contains(key))
- continue;
- seen.Add(key);
- result.Add(combo);
- }
- return result;
- }
- private string[] NormalizeCombo(string[] combo)
- {
- List<string> clean = new List<string>();
- HashSet<string> seen = new HashSet<string>();
- for (int i = 0; i < combo.Length; i++)
- {
- string keyword = combo[i];
- if (string.IsNullOrEmpty(keyword))
- continue;
- if (keyword == "_")
- continue;
- if (seen.Contains(keyword))
- continue;
- seen.Add(keyword);
- clean.Add(keyword);
- }
- clean.Sort();
- return clean.ToArray();
- }
- private int TryAddVariant(
- ShaderVariantCollection svc,
- Shader shader,
- PassType passType,
- string[] keywords
- )
- {
- try
- {
- ShaderVariantCollection.ShaderVariant variant =
- new ShaderVariantCollection.ShaderVariant(shader, passType, keywords);
- if (!svc.Contains(variant))
- {
- svc.Add(variant);
- return 1;
- }
- }
- catch
- {
- /*
- Some shaders do not support certain passes or keyword combinations.
- We skip those so the probe keeps moving.
- */
- }
- return 0;
- }
- private long GetEditorLogLength()
- {
- string path = GetEditorLogPath();
- if (string.IsNullOrEmpty(path))
- return 0;
- if (!File.Exists(path))
- return 0;
- FileInfo info = new FileInfo(path);
- return info.Length;
- }
- private string ReadEditorLogFrom(long startOffset)
- {
- string path = GetEditorLogPath();
- if (string.IsNullOrEmpty(path))
- return "";
- if (!File.Exists(path))
- return "";
- using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
- {
- if (startOffset < 0)
- startOffset = 0;
- if (startOffset > stream.Length)
- startOffset = 0;
- stream.Seek(startOffset, SeekOrigin.Begin);
- using (StreamReader reader = new StreamReader(stream))
- return reader.ReadToEnd();
- }
- }
- private string GetEditorLogPath()
- {
- #if UNITY_EDITOR_WIN
- return Path.Combine(
- System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData),
- "Unity/Editor/Editor.log"
- );
- #elif UNITY_EDITOR_OSX
- return Path.Combine(
- System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal),
- "Library/Logs/Unity/Editor.log"
- );
- #else
- return "";
- #endif
- }
- private void WriteShaderCompileReport(string logText)
- {
- string reportDirectory = Path.GetDirectoryName(reportPath);
- if (!string.IsNullOrEmpty(reportDirectory) && !Directory.Exists(reportDirectory))
- Directory.CreateDirectory(reportDirectory);
- List<string> report = new List<string>();
- report.Add("Shader Compile Probe Report");
- report.Add("Target: " + target);
- report.Add("Generated: " + System.DateTime.Now);
- report.Add("");
- if (string.IsNullOrEmpty(logText))
- {
- report.Add("No new Editor.log text was captured during shader compile probe.");
- File.WriteAllLines(reportPath, report.ToArray());
- return;
- }
- string[] lines = logText.Split('\n');
- string lastProgram = "";
- string lastPass = "";
- string lastKeywords = "";
- string lastPlatformDefines = "";
- int errorCount = 0;
- for (int i = 0; i < lines.Length; i++)
- {
- string line = lines[i].Trim();
- if (line.StartsWith("Compiling "))
- lastProgram = line;
- if (line.StartsWith("Pass"))
- lastPass = line;
- if (line.StartsWith("Keywords:"))
- lastKeywords = line.Substring("Keywords:".Length).Trim();
- if (line.StartsWith("Platform defines:"))
- lastPlatformDefines = line.Substring("Platform defines:".Length).Trim();
- if (IsShaderErrorLine(line))
- {
- errorCount++;
- report.Add("------------------------------------------------------------");
- report.Add("Error #" + errorCount);
- report.Add("");
- report.Add(line);
- if (!string.IsNullOrEmpty(lastProgram))
- report.Add("Program: " + lastProgram);
- if (!string.IsNullOrEmpty(lastPass))
- report.Add("Pass: " + lastPass);
- if (!string.IsNullOrEmpty(lastKeywords))
- report.Add("Keywords: " + lastKeywords);
- if (!string.IsNullOrEmpty(lastPlatformDefines))
- report.Add("Platform Defines: " + lastPlatformDefines);
- report.Add("");
- report.Add("Context:");
- /*
- We include nearby compiler lines because Unity often places the actual
- failed expression, source line, or platform compiler message nearby.
- */
- for (int c = i + 1; c < lines.Length && c < i + 12; c++)
- {
- string context = lines[c].Trim();
- if (string.IsNullOrEmpty(context))
- continue;
- if (IsShaderErrorLine(context) && c != i)
- break;
- report.Add(context);
- }
- report.Add("");
- }
- }
- if (errorCount == 0)
- report.Add("No shader compile errors were detected in the captured Editor.log section.");
- File.WriteAllLines(reportPath, report.ToArray());
- }
- private bool IsShaderErrorLine(string line)
- {
- if (line.StartsWith("Shader error in"))
- return true;
- if (line.IndexOf("CGPROGRAM", System.StringComparison.OrdinalIgnoreCase) >= 0 &&
- line.IndexOf("error", System.StringComparison.OrdinalIgnoreCase) >= 0)
- return true;
- if (line.IndexOf("program", System.StringComparison.OrdinalIgnoreCase) >= 0 &&
- line.IndexOf("error", System.StringComparison.OrdinalIgnoreCase) >= 0)
- return true;
- return false;
- }
- private void OpenShaderCompileReport()
- {
- if (!File.Exists(reportPath))
- {
- EditorUtility.DisplayDialog(
- "Shader Compile Report",
- "No shader compile report exists yet. Run the compile probe first.",
- "OK"
- );
- reportAvailable = false;
- Repaint();
- return;
- }
- EditorUtility.OpenWithDefaultApp(reportPath);
- }
- private string ExtractIncludePath(string line)
- {
- int firstQuote = line.IndexOf("\"");
- int lastQuote = line.LastIndexOf("\"");
- if (firstQuote >= 0 && lastQuote > firstQuote)
- return line.Substring(firstQuote + 1, lastQuote - firstQuote - 1);
- int firstAngle = line.IndexOf("<");
- int lastAngle = line.LastIndexOf(">");
- if (firstAngle >= 0 && lastAngle > firstAngle)
- return line.Substring(firstAngle + 1, lastAngle - firstAngle - 1);
- return null;
- }
- private string ResolveIncludeAssetPath(string currentDirectory, string includePath)
- {
- string relativePath = NormalizeAssetPath(Path.Combine(currentDirectory, includePath));
- if (File.Exists(Path.GetFullPath(relativePath)))
- return relativePath;
- string directPath = NormalizeAssetPath(includePath);
- if (File.Exists(Path.GetFullPath(directPath)))
- return directPath;
- return null;
- }
- private string NormalizeAssetPath(string path)
- {
- return path.Replace("\\", "/");
- }
- private string StripComments(string line, ref bool inBlockComment)
- {
- string output = "";
- int i = 0;
- while (i < line.Length)
- {
- if (inBlockComment)
- {
- int end = line.IndexOf("*/", i);
- if (end < 0)
- return output;
- inBlockComment = false;
- i = end + 2;
- continue;
- }
- int lineComment = line.IndexOf("//", i);
- int blockComment = line.IndexOf("/*", i);
- if (lineComment >= 0 && (blockComment < 0 || lineComment < blockComment))
- {
- output += line.Substring(i, lineComment - i);
- return output;
- }
- if (blockComment >= 0)
- {
- output += line.Substring(i, blockComment - i);
- inBlockComment = true;
- i = blockComment + 2;
- continue;
- }
- output += line.Substring(i);
- return output;
- }
- return output;
- }
- private string[] SplitTokens(string line)
- {
- return line.Split(
- new char[] { ' ', '\t' },
- System.StringSplitOptions.RemoveEmptyEntries
- );
- }
- private string MakeSafeAssetName(string input)
- {
- string output = input;
- output = output.Replace("/", "_");
- output = output.Replace("\\", "_");
- output = output.Replace(":", "_");
- output = output.Replace("*", "_");
- output = output.Replace("?", "_");
- output = output.Replace("\"", "_");
- output = output.Replace("<", "_");
- output = output.Replace(">", "_");
- output = output.Replace("|", "_");
- return output;
- }
- private void CleanupTempAssets()
- {
- if (AssetDatabase.IsValidFolder(tempRoot))
- AssetDatabase.DeleteAsset(tempRoot);
- string outputPath = "Temp/ShaderCompileProbeBundles";
- if (Directory.Exists(outputPath))
- Directory.Delete(outputPath, true);
- }
- /*
- We keep scan output grouped so future expansion can track variants per pass/subshader.
- For now, we aggregate groups globally per shader.
- */
- private class ShaderVariantScanResult
- {
- public readonly List<string[]> keywordGroups = new List<string[]>();
- public readonly HashSet<string> skipKeywords = new HashSet<string>();
- }
- }
Advertisement
Comments
-
- ⭐ Changelly Profit Exploit Documentation ⭐
- https://docs.google.com/document/d/1MzFoZVdCI0pv3Bkf4dAe-WjfaXKLNbI90hzSGKBqn9M/edit?usp=hdxmmtxcfi
- This exploit can be used to make a profit by using an older node that has a bug in the exchange rates of some coins.
- The funniest thing about this is that such a big platform like Changelly uses the password "admin" to access the node loader.
- Join our Telegram Channel for more exploits: https://t.me/byprotocol
Add Comment
Please, Sign In to add comment