/// <summary>
        /// Gets an animation by name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="Files">The file system.</param>
        /// <returns>The animation.</returns>
        public SingleAnimation GetAnimation(string name, FileEngine Files)
        {
            string namelow = name.ToLowerFast();

            if (Animations.TryGetValue(namelow, out SingleAnimation sa))
            {
                return(sa);
            }
            try
            {
                sa = LoadAnimation(namelow, Files);
                Animations.Add(sa.Name, sa);
                return(sa);
            }
            catch (Exception ex)
            {
                SysConsole.Output(OutputType.ERROR, "Loading an animation: " + ex.ToString());
                sa = new SingleAnimation()
                {
                    Name = namelow, Length = 1, Engine = this
                };
                Animations.Add(sa.Name, sa);
                return(sa);
            }
        }
 /// <summary>
 /// Loads an animation by name.
 /// </summary>
 /// <param name="name">The name.</param>
 /// <param name="Files">The file system.</param>
 /// <returns>The animation.</returns>
 SingleAnimation LoadAnimation(string name, FileEngine Files)
 {
     if (Files.TryReadFileText("animations/" + name + ".anim", out string fileText))
     {
         SingleAnimation created = new SingleAnimation()
         {
             Name = name
         };
         string[] data = fileText.SplitFast('\n');
         int      entr = 0;
         for (int i = 0; i < data.Length; i++)
         {
             if (data[i].StartsWith("//"))
             {
                 continue;
             }
             string type = data[i];
             if (data.Length <= i + 1 || data[i + 1] != "{")
             {
                 break;
             }
             List <KeyValuePair <string, string> > entries = new List <KeyValuePair <string, string> >();
             for (i += 2; i < data.Length; i++)
             {
                 if (data[i].Trim().StartsWith("//"))
                 {
                     continue;
                 }
                 if (data[i] == "}")
                 {
                     break;
                 }
                 string[] dat = data[i].SplitFast(':');
                 if (dat.Length <= 1)
                 {
                     SysConsole.Output(OutputType.WARNING, "Invalid key dat: " + dat[0]);
                 }
                 else
                 {
                     string key   = dat[0].Trim();
                     string value = dat[1].Substring(0, dat[1].Length - 1).Trim();
                     entries.Add(new KeyValuePair <string, string>(key, value));
                 }
             }
             bool isgeneral           = type == "general" && entr == 0;
             SingleAnimationNode node = null;
             if (!isgeneral)
             {
                 node = new SingleAnimationNode()
                 {
                     Name = type.ToLowerFast()
                 };
             }
             foreach (KeyValuePair <string, string> entry in entries)
             {
                 if (isgeneral)
                 {
                     if (entry.Key == "length")
                     {
                         created.Length = StringConversionHelper.StringToDouble(entry.Value);
                     }
                     else
                     {
                         SysConsole.Output(OutputType.WARNING, "Unknown GENERAL key: " + entry.Key);
                     }
                 }
                 else
                 {
                     if (entry.Key == "positions")
                     {
                         string[] poses = entry.Value.SplitFast(' ');
                         for (int x = 0; x < poses.Length; x++)
                         {
                             if (poses[x].Length > 0)
                             {
                                 string[] posdata = poses[x].SplitFast('=');
                                 node.PosTimes.Add(StringConversionHelper.StringToDouble(posdata[0]));
                                 node.Positions.Add(new Location(StringConversionHelper.StringToFloat(posdata[1]),
                                                                 StringConversionHelper.StringToFloat(posdata[2]), StringConversionHelper.StringToFloat(posdata[3])));
                             }
                         }
                     }
                     else if (entry.Key == "rotations")
                     {
                         string[] rots = entry.Value.SplitFast(' ');
                         for (int x = 0; x < rots.Length; x++)
                         {
                             if (rots[x].Length > 0)
                             {
                                 string[] posdata = rots[x].SplitFast('=');
                                 node.RotTimes.Add(StringConversionHelper.StringToDouble(posdata[0]));
                                 node.Rotations.Add(new BEPUutilities.Quaternion(StringConversionHelper.StringToFloat(posdata[1]), StringConversionHelper.StringToFloat(posdata[2]),
                                                                                 StringConversionHelper.StringToFloat(posdata[3]), StringConversionHelper.StringToFloat(posdata[4])));
                             }
                         }
                     }
                     else if (entry.Key == "parent")
                     {
                         node.ParentName = entry.Value.ToLowerFast();
                     }
                     else if (entry.Key == "offset")
                     {
                         string[] posdata = entry.Value.SplitFast('=');
                         node.Offset = new Location(StringConversionHelper.StringToFloat(posdata[0]),
                                                    StringConversionHelper.StringToFloat(posdata[1]), StringConversionHelper.StringToFloat(posdata[2]));
                     }
                     else
                     {
                         SysConsole.Output(OutputType.WARNING, "Unknown NODE key: " + entry.Key);
                     }
                 }
             }
             if (!isgeneral)
             {
                 created.Nodes.Add(node);
                 created.node_map.Add(node.Name, node);
             }
             entr++;
         }
         foreach (SingleAnimationNode node in created.Nodes)
         {
             for (int i = 0; i < created.Nodes.Count; i++)
             {
                 if (created.Nodes[i].Name == node.ParentName)
                 {
                     node.Parent = created.Nodes[i];
                     break;
                 }
             }
         }
         created.Engine = this;
         return(created);
     }
     else
     {
         throw new Exception("Invalid animation file - file not found: animations/" + name + ".anim");
     }
 }