コード例 #1
0
ファイル: Up.cs プロジェクト: WildGenie/actools
        private void UPinit()
        {
            if (!_up)
            {
                _up = true;

                _l = new Kn5RenderableList(Kn5Node.CreateBaseNode("L"), null)
                {
                    LocalMatrix    = Matrix.Translation(_swRadius, 0, _swOffset),
                    HighlightDummy = true
                };
                _r = new Kn5RenderableList(Kn5Node.CreateBaseNode("R"), null)
                {
                    LocalMatrix    = Matrix.Translation(-_swRadius, 0, _swOffset),
                    HighlightDummy = true
                };

                _dbg0 = new Kn5RenderableList(Kn5Node.CreateBaseNode("debug"), null)
                {
                    HighlightDummy = true
                };

                _dbg1 = new Kn5RenderableList(Kn5Node.CreateBaseNode("debug"), null)
                {
                    HighlightDummy = true
                };

                //_steer.Add(_l);
                //_steer.Add(_r);

                _la = new Arm(_driver, true);
                _ra = new Arm(_driver, false);
            }
        }
コード例 #2
0
        public static Mat4x4 CalculateTransformRelativeToParent(this Kn5Node child, Kn5Node root)
        {
            var mat = new Mat4x4();

            if (!TraverseDown(root, Mat4x4.Identity, ref mat))
            {
                throw new Exception("Failed to traverse down");
            }
            return(mat);

            bool TraverseDown(Kn5Node node, Mat4x4 m, ref Mat4x4 r)
            {
                foreach (var c in node.Children)
                {
                    if (c == child)
                    {
                        r = m;
                        return(true);
                    }
                    if (c.NodeClass == Kn5NodeClass.Base)
                    {
                        if (TraverseDown(c, c.Transform * m, ref r))
                        {
                            return(true);
                        }
                    }
                }
                return(false);
            }
        }
コード例 #3
0
ファイル: Kn5Fixer.cs プロジェクト: WildGenie/actools
 private static bool FixLrHrNodes_HasChild(Kn5Node node, Kn5Node child)
 {
     if (node.NodeClass != Kn5NodeClass.Base)
     {
         return(false);
     }
     return(node.Children.Contains(child) || node.Children.Any(subNode => FixLrHrNodes_HasChild(subNode, child)));
 }
コード例 #4
0
 public Kn5RenderableDepthOnlyObject(Kn5Node node, bool forceVisible = false) : base(node.Name, Convert(node.Vertices), Convert(node.Indices))
 {
     OriginalNode = node;
     if (IsEnabled && (!node.Active || !forceVisible && (!node.IsVisible || !node.IsRenderable)))
     {
         IsEnabled = false;
     }
 }
コード例 #5
0
 public int MergeGroup(Kn5Node node, double priority)
 {
     if (_mergeAsBlack?.Any(x => x.Test(node)) == true)
     {
         node.MaterialId = uint.MaxValue;
         return(priority.GetHashCode());
     }
     return((((int)node.MaterialId * 397) | (node.IsTransparent ? 1 << 31 : 0) | (node.CastShadows ? 1 << 30 : 0)) ^ priority.GetHashCode());
 }
コード例 #6
0
ファイル: Kn5MeshUtils.cs プロジェクト: tankyx/actools
        public static Aabb3 CalculateAabb3(this Kn5Node mesh, Kn5Node relativeTo)
        {
            var transform = mesh.CalculateTransformRelativeToParent(relativeTo);
            var aabb      = Aabb3.CreateNew();

            foreach (var v in mesh.Vertices)
            {
                aabb.Extend(Vec3.Transform(v.Position, transform));
            }
            return(aabb);
        }
コード例 #7
0
 public bool HasParentWithSameName([NotNull] Kn5Node node)
 {
     for (var parent = _filterContext.GetParent(node); parent != null; parent = _filterContext.GetParent(parent))
     {
         if (parent.Name == node.Name)
         {
             return(true);
         }
     }
     return(false);
 }
コード例 #8
0
        public Kn5RenderableList(Kn5Node node, Func <Kn5Node, IRenderableObject> convert)
            : base(node.Name, node.Transform.ToMatrix(), node.Children.Count == 0 ? new IRenderableObject[0] : node.Children.Select(convert))
        {
            OriginalNode = node;
            if (IsEnabled && (!OriginalNode.Active || OriginalNode.Name == "CINTURE_ON" || OriginalNode.Name.StartsWith("DAMAGE_GLASS")))
            {
                IsEnabled = false;
            }

            if (node.Name.StartsWith("DIR_"))
            {
                _dirNode = node.Name.Substring(4);
            }
        }
コード例 #9
0
        private static void FixSuspensionNodes(Kn5 kn5)
        {
            foreach (var name in SuspensionNodes.Where(name => kn5.FirstByName(name) == null))
            {
                var node  = Kn5Node.CreateBaseNode(name);
                var wheel = kn5.FirstByName(name.Replace("SUSP", "WHEEL"))?.Transform;
                if (wheel != null)
                {
                    node.Transform = wheel;
                }

                kn5.RootNode.Children.Add(node);
            }
        }
コード例 #10
0
        public static IRenderableObject Convert(Kn5Node node)
        {
            switch (node.NodeClass)
            {
            case Kn5NodeClass.Base:
                return(new Kn5RenderableList(node, Convert));

            case Kn5NodeClass.Mesh:
            case Kn5NodeClass.SkinnedMesh:
                return(new Kn5RenderableDepthOnlyObject(node));

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
コード例 #11
0
 public static Kn5Node FindFirst(this Kn5Node parent, string name)
 {
     foreach (var child in parent.Children)
     {
         if (child.Name == name)
         {
             return(child);
         }
         var ret = child.FindFirst(name);
         if (ret != null)
         {
             return(ret);
         }
     }
     return(null);
 }
コード例 #12
0
        public Kn5RenderableObject(Kn5Node node) : base(node.Name, Convert(node.Vertices), Convert(node.Indices))
        {
            OriginalNode     = node;
            IsCastingShadows = node.CastShadows;

            if (IsEnabled && (!OriginalNode.Active || !OriginalNode.IsVisible || !OriginalNode.IsRenderable))
            {
                IsEnabled = false;
            }

            if (OriginalNode.IsTransparent || OriginalNode.Layer == 1 /* WHAT? WHAT DOES IT DO? BUT KUNOS PREVIEWS SHOWROOM WORKS THIS WAY, SO… */)
            {
                IsReflectable = false;
            }

            _isTransparent   = OriginalNode.IsTransparent;
            _distanceFromSqr = OriginalNode.LodIn.Pow(2f);
            _distanceToSqr   = OriginalNode.LodOut.Pow(2f);
        }
コード例 #13
0
 private static void FixVertices(Kn5Node node, Matrix parentMatrix)
 {
     if (node.NodeClass == Kn5NodeClass.Base)
     {
         var localMatrix = node.Transform.ToMatrix() * parentMatrix;
         foreach (var child in node.Children)
         {
             FixVertices(child, localMatrix);
         }
     }
     else
     {
         var normal = Vector3.TransformNormal(Vector3.UnitY, Matrix.Invert(parentMatrix));
         for (var i = 0; i < node.Vertices.Length; i++)
         {
             FixVertice(ref node.Vertices[i], normal);
         }
     }
 }
コード例 #14
0
        private static void MergeMeshes(Kn5Node root, List <Tuple <Kn5Node, double, Mat4x4> > children, CarLodGeneratorMergeRules mergeRules,
                                        CarLodGeneratorStageParams stage)
        {
            if (children.Count == 0)
            {
                return;
            }

            var mesh            = children[0].Item1;
            var priority        = children[0].Item2;
            var considerDetails = mesh.MaterialId != uint.MaxValue;
            var builder         = new Kn5MeshBuilder(considerDetails, considerDetails);
            // AcToolsLogging.Write($"Merging together: {children.Select(x => $"{x.Item1.Name} [{x.Item2}]").JoinToString(", ")}");

            var extraCounter = 0;

            foreach (var child in children)
            {
                var transform = child.Item3 * Mat4x4.CreateScale(new Vec3((float)priority)) * Mat4x4.CreateTranslation(MoveAsideDistance(priority, stage));
                var offset    = mergeRules.GetOffsetAlongNormal(child.Item1);
                for (var i = 0; i < child.Item1.Indices.Length; ++i)
                {
                    builder.AddVertex(child.Item1.Vertices[child.Item1.Indices[i]].Transform(transform, offset));
                    if (i % 3 == 2 && builder.IsCloseToLimit)
                    {
                        builder.SetTo(mesh);
                        root.Children.Add(mesh);
                        mesh.Tag = priority;

                        builder.Clear();
                        mesh = Kn5MeshUtils.Create(children[0].Item1.Name + $"___$extra:{extraCounter}", children[0].Item1.MaterialId);
                        ++extraCounter;
                    }
                }
            }

            if (builder.Count > 0)
            {
                builder.SetTo(mesh);
                root.Children.Add(mesh);
                mesh.Tag = priority;
            }
        }
コード例 #15
0
        protected static IRenderableObject Convert(Kn5Node node, bool allowSkinnedObjects)
        {
            switch (node.NodeClass)
            {
            case Kn5NodeClass.Base:
                return(new Kn5RenderableList(node, n => Convert(n, allowSkinnedObjects)));

            case Kn5NodeClass.Mesh:
                return(new Kn5RenderableObject(node));

            case Kn5NodeClass.SkinnedMesh:
                if (allowSkinnedObjects)
                {
                    return(new Kn5SkinnedObject(node));
                }
                return(new Kn5RenderableObject(node));

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
コード例 #16
0
        static void PrintNode(Kn5Node node, int spaces = 0)
        {
            for (var i = -1; i < spaces; i++)
            {
                Console.Write(@"  ");
            }

            if (node.NodeClass == Kn5NodeClass.Base)
            {
                Console.WriteLine(@"{0}:", node.Name);

                foreach (var child in node.Children)
                {
                    PrintNode(child, spaces + 1);
                }
            }
            else
            {
                Console.WriteLine(@"{0}", node.Name);
            }
        }
コード例 #17
0
ファイル: Kn5Fixer.cs プロジェクト: Abishai2007/actools
        public static bool FixSuspension(string acRoot, string carName)
        {
            var kn5File = FileUtils.GetMainCarFilename(acRoot, carName);

            var kn5   = Kn5.FromFile(kn5File);
            var added = 0;

            foreach (var name in new [] { "SUSP_LF", "SUSP_RF", "SUSP_LR", "SUSP_RR" }.Where(name => kn5.FirstByName(name) == null))
            {
                kn5.RootNode.Children.Add(Kn5Node.CreateBaseNode(name));
                added++;
            }

            if (added == 0)
            {
                return(false);
            }

            kn5.SaveRecyclingOriginal(kn5File);
            return(true);
        }
コード例 #18
0
ファイル: Kn5Fixer.cs プロジェクト: WildGenie/actools
        private static bool FixLrHrNodes_HasParentWithName(Kn5Node rootNode, Kn5Node node, string name)
        {
            if (rootNode.NodeClass != Kn5NodeClass.Base)
            {
                return(false);
            }

            foreach (var subNode in rootNode.Children)
            {
                if (subNode.Name == name)
                {
                    return(FixLrHrNodes_HasChild(subNode, node));
                }
                else if (FixLrHrNodes_HasParentWithName(subNode, node, name))
                {
                    return(true);
                }
            }

            return(false);
        }
コード例 #19
0
ファイル: Kn5MeshUtils.cs プロジェクト: tankyx/actools
        public static void RecalculateTangents(this Kn5Node mesh)
        {
            var vertexCount   = mesh.Vertices.Length;
            var triangleCount = mesh.Indices.Length / 3;
            var tan1          = new Vec3[vertexCount];
            var tan2          = new Vec3[vertexCount];

            for (long a = 0; a < triangleCount; a++)
            {
                var i1   = mesh.Indices[a * 3];
                var i2   = mesh.Indices[a * 3 + 1];
                var i3   = mesh.Indices[a * 3 + 2];
                var v1   = mesh.Vertices[i1];
                var v2   = mesh.Vertices[i2];
                var v3   = mesh.Vertices[i3];
                var x1   = v2.Position.X - v1.Position.X;
                var x2   = v3.Position.X - v1.Position.X;
                var y1   = v2.Position.Y - v1.Position.Y;
                var y2   = v3.Position.Y - v1.Position.Y;
                var z1   = v2.Position.Z - v1.Position.Z;
                var z2   = v3.Position.Z - v1.Position.Z;
                var s1   = v2.Tex.X - v1.Tex.X;
                var s2   = v3.Tex.X - v1.Tex.X;
                var t1   = v2.Tex.Y - v1.Tex.Y;
                var t2   = v3.Tex.Y - v1.Tex.Y;
                var r    = 1f / (s1 * t2 - s2 * t1);
                var sdir = new Vec3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
                var tdir = new Vec3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);
                tan1[i1] += sdir;
                tan1[i2] += sdir;
                tan1[i3] += sdir;
                tan2[i1] += tdir;
                tan2[i2] += tdir;
                tan2[i3] += tdir;
            }
            for (long a = 0; a < vertexCount; a++)
            {
                mesh.Vertices[a].Tangent = Vec3.Normalize(tan1[a] - mesh.Vertices[a].Normal * Vec3.Dot(mesh.Vertices[a].Normal, tan1[a]));
            }
        }
コード例 #20
0
        private void GetObject(Kn5Node node, Matrix matrix)
        {
            if ((!node.Active || node.Name == "CINTURE_ON") && _mode != VisualMode.TRACK_MAP)
            {
                return;
            }

            if (node.NodeClass == Kn5NodeClass.Base)
            {
                matrix = ToMatrix(node.Transform) * matrix;
                foreach (var child in node.Children)
                {
                    GetObject(child, matrix);
                }

                switch (node.Name)
                {
                case "WHEEL_LF":
                    _wheelLfPos = new Vector3(matrix.M41, matrix.M42, matrix.M43);
                    break;

                case "WHEEL_RF":
                    _wheelRfPos = new Vector3(matrix.M41, matrix.M42, matrix.M43);
                    break;

                case "WHEEL_LR":
                    _wheelLrPos = new Vector3(matrix.M41, matrix.M42, matrix.M43);
                    break;

                case "WHEEL_RR":
                    _wheelRrPos = new Vector3(matrix.M41, matrix.M42, matrix.M43);
                    break;
                }
            }
            else if (_mode == VisualMode.TRACK_MAP || node.IsRenderable)
            {
                GetMeshObject(node, matrix);
            }
        }
コード例 #21
0
ファイル: Kn5SkinnedObject.cs プロジェクト: WildGenie/actools
        public Kn5SkinnedObject(Kn5Node node) : base(node.Name, Convert(node.Vertices, node.VerticeWeights), Convert(node.Indices))
        {
            OriginalNode     = node;
            IsCastingShadows = node.CastShadows;

            if (IsEnabled && (!OriginalNode.Active || !OriginalNode.IsVisible || !OriginalNode.IsRenderable))
            {
                IsEnabled = false;
            }

            if (OriginalNode.IsTransparent || OriginalNode.Layer == 1 /* WHAT? WHAT DOES IT DO? BUT KUNOS PREVIEWS SHOWROOM WORKS THIS WAY, SO… */)
            {
                IsReflectable = false;
            }

            _bonesTransform = node.Bones.Select(x => x.Transform.ToMatrix()).ToArray();
            _bones          = _bonesTransform.ToArray();

            _isTransparent   = OriginalNode.IsTransparent;
            _distanceFromSqr = OriginalNode.LodIn.Pow(2f);
            _distanceToSqr   = OriginalNode.LodOut.Pow(2f);
        }
コード例 #22
0
        public static IEnumerable <Kn5Node> AllChildren([CanBeNull] this Kn5Node parent)
        {
            var queue = new Queue <Kn5Node>();

            if (parent != null)
            {
                queue.Enqueue(parent);
            }

            while (queue.Count > 0)
            {
                var next = queue.Dequeue();
                if (next.NodeClass == Kn5NodeClass.Base)
                {
                    foreach (var child in next.Children)
                    {
                        queue.Enqueue(child);
                    }
                }
                yield return(next);
            }
        }
コード例 #23
0
ファイル: Program.cs プロジェクト: Cimmerian-Iter/actools
        private static IEnumerable <Kn5Node> FilterNodes(IKn5 kn5, IFilter <string> filter, Kn5Node node)
        {
            if (node.NodeClass == Kn5NodeClass.Base)
            {
                return(node.Children.SelectMany(x => FilterNodes(kn5, filter, x)));
            }

            if (!filter.Test(node.Name) ||
                kn5.GetMaterial(node.MaterialId)?.TextureMappings.Any(x => x.Name == "txNormal" || x.Name == "txNormalDetail") != false)
            {
                return(new Kn5Node[0]);
            }

            return(new[] { node });
        }
コード例 #24
0
        private static async Task PrepareForGenerationAsync(Kn5NodeFilterContext filterContext, IKn5 kn5, CarLodGeneratorStageParams stage, bool printNodes)
        {
            var mergeRules  = new CarLodGeneratorMergeRules(filterContext, stage);
            var toMerge     = new Dictionary <Kn5Node, List <Tuple <Kn5Node, double, Mat4x4> > >();
            var nodeIndices = new Dictionary <Kn5Node, int>();

            MergeNode(kn5.RootNode, kn5.RootNode, 1d);
            foreach (var pair in toMerge)
            {
                var mergeData = pair.Value.GroupBy(x => mergeRules.MergeGroup(x.Item1, x.Item2))
                                .OrderBy(v => mergeRules.GroupOrder(kn5, v, nodeIndices)).Select(v => v.ToList()).ToList();
                await Task.Run(() => {
                    foreach (var group in mergeData)
                    {
                        MergeMeshes(pair.Key, group, mergeRules, stage);
                    }
                });
            }
            foreach (var node in kn5.Nodes.Where(x => x.Children?.Count > 1).ToList())
            {
                var meshesList = node.Children
                                 .Where(x => x.NodeClass != Kn5NodeClass.Base)
                                 .Select((x, i) => new { x, i = OrderIndex(x, i) })
                                 .OrderBy(x => x.i)
                                 .Select(x => x.x).ToList();
                if (meshesList.Count > 0)
                {
                    if (node.Children.Any(x => x.NodeClass == Kn5NodeClass.Base))
                    {
                        node.Children = node.Children.Where(x => x.NodeClass == Kn5NodeClass.Base)
                                        .Prepend(Kn5Node.CreateBaseNode($"__{meshesList[0].Name}_wrap_", meshesList, true))
                                        .Select((x, i) => new { x, i = OrderIndex(x, i) })
                                        .OrderBy(x => x.i)
                                        .Select(x => x.x).ToList();
                    }
                    else
                    {
                        node.Children = meshesList;
                    }
                }
            }
            if (printNodes)
            {
                PrintNode(kn5.RootNode, 0, 0);
            }
            mergeRules.FinalizeKn5(kn5);

            var duplicateNames = kn5.Nodes.GroupBy(x => $"{x.NodeClass}/{x.Name}")
                                 .Select(x => x.ToList()).Where(x => x.Count > 1).ToList();

            foreach (var group in duplicateNames)
            {
                AcToolsLogging.Write($"Duplicate name: {group[0].Name} ({group[0].NodeClass})");
                foreach (var toRename in group.Skip(1).Select((x, i) => new { x, i }))
                {
                    toRename.x.Name = $"{toRename.x.Name}___$unique:{toRename.i}";
                }
            }

            int OrderIndex(Kn5Node node, int index)
            {
                return(index + (AnyTransparent(node) ? 1 << 10 : 0));
            }

            void PrintNode(Kn5Node node, int level, int index)
            {
                var postfix = node.NodeClass == Kn5NodeClass.Base ? "" :
                              $"{(node.IsTransparent ? ", transparent" : "")}, material: {kn5.GetMaterial(node.MaterialId)?.Name}";

                AcToolsLogging.Write(
                    $"{new string('\t', level)}{node.Name} [{node.NodeClass}{postfix}, index: {OrderIndex(node, index)}, aabb: {filterContext.GetAabb3(node)}]");
                if (node.NodeClass == Kn5NodeClass.Base)
                {
                    for (var i = 0; i < node.Children.Count; i++)
                    {
                        PrintNode(node.Children[i], level + 1, i);
                    }
                }
            }

            bool AnyTransparent(Kn5Node node)
            {
                return(node.NodeClass == Kn5NodeClass.Base
                        ? node.Children.Any(AnyTransparent)
                        : node.IsTransparent || kn5.GetMaterial(node.MaterialId)?.BlendMode == Kn5MaterialBlendMode.AlphaBlend);
            }

            void ApplyPriority(Kn5Node mesh, double priority)
            {
                var offset = MoveAsideDistance(priority, stage);

                for (var i = 0; i < mesh.Vertices.Length; i++)
                {
                    Apply(ref mesh.Vertices[i]);
                }
                mesh.Tag = priority;

                void Apply(ref Kn5Node.Vertex v)
                {
                    v.Position[0] = v.Position[0] * (float)priority + offset.X;
                    v.Position[1] = v.Position[1] * (float)priority + offset.Y;
                    v.Position[2] = v.Position[2] * (float)priority + offset.Z;
                }
            }

            bool MergeNode(Kn5Node node, Kn5Node mergeRoot, double priority)
            {
                nodeIndices[node] = nodeIndices.Count;

                if (node != mergeRoot)
                {
                    if (mergeRules.CanSkipNode(node))
                    {
                        if (node.NodeClass == Kn5NodeClass.Base && !mergeRules.HasParentWithSameName(node) && !mergeRules.CanRemoveEmptyNode(node))
                        {
                            node.Children.Clear();
                            return(true);
                        }
                        return(false);
                    }

                    var priorityAdjustment = mergeRules.CalculateReductionPriority(node);
                    if (priorityAdjustment != 1d && (priorityAdjustment < priority || priority == 1d || node.NodeClass == Kn5NodeClass.Mesh))
                    {
                        priority = priorityAdjustment;
                    }

                    if (node.NodeClass == Kn5NodeClass.Mesh)
                    {
                        if (mergeRoot != null && mergeRules.CanMerge(node))
                        {
                            if (!toMerge.ContainsKey(mergeRoot))
                            {
                                toMerge[mergeRoot] = new List <Tuple <Kn5Node, double, Mat4x4> >();
                            }
                            toMerge[mergeRoot].Add(Tuple.Create(node, priority, node.CalculateTransformRelativeToParent(mergeRoot)));
                            return(false);
                        }
                        if (priority != 1d)
                        {
                            ApplyPriority(node, priority);
                        }
                        return(true);
                    }

                    if (node.NodeClass == Kn5NodeClass.SkinnedMesh)
                    {
                        return(true);
                    }

                    if (mergeRoot != null)
                    {
                        if (!mergeRules.CanMerge(node))
                        {
                            mergeRoot = null;
                        }
                        else if (node.Name != mergeRoot.Name && mergeRules.IsNodeMergeRoot(node))
                        {
                            mergeRoot = node;
                        }
                    }
                }

                for (var i = 0; i < node.Children.Count; ++i)
                {
                    if (!MergeNode(node.Children[i], mergeRoot, priority))
                    {
                        node.Children.RemoveAt(i);
                        --i;
                    }
                }

                return(node.Children.Count > 0 || mergeRoot == node || !mergeRules.CanRemoveEmptyNode(node));
            }
        }
コード例 #25
0
 public bool CanRemoveEmptyNode(Kn5Node node)
 {
     return(_emptyNodesToKeep?.Any(x => x.Test(node)) != true);
 }
コード例 #26
0
 public bool IsNodeMergeRoot(Kn5Node node)
 {
     return(_mergeParents?.Any(x => x.Test(node)) == true);
 }
コード例 #27
0
 public bool CanMerge(Kn5Node node)
 {
     return(_mergeExceptions?.Any(x => x.Test(node)) != true);
 }
コード例 #28
0
 public bool CanSkipNode(Kn5Node node)
 {
     return(node.NodeClass == Kn5NodeClass.SkinnedMesh ||
            node.NodeClass == Kn5NodeClass.Mesh && !node.IsRenderable ||
            _elementToRemove?.Any(x => x.Test(node)) == true);
 }
コード例 #29
0
 public double GetOffsetAlongNormal(Kn5Node node)
 {
     return(_offsetsAlongNormal?.FirstOrDefault(x => x.Item1.Test(node))?.Item2 ?? 0d);
 }
コード例 #30
0
 public double CalculateReductionPriority(Kn5Node node)
 {
     return(_elementPriorities?.FirstOrDefault(x => x.Item1.Test(node))?.Item2 ?? 1d);
 }
コード例 #31
0
ファイル: Kn5_Save.cs プロジェクト: gro-ove/actools
 private static void Save_Node(Kn5Writer writer, Kn5Node node) {
     writer.Write(node);
     foreach (var t in node.Children) {
         Save_Node(writer, t);
     }
 }