static bool CopyFiles(ref Asset asset, string location)
        {
            // Sanity
            DirectoryInfo dir = new DirectoryInfo(asset.path);

            if (!dir.Exists)
            {
                Console.WriteLine($"Could not find source directory {asset.path}");
                return(false);
            }

            // Create destination directories
            Directory.CreateDirectory(location);
            if (asset.geometry.Count > 0)
            {
                Directory.CreateDirectory($"{location}/geometry");
            }
            if (asset.textures.Count > 0)
            {
                Directory.CreateDirectory($"{location}/textures");
            }

            // TODO: remove repetition
            for (int i = 0; i < asset.geometry.Count; i++)
            {
                Geometry geometry    = asset.geometry[i];
                string   destination = geometry.path.Replace(asset.path, $"{location}/geometry");
                destination = Util.SanitizeProjectPath(destination, RunOptions.ProjectPath);
                Directory.CreateDirectory(Path.GetDirectoryName(destination));
                Console.WriteLine($"Copying geometry {geometry.path} -> {destination}");
                File.Copy(geometry.path, destination, true);
                geometry.path     = destination;
                geometry.name     = geometry.name.ToLower();
                asset.geometry[i] = geometry;
            }

            for (int i = 0; i < asset.lodList.Count; i++)
            {
                GeometryLOD lod         = asset.lodList[i];
                string      destination = lod.path.Replace(asset.path, $"{location}/geometry");
                destination = Util.SanitizeProjectPath(destination, RunOptions.ProjectPath);
                Directory.CreateDirectory(Path.GetDirectoryName(destination));
                Console.WriteLine($"Copying lod {lod.path} -> {destination}");
                File.Copy(lod.path, destination, true);
                lod.path         = destination;
                lod.name         = lod.name.ToLower();
                asset.lodList[i] = lod;
            }

            for (int i = 0; i < asset.textures.Count; i++)
            {
                Texture texture     = asset.textures[i];
                string  destination = texture.path.Replace(asset.path, $"{location}/textures");
                destination = Util.SanitizeProjectPath(destination, RunOptions.ProjectPath);
                Directory.CreateDirectory(Path.GetDirectoryName(destination));
                Console.WriteLine($"Copying texture {texture.path} -> {destination}");
                File.Copy(texture.path, destination, true);
                texture.path      = destination;
                texture.name      = texture.name.ToLower();
                asset.textures[i] = texture;
            }

            asset.path          = location;
            asset.name          = asset.name.ToLower();
            asset.directoryName = asset.directoryName.ToLower();
            asset.id            = asset.id.ToLower();

            return(true);
        }
        static Asset ImportMegascansAssets(JObject objectList)
        {
            Asset asset = new Asset();

            // Parsing asset properties.
            asset.name            = ( string )objectList["name"];
            asset.id              = ( string )objectList["id"];
            asset.type            = ( string )objectList["type"];
            asset.category        = ( string )objectList["category"];
            asset.path            = ( string )objectList["path"];
            asset.averageColor    = ( string )objectList["averageColor"];
            asset.activeLOD       = ( string )objectList["activeLOD"];
            asset.textureMimeType = ( string )objectList["textureFormat"];
            asset.meshVersion     = ( int )objectList["meshVersion"];
            asset.resolution      = ( string )objectList["resolution"];
            asset.resolutionValue = int.Parse(( string )objectList["resolutionValue"]);
            asset.isCustom        = ( bool )objectList["isCustom"];

            // Helpers
            string dirName = new DirectoryInfo(asset.path).Name;

            asset.directoryName = dirName;

            // Initializing asset component lists to avoid null reference error.
            asset.textures       = new List <Texture>();
            asset.geometry       = new List <Geometry>();
            asset.lodList        = new List <GeometryLOD>();
            asset.packedTextures = new List <PackedTextures>();
            asset.meta           = new List <MetaElement>();

            // Parse and store geometry list.
            JArray meshComps = (JArray)objectList["meshList"];

            foreach (JObject obj in meshComps)
            {
                Geometry geo = new Geometry();
                geo.name   = ( string )obj["name"];
                geo.path   = ( string )obj["path"];
                geo.type   = ( string )obj["type"];
                geo.format = ( string )obj["format"];

                asset.geometry.Add(geo);
            }

            // Parse and store LOD list.
            JArray lodComps = (JArray)objectList["lodList"];

            foreach (JObject obj in lodComps)
            {
                GeometryLOD geo = new GeometryLOD();
                geo.name   = ( string )obj["name"];
                geo.path   = ( string )obj["path"];
                geo.type   = ( string )obj["type"];
                geo.format = ( string )obj["format"];
                geo.lod    = ( string )obj["lod"];

                asset.lodList.Add(geo);
            }

            // Parse and store meta data list.
            JArray metaData = (JArray)objectList["meta"];

            foreach (JObject obj in metaData)
            {
                MetaElement mElement = new MetaElement();
                mElement.name = ( string )obj["name"];
                mElement.key  = ( string )obj["key"];

                // Something weird is happening with booleans
                if (obj["value"].Type == JTokenType.Boolean)
                {
                    mElement.value = ( bool )obj["value"];
                }
                else
                {
                    mElement.value = ( object )obj["value"];
                }

                asset.meta.Add(mElement);
            }

            // Parse and store textures list.
            JArray textureComps = (JArray)objectList["components"];

            foreach (JObject obj in textureComps)
            {
                Texture tex = new Texture();
                tex.name       = ( string )obj["name"];
                tex.path       = ( string )obj["path"];
                tex.type       = ( string )obj["type"];
                tex.format     = ( string )obj["format"];
                tex.resolution = ( string )obj["resolution"];

                asset.textures.Add(tex);
            }

            // Parse and store channel packed textures list.
            JArray packedTextureComps = (JArray)objectList["packedTextures"];

            foreach (JObject obj in packedTextureComps)
            {
                PackedTextures tex = new PackedTextures();
                tex.name       = ( string )obj["name"];
                tex.path       = ( string )obj["path"];
                tex.type       = ( string )obj["type"];
                tex.format     = ( string )obj["format"];
                tex.resolution = ( string )obj["resolution"];

                tex.channelsData.Red.type          = ( string )obj["channelsData"]["Red"][0];
                tex.channelsData.Red.channel       = ( string )obj["channelsData"]["Red"][1];
                tex.channelsData.Green.type        = ( string )obj["channelsData"]["Green"][0];
                tex.channelsData.Green.channel     = ( string )obj["channelsData"]["Green"][1];
                tex.channelsData.Blue.type         = ( string )obj["channelsData"]["Blue"][0];
                tex.channelsData.Blue.channel      = ( string )obj["channelsData"]["Blue"][1];
                tex.channelsData.Alpha.type        = ( string )obj["channelsData"]["Alpha"][0];
                tex.channelsData.Alpha.channel     = ( string )obj["channelsData"]["Alpha"][1];
                tex.channelsData.Grayscale.type    = ( string )obj["channelsData"]["Grayscale"][0];
                tex.channelsData.Grayscale.channel = ( string )obj["channelsData"]["Grayscale"][1];

                asset.packedTextures.Add(tex);
            }

            // Parse and store categories list.
            JArray categories = (JArray)objectList["categories"];

            asset.categories = new string[categories.Count];
            for (int i = 0; i < categories.Count; ++i)
            {
                asset.categories[i] = ( string )categories[i];
            }

            // Parse and store tags list.
            JArray tags = (JArray)objectList["tags"];

            asset.tags = new string[tags.Count];
            for (int i = 0; i < tags.Count; ++i)
            {
                asset.tags[i] = ( string )tags[i];
            }

            return(asset);
        }