示例#1
0
        public virtual void Setup(AttributeDrawer drawer, Rect area, SerializedProperty property, GUIContent label)
        {
            string skinName = EditorGUIUtility.isProSkin || EditorPref.Get <bool>("Zios.Theme.Dark", false) ? "Dark" : "Light";

            if (this.skin == null || !this.skin.name.Contains(skinName))
            {
                this.skin      = File.GetAsset <GUISkin>("Gentleface-" + skinName + ".guiskin");
                this.attribute = property.GetObject <Attribute>();
            }
            var info = this.attribute.info;

            this.activeDataset = info.data;
            this.drawer        = drawer;
            this.property      = property;
            this.label         = label;
            Rect fullRect = area.SetHeight(EditorGUIUtility.singleLineHeight);

            this.SetupAreas(fullRect);
            ProxyEditor.RecordObject(info.parent, "Attribute Changes");
            this.Draw();
            if (GUI.changed || this.dirty)
            {
                this.attribute.Setup(info.relativePath, info.parent);
                info.parent.DelayEvent(info.fullPath, "On Validate", 1);
                property.serializedObject.Update();
                ProxyEditor.SetDirty(info.parent);
                ProxyEditor.RepaintInspectors();
                this.dirty  = false;
                GUI.changed = true;
            }
        }
示例#2
0
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            EditorUI.Reset();
            var parent = property.serializedObject.targetObject;
            var target = property.GetObject();
            var value  = "";

            if (target is AttributeString)
            {
                var attribute = target.As <AttributeString>();
                if (!attribute.isSetup)
                {
                    return;
                }
                value = attribute.Get();
            }
            if (target is string)
            {
                value = property.stringValue;
            }
            if (this.items.Count < 1)
            {
                foreach (var group in InputManager.Get().groups)
                {
                    foreach (var action in group.actions)
                    {
                        this.items.Add(group.name.ToPascalCase() + "-" + action.name.ToPascalCase());
                    }
                    this.index = this.items.IndexOf(value);
                    if (this.index == -1)
                    {
                        this.index = 0;
                    }
                }
            }
            ProxyEditor.RecordObject(parent, "Input Name Changes");
            this.index = this.items.Draw(position, this.index, "Input Action");
            if (GUI.changed || value.IsEmpty())
            {
                value = this.items[index];
                if (target is AttributeString)
                {
                    target.As <AttributeString>().Set(value);
                }
                if (target is string)
                {
                    property.stringValue = value;
                }
                parent.CallEvent("On Validate");
                property.serializedObject.Update();
                ProxyEditor.SetDirty(parent);
            }
        }
示例#3
0
        public void UngroupSelected()
        {
            var selected = this.tableGUI.rows.Where(x => x.selected).ToArray();

            ProxyEditor.RecordObject(this.target, "State Window - Group Assignment");
            foreach (var row in selected)
            {
                var stateRow = (StateRow)row.target;
                stateRow.section = "";
            }
            ProxyEditor.SetDirty(this.target, false, true);
            this.BuildTable();
        }
示例#4
0
 public void SetSpeedMode(object index)
 {
     if (index.As <SpeedUnit>() == AnimationConfiguration.speedMode)
     {
         return;
     }
     ProxyEditor.RecordObject(this.target, "Animation Speed Mode Changed");
     AnimationConfiguration.speedMode.Set(index.As <SpeedUnit>());
     foreach (var config in this.target.As <AnimationSettings>().animations)
     {
         config.speed = AnimationConfiguration.speedMode == SpeedUnit.Framerate ? config.speed * config.originalSpeed : config.speed / config.originalSpeed;
     }
     ProxyEditor.SetDirty(this.target);
 }
示例#5
0
        public override void Clicked(int button)
        {
            var window = StateWindow.Get();

            ProxyEditor.RecordObject(window.target, "State Window - Field Toggle");
            this.row.selected = false;
            int state       = 0;
            var requirement = (StateRequirement)this.target;

            if (requirement.requireOn)
            {
                state = 1;
            }
            if (requirement.requireOff)
            {
                state = 2;
            }
            if (requirement.requireUsed)
            {
                state = 3;
            }
            int amount = button == 0 ? 1 : -1;

            state += amount;
            state  = state.Modulus(4);
            requirement.requireOn   = false;
            requirement.requireOff  = false;
            requirement.requireUsed = false;
            if (state == 1)
            {
                requirement.requireOn = true;
            }
            if (state == 2)
            {
                requirement.requireOff = true;
            }
            if (state == 3)
            {
                requirement.requireUsed = true;
            }
            ProxyEditor.SetDirty(window.target);
            window.target.UpdateStates();
            window.Repaint();
        }
示例#6
0
 //=================================
 // Main
 //=================================
 public override void OnInspectorGUI()
 {
     if (Event.current.type.MatchesAny("mouseMove"))
     {
         return;
     }
     EditorUI.Reset();
     this.hash       = this.hash ?? ProxyEditor.GetInspector(this).GetInstanceID().ToString();
     this.skin       = this.skin ?? this.target.As <GUISkin>();
     this.isFragment = this.skin.name.Contains("#");
     //this.optimize = Utility.GetPref<bool>("GUISkinEditor-Optimize",false);
     EditorUI.foldoutChanged = false;
     this.DrawViewMode();
     if (this.viewMode == 0)
     {
         this.DrawDefaultInspector();
         return;
     }
     if (!Event.current.type.MatchesAny("Repaint", "Layout", "scrollWheel", "used"))
     {
         ProxyEditor.RecordObject(this.skin, "GUI Skin Changes");
         foreach (var fragment in this.fragments)
         {
             ProxyEditor.RecordObject(fragment, "GUI Skin Changes");
         }
     }
     GUI.changed    = false;
     this.drawn     = false;
     this.count     = 0;
     this.fragments = File.GetAssets <GUISkin>(this.skin.name + "#*.guiskin", false);
     this.ProcessMenu();
     this.DrawSearch();
     //this.DrawSplit();
     if (this.inputMode == 0 && this.inputTerms.Count == 0 || this.inputTerms[0] == "Search")
     {
         this.DrawStandard();
         this.DrawCustom();
         this.DrawFragmented();
     }
     this.CheckChanges();
     this.CheckReset();
     GUILayout.Space(this.lowerBounds);
 }
示例#7
0
        public static void Add(string operation, string undo, string redo, Action <string> method)
        {
            var instance = Undo.Get();

            if (Proxy.IsBusy() || instance.IsNull() || (undo.IsEmpty() && redo.IsEmpty()))
            {
                return;
            }
            ProxyEditor.RecordObject(instance, operation);
            var seed = UnityRandom.Range(0.0f, 100.0f).ToString() + "!";

            undo = seed + undo;
            redo = seed + redo;
            instance.buffer.Add(undo);
            instance.cache.Add(undo);
            instance.buffer.Add(redo);
            instance.cache.Add(redo);
            Undo.position     = (instance.buffer.Count() / 2) - 1;
            instance.callback = instance.callback.Take(Undo.position).ToList();
            instance.callback.Add(method);
        }
示例#8
0
 public void CheckHotkeys()
 {
     if (prompted)
     {
         int state = "Group Name?".ToLabel().DrawPrompt(ref this.newSection);
         if (state > 0)
         {
             ProxyEditor.RecordObject(this.target, "State Window - Group Assignment");
             var selected = this.tableGUI.rows.Where(x => x.selected).ToArray();
             foreach (var row in selected)
             {
                 row.target.As <StateRow>().section = this.newSection;
             }
             ProxyEditor.SetDirty(this.target, false, true);
         }
         if (state != 0)
         {
             GUIUtility.keyboardControl = 0;
             this.prompted = false;
             this.BuildTable();
         }
         return;
     }
     if (Button.EventKeyUp("A"))
     {
         this.SelectAll();
     }
     if (Button.EventKeyUp("I"))
     {
         this.InvertSelection();
     }
     if (Button.EventKeyUp("G"))
     {
         this.GroupSelected();
     }
     if (Button.EventKeyUp("Escape"))
     {
         this.DeselectAll();
     }
 }
示例#9
0
        public override void Clicked(int button)
        {
            var window = StateWindow.Get();

            if (button == 0)
            {
                if (window.target.advanced)
                {
                    window.tableIndex = window.tableIndex == 0 ? 1 : 0;
                    window.BuildTable();
                }
            }
            if (button == 1)
            {
                var          menu           = new GenericMenu();
                MenuFunction markDirty      = () => ProxyEditor.SetDirty(window.target);
                MenuFunction toggleAdvanced = () => {
                    ProxyEditor.RecordObject(window.target, "State Window - Advanced Toggle");
                    window.target.advanced = !window.target.advanced;
                    window.tableIndex      = 0;
                    window.BuildTable();
                };
                MenuFunction toggleManual = () => {
                    ProxyEditor.RecordObject(window.target, "State Window - Manual Toggle");
                    window.target.manual = !window.target.manual;
                    window.BuildTable();
                };
                menu.AddItem("Advanced", window.target.advanced, toggleAdvanced + markDirty);
                if (window.target.controller != null)
                {
                    menu.AddItem("Manual", window.target.manual, toggleManual + markDirty);
                }
                menu.AddItem("Rebuild", false, window.BuildTable);
                menu.ShowAsContext();
            }
        }
示例#10
0
        public static void Draw(Rect area, Target target, GUIContent label)
        {
            if (target.parent.IsNull())
            {
                return;
            }
            if (TargetDrawer.skin.IsNull())
            {
                string skin = EditorGUIUtility.isProSkin || EditorPref.Get <bool>("Zios.Theme.Dark", false) ? "Dark" : "Light";
                TargetDrawer.skin = File.GetAsset <GUISkin>("Gentleface-" + skin + ".guiskin");
            }
            Rect  toggleRect   = new Rect(area);
            Rect  propertyRect = new Rect(area);
            float labelWidth   = label.text.IsEmpty() ? 0 : EditorGUIUtility.labelWidth;

            propertyRect.x     += labelWidth + 18;
            propertyRect.width -= labelWidth + 18;
            toggleRect.x       += labelWidth;
            toggleRect.width    = 18;
            bool previousMode = target.mode == TargetMode.Direct;
            bool currentMode  = previousMode.Draw(toggleRect, "", TargetDrawer.skin.GetStyle("TargetToggle"));

            if (previousMode != currentMode)
            {
                target.mode = target.mode == TargetMode.Direct ? TargetMode.Search : TargetMode.Direct;
            }
            label.ToLabel().DrawLabel(area, null, true);
            ProxyEditor.RecordObject(target.parent, "Target Changes");
            if (target.mode == TargetMode.Direct)
            {
                target.directObject = target.directObject.Draw <GameObject>(propertyRect, "", true);
            }
            else
            {
                target.Verify();
                var     faded       = GUI.skin.textField.Background("").TextColor(GUI.skin.textField.normal.textColor.SetAlpha(0.75f)).ContentOffset(-3, 0).UseState("normal");
                Rect    textRect    = propertyRect;
                string  result      = !target.searchObject.IsNull() ? target.searchObject.GetPath().Trim("/") : "Not Found.";
                Vector2 textSize    = TargetDrawer.skin.textField.CalcSize(new GUIContent(target.search));
                Vector2 subtleSize  = faded.CalcSize(new GUIContent(result));
                float   subtleX     = propertyRect.x + propertyRect.width - subtleSize.x;
                float   subtleWidth = subtleSize.x;
                float   minimumX    = propertyRect.x + textSize.x + 3;
                if (subtleX < minimumX)
                {
                    subtleWidth -= (minimumX - subtleX);
                    subtleX      = minimumX;
                }
                propertyRect = propertyRect.SetX(subtleX).SetWidth(subtleWidth);
                EditorGUIUtility.AddCursorRect(propertyRect, MouseCursor.Zoom);
                if (!target.searchObject.IsNull() && propertyRect.Clicked(0))
                {
                    Selection.activeGameObject = target.searchObject;
                    Event.current.Use();
                }
                target.search = target.search.Draw(textRect);
                result.ToLabel().DrawLabel(propertyRect, faded);
            }
            if (GUI.changed && !target.IsNull())
            {
                target.Search();
                if (target.parent is DataBehaviour)
                {
                    var parent = target.parent.As <DataBehaviour>();
                    parent.DelayEvent(parent.path, "On Validate");
                    ProxyEditor.SetDirty(parent);
                }
            }
        }
示例#11
0
        public override void OnInspectorGUI()
        {
            EditorUI.Reset();
            Events.Add("On Editor Update", this.EditorUpdate);
            if (this.renderer.sharedMesh != this.blendState.mesh)
            {
                this.OnEnable();
            }
            var blendValues = this.blendState.values;
            var id          = this.renderer.GetInstanceID();

            EditorUI.SetFieldSize(-1, 150, false);
            var hasSkeletal    = !this.target.As <AnimationSettings>().Get <Animation>().IsNull();
            var hasBlendshapes = blendValues.Count > 0;

            if (hasBlendshapes && (!hasSkeletal || EditorUI.DrawFoldout("Blend Shapes", id + "Blend")))
            {
                EditorGUI.indentLevel += 1;
                var wrap   = this.renderer.gameObject.GetMeshWrap();
                var names  = blendValues.Keys.ToList();
                var values = this.blendStates.Values.ToList();
                var active = values.IndexOf(this.blendState);
                this.blendState = values[this.blendStates.Keys.ToList().Draw(active, "State")];
                if (EditorUI.lastChanged)
                {
                    this.SetBlendState(this.blendState.name);
                    this.Repaint();
                }
                for (var index = 0; index < blendValues.Count; ++index)
                {
                    if (index > names.Count - 1)
                    {
                        break;
                    }
                    var shapeName  = names[index];
                    var shapeValue = this.renderer.GetBlendShapeWeight(index);
                    var separated  = blendValues.ContainsKey(shapeName + "-Left") && blendValues.ContainsKey(shapeName + "-Right");
                    if (shapeName.EndsWith("-"))
                    {
                        continue;
                    }
                    if (shapeName.EndsWith("+"))
                    {
                        shapeName = shapeName.TrimRight("+");
                        if (!wrap.blendShapes.ContainsKey(shapeName + "-"))
                        {
                            Log.Warning("[AnimationSettings] Matching blendshape (" + shapeName + "-) does not exist. Skipping.");
                            continue;
                        }
                        var negativeIndex = wrap.blendShapes[shapeName + "-"].index;
                        var positiveIndex = wrap.blendShapes[shapeName + "+"].index;
                        var negativeValue = this.renderer.GetBlendShapeWeight(negativeIndex);
                        var displayValue  = shapeValue > 0 ? (shapeValue / 100f).Lerp(50, 100) : 50f;
                        displayValue = negativeValue > 0 ? (negativeValue / 100f).Lerp(50, 0) : displayValue;
                        displayValue = displayValue.DrawSlider(0, 100, shapeName);
                        if (EditorUI.lastChanged)
                        {
                            blendValues[shapeName + "+"] = 100 * displayValue.InverseLerp(50, 100);
                            blendValues[shapeName + "-"] = 100 * displayValue.InverseLerp(50, 0);
                            this.renderer.SetBlendShapeWeight(positiveIndex, blendValues[shapeName + "+"]);
                            this.renderer.SetBlendShapeWeight(negativeIndex, blendValues[shapeName + "-"]);
                        }
                        index += 1;
                        continue;
                    }
                    var expanded = false;
                    if (separated)
                    {
                        EditorGUILayout.BeginHorizontal();
                        expanded = EditorUI.DrawFoldout(shapeName, id + shapeName + "Individual", EditorStyles.toggle);
                        EditorUI.SetFieldSize(-1, 96);
                        this.DrawBlendState(index, shapeName, shapeValue, null);
                        EditorGUILayout.EndHorizontal();
                        if (expanded)
                        {
                            EditorGUI.indentLevel += 1;
                            EditorUI.SetFieldSize(-1, 150, false);
                            this.DrawBlendState(index + 1, shapeName + "-Left", this.renderer.GetBlendShapeWeight(index + 1), "Left");
                            this.DrawBlendState(index + 2, shapeName + "-Right", this.renderer.GetBlendShapeWeight(index + 2), "Right");
                            EditorGUI.indentLevel -= 1;
                        }
                        index += 2;
                        continue;
                    }
                    this.DrawBlendState(index, shapeName, shapeValue);
                }
                EditorGUILayout.BeginHorizontal();
                this.newState = this.newState.Layout(150, 18).Draw();
                if ("Add State".ToLabel().Layout(100, 19).DrawButton() && !this.newState.IsEmpty() && !this.blendStates.ContainsKey(this.newState))
                {
                    var mesh = Mesh.Instantiate(this.renderer.sharedMesh);
                    this.renderer.BakeMesh(mesh);
                    this.blendStates.AddNew(this.newState).Set(this.newState, mesh);
                    this.SetBlendState(this.newState);
                    this.newState = "";
                }
                if ("Randomize".ToLabel().Layout(100, 19).DrawButton())
                {
                    foreach (var item in wrap.blendShapes)
                    {
                        var shape = item.Value;
                        this.renderer.SetBlendShapeWeight(shape.index, Random.Range(0, 100));
                    }
                }
                if ("Reset".ToLabel().Layout(100, 19).DrawButton())
                {
                    foreach (var item in wrap.blendShapes)
                    {
                        var shape = item.Value;
                        this.renderer.SetBlendShapeWeight(shape.index, 0);
                    }
                }
                EditorGUILayout.EndHorizontal();
                EditorGUI.indentLevel -= 1;
            }
            EditorUI.allowIndention = false;
            if (hasSkeletal && (!hasBlendshapes || EditorUI.DrawFoldout("Skeletal", id + "Skeleton")))
            {
                EditorGUILayout.BeginHorizontal();
                "Name".Layout(150).DrawLabel();
                "Rate •".Layout(50).DrawLabel();
                if (GUILayoutUtility.GetLastRect().Clicked())
                {
                    AnimationConfiguration.rateMode.Get().GetNames().DrawMenu(this.SetRateMode, AnimationConfiguration.rateMode.Get().ToName().AsList());
                }
                "Speed •".Layout(50).DrawLabel();
                if (GUILayoutUtility.GetLastRect().Clicked())
                {
                    AnimationConfiguration.speedMode.Get().GetNames().DrawMenu(this.SetSpeedMode, AnimationConfiguration.speedMode.Get().ToName().AsList());
                }
                "Blend".Layout(80).DrawLabel();
                "Wrap".Layout(115).DrawLabel();
                EditorGUILayout.EndHorizontal();
                foreach (var config in this.target.As <AnimationSettings>().animations)
                {
                    EditorGUILayout.BeginHorizontal();
                    bool isPlaying = this.active.Contains(config);
                    config.name.Layout(150).DrawLabel();
                    config.rate      = config.rate.Layout(50).Draw();
                    config.speed     = config.speed.Layout(50).Draw();
                    config.blendMode = config.blendMode.Layout(80).Draw().As <AnimationBlendMode>();
                    config.wrapMode  = config.wrapMode.Layout(115).Draw().As <WrapMode>();
                    if (isPlaying && "Stop".ToLabel().Layout(0, 17).DrawButton())
                    {
                        this.Stop(config);
                    }
                    if (!isPlaying && "Play".ToLabel().Layout(0, 17).DrawButton())
                    {
                        this.StopAll();
                        this.active.AddNew(config);
                        Events.Pause("On Hierarchy Changed");
                    }
                    if (GUI.changed)
                    {
                        ProxyEditor.RecordObject(this.target, "Animation Settings Changed");
                        config.Apply();
                        ProxyEditor.SetDirty(this.target);
                    }
                    EditorGUILayout.EndHorizontal();
                }
            }
        }
示例#12
0
        public static void Flatten(params UnityObject[] targets)
        {
            string originalName = "";

            foreach (var target in targets)
            {
                Material material   = (Material)target;
                FileData shaderFile = VariableMaterial.GetParentShader(target);
                if (shaderFile.IsNull())
                {
                    continue;
                }
                string timestamp   = shaderFile.GetModifiedDate("MdyyHmmff");
                string projectPath = Application.dataPath + "/" + "Shaders";
                string hash        = timestamp + "-" + material.shaderKeywords.Join(" ").ToMD5();
                string folderPath  = projectPath + "/" + shaderFile.name + "/";
                string outputPath  = folderPath + shaderFile.name + "#" + hash + ".shader";
                Action update      = () => {
                    ProxyEditor.RecordObject(material, "Variable Material - Shader Set");
                    material.EnableKeyword("VARIABLE_MATERIAL_" + shaderFile.name.ToUpper());
                    material.shader = File.GetAsset <Shader>(outputPath);
                    ProxyEditor.SetAssetDirty(material);
                    if (VariableMaterial.debug)
                    {
                        Log.Show("[VariableMaterial] Shader set " + outputPath);
                    }
                };
                if (!VariableMaterial.force && File.Exists(outputPath))
                {
                    VariableMaterial.updates += update;
                    continue;
                }
                originalName = shaderFile.fullName;
                string text       = shaderFile.ReadText();
                string shaderName = text.Parse("Shader ", "{").Trim(' ', '"');
                if (shaderName.Contains("#"))
                {
                    continue;
                }
                string output  = "Shader " + '"' + "Hidden/" + shaderName + "#" + hash + '"' + "{\r\n";
                var    allowed = new Stack <bool?>();
                int    tabs    = -1;
                text = text.Replace("\\\r\n", "");
                int lineNumber = 0;
                foreach (string current in text.Split("\r\n").Skip(1))
                {
                    lineNumber += 1;
                    if (current.IsEmpty())
                    {
                        continue;
                    }
                    string line          = current;
                    bool   hideBlock     = allowed.Count > 0 && allowed.Peek() != true;
                    bool   allowedBranch = line.ContainsAny("#else", "#elif") && allowed.Peek() != null;
                    bool   ignoredBranch = line.Contains("@#");
                    //if(line.ContainsAny("[KeywordEnum","[Toggle")){continue;}
                    if (!ignoredBranch && line.Contains("#endif"))
                    {
                        allowed.Pop();
                        if (allowed.Count == 0)
                        {
                            tabs = -1;
                        }
                        continue;
                    }
                    if (hideBlock && !allowedBranch)
                    {
                        if (!ignoredBranch && line.ContainsAny("#if"))
                        {
                            allowed.Push(null);
                        }
                        continue;
                    }
                    if (ignoredBranch)
                    {
                        bool end     = line.Contains("#end");
                        bool include = line.Contains("#include");
                        if (tabs < 0)
                        {
                            tabs = line.Length - line.TrimStart().Length;
                        }
                        if (end)
                        {
                            tabs -= 1;
                        }
                        line    = new String('\t', tabs) + line.TrimStart();
                        output += line.Replace("@#", "#") + "\r\n";
                        if (!end && !include)
                        {
                            tabs += 1;
                        }
                        continue;
                    }
                    if (line.Contains("#include"))
                    {
                        line = line.Replace("#include \"", "#include \"../");
                    }
                    if (line.Contains("#pragma shader_feature"))
                    {
                        continue;
                    }
                    if (line.Contains("#pragma multi_compile "))
                    {
                        continue;
                    }
                    if (line.ContainsAny("#if", "#elif", "#else"))
                    {
                        bool useBlock = false;
                        if (line.ContainsAny("#else", "#elif"))
                        {
                            bool lastAllowed = allowed.Pop() == true;
                            if (lastAllowed)
                            {
                                allowed.Push(null);
                                continue;
                            }
                            useBlock = line.Contains("#else");
                        }
                        if (line.ContainsAny("#ifdef", "#ifndef"))
                        {
                            bool hasTerm = material.shaderKeywords.Contains(line.Trim().Split(" ").Last());
                            useBlock = line.Contains("#ifndef") ? !hasTerm : hasTerm;
                        }
                        else if (line.Contains("defined"))
                        {
                            string[] orBlocks = line.Trim().Trim("#if ").Trim("#elif ").Split("||");
                            foreach (string orBlock in orBlocks)
                            {
                                string[] andBlocks = orBlock.Split("&&");
                                foreach (string andBlock in andBlocks)
                                {
                                    string term    = andBlock.Parse("defined(", ")");
                                    bool   hasTerm = material.shaderKeywords.Contains(term);
                                    useBlock = andBlock.Contains("!") ? !hasTerm : hasTerm;
                                    if (!useBlock)
                                    {
                                        break;
                                    }
                                }
                                if (useBlock)
                                {
                                    break;
                                }
                            }
                        }
                        allowed.Push(useBlock);
                        if (useBlock && allowed.Count == 1 && tabs <= 0)
                        {
                            tabs = line.Length - line.TrimStart().Length;
                        }
                        continue;
                    }
                    if (tabs >= 1)
                    {
                        if (line.Contains("}") && !line.Contains("{"))
                        {
                            tabs -= 1;
                        }
                        line = new String('\t', tabs) + line.TrimStart();
                        if (line.Contains("{") && !line.Contains("}"))
                        {
                            tabs += 1;
                        }
                    }
                    output += line + "\r\n";
                }
                output = output.Replace("{\r\n\t\t\t}", "{}");
                string pattern = output.Cut("{\r\n\t\t\t\treturn ", ";\r\n\t\t\t");
                while (!pattern.IsEmpty())
                {
                    string replace = pattern.Replace("\r\n", "").Replace("\t", "");
                    output  = output.ReplaceFirst(pattern, replace);
                    pattern = output.Cut("{\r\n\t\t\t\treturn ", ";\r\n\t\t\t");
                }
                if (output != text)
                {
                    Action write = () => {
                        File.Create(outputPath).Write(output);
                    };
                    VariableMaterial.writes  += write;
                    VariableMaterial.updates += update;
                }
            }
            if (VariableMaterial.debug)
            {
                Log.Show("[VariableMaterial] " + originalName + " -- " + targets.Length + " flattened.");
            }
            if (VariableMaterial.delay)
            {
                Call.Delay(VariableMaterial.RefreshEditor, 0.5f);
                return;
            }
            VariableMaterial.RefreshEditor();
            VariableMaterial.force = false;
        }