一款基于卡牌的塔防游戏,类似于 Supercell 的《皇室战争》的游戏玩法(简化形式), 可以与“非智能”AI 进行比赛。
您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

338 行
15 KiB

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEditor.Experimental.AssetImporters;
using UnityEditor.Graphing;
using UnityEditor.Graphing.Util;
using UnityEditor.Rendering;
using UnityEngine;
namespace UnityEditor.ShaderGraph
{
[ScriptedImporter(1, ".sgsubgraphdb", 2)]
class SubGraphDatabaseImporter : ScriptedImporter
{
public const string path = "Packages/com.unity.shadergraph/Editor/Importers/_.sgsubgraphdb";
public override void OnImportAsset(AssetImportContext ctx)
{
var currentTime = DateTime.Now.Ticks;
if (ctx.assetPath != path)
{
ctx.LogImportError("The sgpostsubgraph extension may only be used internally by Shader Graph.");
return;
}
if (SubGraphDatabase.instance == null)
{
SubGraphDatabase.instance = ScriptableObject.CreateInstance<SubGraphDatabase>();
}
var database = SubGraphDatabase.instance;
var allSubGraphGuids = AssetDatabase.FindAssets($"t:{nameof(SubGraphAsset)}").ToList();
allSubGraphGuids.Sort();
var subGraphMap = new Dictionary<string, SubGraphData>();
var graphDataMap = new Dictionary<string, GraphData>();
foreach (var subGraphData in database.subGraphs)
{
if (allSubGraphGuids.BinarySearch(subGraphData.assetGuid) >= 0)
{
subGraphMap.Add(subGraphData.assetGuid, subGraphData);
}
}
var dirtySubGraphGuids = new List<string>();
foreach (var subGraphGuid in allSubGraphGuids)
{
var subGraphAsset = AssetDatabase.LoadAssetAtPath<SubGraphAsset>(AssetDatabase.GUIDToAssetPath(subGraphGuid));
if (!subGraphMap.TryGetValue(subGraphGuid, out var subGraphData))
{
subGraphData = new SubGraphData();
}
if (subGraphAsset.importedAt > subGraphData.processedAt)
{
dirtySubGraphGuids.Add(subGraphGuid);
subGraphData.Reset();
subGraphData.processedAt = currentTime;
var subGraphPath = AssetDatabase.GUIDToAssetPath(subGraphGuid);
var textGraph = File.ReadAllText(subGraphPath, Encoding.UTF8);
var graphData = new GraphData { isSubGraph = true, assetGuid = subGraphGuid };
JsonUtility.FromJsonOverwrite(textGraph, graphData);
subGraphData.children.AddRange(graphData.GetNodes<SubGraphNode>().Select(x => x.subGraphGuid).Distinct());
subGraphData.assetGuid = subGraphGuid;
subGraphMap[subGraphGuid] = subGraphData;
graphDataMap[subGraphGuid] = graphData;
}
else
{
subGraphData.ancestors.Clear();
subGraphData.descendents.Clear();
subGraphData.isRecursive = false;
}
}
database.subGraphs.Clear();
database.subGraphs.AddRange(subGraphMap.Values);
database.subGraphs.Sort((s1, s2) => s1.assetGuid.CompareTo(s2.assetGuid));
database.subGraphGuids.Clear();
database.subGraphGuids.AddRange(database.subGraphs.Select(x => x.assetGuid));
var permanentMarks = new HashSet<string>();
var stack = new Stack<string>(allSubGraphGuids.Count);
// Detect recursion, and populate `ancestors` and `descendents` per sub graph.
foreach (var rootSubGraphData in database.subGraphs)
{
var rootSubGraphGuid = rootSubGraphData.assetGuid;
stack.Push(rootSubGraphGuid);
while (stack.Count > 0)
{
var subGraphGuid = stack.Pop();
if (!permanentMarks.Add(subGraphGuid))
{
continue;
}
var subGraphData = subGraphMap[subGraphGuid];
if (subGraphData != rootSubGraphData)
{
subGraphData.ancestors.Add(rootSubGraphGuid);
rootSubGraphData.descendents.Add(subGraphGuid);
}
foreach (var childSubGraphGuid in subGraphData.children)
{
if (childSubGraphGuid == rootSubGraphGuid)
{
rootSubGraphData.isRecursive = true;
}
else
{
stack.Push(childSubGraphGuid);
}
}
}
permanentMarks.Clear();
}
// Next up we build a list of sub graphs to be processed, which will later be sorted topologically.
var sortedSubGraphs = new List<SubGraphData>();
foreach (var subGraphGuid in dirtySubGraphGuids)
{
var subGraphData = subGraphMap[subGraphGuid];
if (permanentMarks.Add(subGraphGuid))
{
sortedSubGraphs.Add(subGraphData);
}
// Note that we're traversing up the graph via ancestors rather than descendents, because all Sub Graphs using the current sub graph needs to be re-processed.
foreach (var ancestorGuid in subGraphData.ancestors)
{
if (permanentMarks.Add(ancestorGuid))
{
var ancestorSubGraphData = subGraphMap[ancestorGuid];
sortedSubGraphs.Add(ancestorSubGraphData);
}
}
}
permanentMarks.Clear();
// Sort topologically. At this stage we can assume there are no loops because all recursive sub graphs have been filtered out.
sortedSubGraphs.Sort((s1, s2) => s1.descendents.Contains(s2.assetGuid) ? 1 : s2.descendents.Contains(s1.assetGuid) ? -1 : 0);
// Finally process the topologically sorted sub graphs without recursion.
var registry = new FunctionRegistry(new ShaderStringBuilder(), true);
var messageManager = new MessageManager();
foreach (var subGraphData in sortedSubGraphs)
{
try
{
var subGraphPath = AssetDatabase.GUIDToAssetPath(subGraphData.assetGuid);
if (!graphDataMap.TryGetValue(subGraphData.assetGuid, out var graphData))
{
var textGraph = File.ReadAllText(subGraphPath, Encoding.UTF8);
graphData = new GraphData { isSubGraph = true, assetGuid = subGraphData.assetGuid };
JsonUtility.FromJsonOverwrite(textGraph, graphData);
}
graphData.messageManager = messageManager;
ProcessSubGraph(subGraphMap, registry, subGraphData, graphData);
if (messageManager.nodeMessagesChanged)
{
var subGraphAsset = AssetDatabase.LoadAssetAtPath<SubGraphAsset>(AssetDatabase.GUIDToAssetPath(subGraphData.assetGuid));
foreach (var pair in messageManager.GetNodeMessages())
{
var node = graphData.GetNodeFromTempId(pair.Key);
foreach (var message in pair.Value)
{
MessageManager.Log(node, subGraphPath, message, subGraphAsset);
}
}
}
}
catch (Exception e)
{
subGraphData.isValid = false;
var subGraphAsset = AssetDatabase.LoadAssetAtPath<SubGraphAsset>(AssetDatabase.GUIDToAssetPath(subGraphData.assetGuid));
Debug.LogException(e, subGraphAsset);
}
finally
{
subGraphData.processedAt = currentTime;
messageManager.ClearAll();
}
}
// Carry over functions used by sub-graphs that were not re-processed in this import.
foreach (var subGraphData in database.subGraphs)
{
foreach (var functionName in subGraphData.functionNames)
{
if (!registry.sources.ContainsKey(functionName))
{
registry.sources.Add(functionName, database.functionSources[database.functionNames.BinarySearch(functionName)]);
}
}
}
var functions = registry.sources.ToList();
functions.Sort((p1, p2) => p1.Key.CompareTo(p2.Key));
database.functionNames.Clear();
database.functionSources.Clear();
foreach (var pair in functions)
{
database.functionNames.Add(pair.Key);
database.functionSources.Add(pair.Value);
}
ctx.AddObjectToAsset("MainAsset", database);
ctx.SetMainObject(database);
SubGraphDatabase.instance = null;
}
static void ProcessSubGraph(Dictionary<string, SubGraphData> subGraphMap, FunctionRegistry registry, SubGraphData subGraphData, GraphData graph)
{
registry.names.Clear();
subGraphData.functionNames.Clear();
subGraphData.nodeProperties.Clear();
subGraphData.isValid = true;
graph.OnEnable();
graph.messageManager.ClearAll();
graph.ValidateGraph();
var assetPath = AssetDatabase.GUIDToAssetPath(subGraphData.assetGuid);
subGraphData.hlslName = NodeUtils.GetHLSLSafeName(Path.GetFileNameWithoutExtension(assetPath));
subGraphData.inputStructName = $"Bindings_{subGraphData.hlslName}_{subGraphData.assetGuid}";
subGraphData.functionName = $"SG_{subGraphData.hlslName}_{subGraphData.assetGuid}";
subGraphData.path = graph.path;
var outputNode = (SubGraphOutputNode)graph.outputNode;
subGraphData.outputs.Clear();
outputNode.GetInputSlots(subGraphData.outputs);
List<AbstractMaterialNode> nodes = new List<AbstractMaterialNode>();
NodeUtils.DepthFirstCollectNodesFromNode(nodes, outputNode);
subGraphData.effectiveShaderStage = ShaderStageCapability.All;
foreach (var slot in subGraphData.outputs)
{
var stage = NodeUtils.GetEffectiveShaderStageCapability(slot, true);
if (stage != ShaderStageCapability.All)
{
subGraphData.effectiveShaderStage = stage;
break;
}
}
subGraphData.requirements = ShaderGraphRequirements.FromNodes(nodes, subGraphData.effectiveShaderStage, false);
subGraphData.inputs = graph.properties.ToList();
foreach (var node in nodes)
{
if (node.hasError)
{
subGraphData.isValid = false;
registry.ProvideFunction(subGraphData.functionName, sb => { });
return;
}
}
foreach (var node in nodes)
{
if (node is SubGraphNode subGraphNode)
{
var nestedData = subGraphMap[subGraphNode.subGraphGuid];
foreach (var functionName in nestedData.functionNames)
{
registry.names.Add(functionName);
}
}
else if (node is IGeneratesFunction generatesFunction)
{
generatesFunction.GenerateNodeFunction(registry, new GraphContext(subGraphData.inputStructName), GenerationMode.ForReals);
}
}
registry.ProvideFunction(subGraphData.functionName, sb =>
{
var graphContext = new GraphContext(subGraphData.inputStructName);
GraphUtil.GenerateSurfaceInputStruct(sb, subGraphData.requirements, subGraphData.inputStructName);
sb.AppendNewLine();
// Generate arguments... first INPUTS
var arguments = new List<string>();
foreach (var prop in subGraphData.inputs)
arguments.Add(string.Format("{0}", prop.GetPropertyAsArgumentString()));
// now pass surface inputs
arguments.Add(string.Format("{0} IN", subGraphData.inputStructName));
// Now generate outputs
foreach (var output in subGraphData.outputs)
arguments.Add($"out {output.concreteValueType.ToString(outputNode.precision)} {output.shaderOutputName}");
// Create the function prototype from the arguments
sb.AppendLine("void {0}({1})"
, subGraphData.functionName
, arguments.Aggregate((current, next) => $"{current}, {next}"));
// now generate the function
using (sb.BlockScope())
{
// Just grab the body from the active nodes
var bodyGenerator = new ShaderGenerator();
foreach (var node in nodes)
{
if (node is IGeneratesBodyCode)
(node as IGeneratesBodyCode).GenerateNodeCode(bodyGenerator, graphContext, GenerationMode.ForReals);
}
foreach (var slot in subGraphData.outputs)
bodyGenerator.AddShaderChunk($"{slot.shaderOutputName} = {outputNode.GetSlotValue(slot.id, GenerationMode.ForReals)};");
sb.Append(bodyGenerator.GetShaderString(1));
}
});
subGraphData.functionNames.AddRange(registry.names.Distinct());
var collector = new PropertyCollector();
subGraphData.nodeProperties = collector.properties;
foreach (var node in nodes)
{
node.CollectShaderProperties(collector, GenerationMode.ForReals);
}
subGraphData.OnBeforeSerialize();
}
}
}