Пример #1
0
            protected override void UpgradeAsset(AssetMigrationContext context, PackageVersion currentVersion, PackageVersion targetVersion, dynamic asset, PackageLoadingAssetFile assetFile)
            {
                // SerializedVersion format changed during renaming upgrade. However, before this was merged back in master, some asset upgrader still with older version numbers were developed.
                // As a result, sprite component upgrade is not needed for version 19 and 20, and physics component upgrade is not needed for version 20
                var version19 = PackageVersion.Parse("0.0.19");
                var version20 = PackageVersion.Parse("0.0.20");

                var hierarchy = asset.Hierarchy;
                var entities  = (DynamicYamlArray)hierarchy.Entities;

                foreach (dynamic entity in entities)
                {
                    var components      = entity.Entity.Components;
                    var spriteComponent = components["SpriteComponent.Key"];
                    if (spriteComponent != null && (currentVersion != version19 && currentVersion != version20))
                    {
                        var color = spriteComponent.Color;
                        spriteComponent.Color = DynamicYamlExtensions.ConvertFrom((Color4)DynamicYamlExtensions.ConvertTo <Color>(color));
                    }

                    var physComponent = components["PhysicsComponent.Key"];
                    if (physComponent != null && (currentVersion != version20))
                    {
                        foreach (dynamic element in physComponent.Elements)
                        {
                            if (element.Node.Tag == "!TriggerElement")
                            {
                                element.Node.Tag  = "!StaticColliderElement";
                                element.IsTrigger = true;
                            }
                        }
                    }
                }
            }
            protected override void UpgradeAsset(AssetMigrationContext context, PackageVersion currentVersion, PackageVersion targetVersion, dynamic asset, PackageLoadingAssetFile assetFile, OverrideUpgraderHint overrideHint)
            {
                if (asset.ColliderShapes == null)
                {
                    return;
                }

                foreach (var colliderShape in asset.ColliderShapes)
                {
                    if (colliderShape.Node.Tag == "!Box2DColliderShapeDesc")
                    {
                        var size = 2f * DynamicYamlExtensions.ConvertTo <Vector2>(colliderShape.HalfExtent);
                        colliderShape.Size       = DynamicYamlExtensions.ConvertFrom(size);
                        colliderShape.HalfExtent = DynamicYamlEmpty.Default;
                    }
                    if (colliderShape.Node.Tag == "!BoxColliderShapeDesc")
                    {
                        var size = 2f * DynamicYamlExtensions.ConvertTo <Vector3>(colliderShape.HalfExtents);
                        colliderShape.Size        = DynamicYamlExtensions.ConvertFrom(size);
                        colliderShape.HalfExtents = DynamicYamlEmpty.Default;
                    }
                    if (colliderShape.Node.Tag == "!CapsuleColliderShapeDesc" || colliderShape.Node.Tag == "!CylinderColliderShapeDesc")
                    {
                        var upVector = DynamicYamlExtensions.ConvertTo <Vector3>(colliderShape.UpAxis);
                        if (upVector == Vector3.UnitX)
                        {
                            colliderShape.Orientation = ShapeOrientation.UpX;
                        }
                        if (upVector == Vector3.UnitZ)
                        {
                            colliderShape.Orientation = ShapeOrientation.UpZ;
                        }

                        colliderShape.UpAxis = DynamicYamlEmpty.Default;
                    }
                    if (colliderShape.Node.Tag == "!CapsuleColliderShapeDesc" && colliderShape.Height != null)
                    {
                        colliderShape.Length = 2f * (float)colliderShape.Height;
                        colliderShape.Height = DynamicYamlEmpty.Default;
                    }
                    if (colliderShape.Node.Tag == "!CylinderColliderShapeDesc")
                    {
                        colliderShape.Radius      = (float)colliderShape.HalfExtents.X;
                        colliderShape.Height      = 2f * (float)colliderShape.HalfExtents.Y;
                        colliderShape.HalfExtents = DynamicYamlEmpty.Default;
                    }
                }
            }
Пример #3
0
            protected override void UpgradeAsset(AssetMigrationContext context, int currentVersion, int targetVersion, dynamic asset, PackageLoadingAssetFile assetFile)
            {
                var hierarchy = asset.Hierarchy;
                var entities  = (DynamicYamlArray)hierarchy.Entities;

                foreach (dynamic entity in entities)
                {
                    var components      = entity.Entity.Components;
                    var spriteComponent = components["SpriteComponent.Key"];
                    if (spriteComponent != null)
                    {
                        var color = spriteComponent.Color;
                        spriteComponent.Color = DynamicYamlExtensions.ConvertFrom((Color4)DynamicYamlExtensions.ConvertTo <Color>(color));
                    }
                }
            }
Пример #4
0
        public override bool Upgrade(PackageSession session, ILogger log, Package dependentPackage, PackageDependency dependency, Package dependencyPackage, IList <PackageLoadingAssetFile> assetFiles)
        {
            if (dependency.Version.MinVersion < new PackageVersion("1.5.0-alpha01"))
            {
                RunAssetUpgradersUntilVersion(log, dependentPackage, XenkoConfig.PackageName, assetFiles, PackageVersion.Parse("1.5.0-alpha01"));
            }

            if (dependency.Version.MinVersion < new PackageVersion("1.5.0-alpha02"))
            {
                // Ideally, this should be part of asset upgrader but we can't upgrade multiple assets at once yet

                var modelAssets = assetFiles.Where(f => f.FilePath.GetFileExtension() == ".xkm3d").Select(x => x.AsYamlAsset()).ToArray();
                var animAssets  = assetFiles.Where(f => f.FilePath.GetFileExtension() == ".xkanim").Select(x => x.AsYamlAsset()).ToArray();
                var sceneAssets = assetFiles.Where(f => f.FilePath.GetFileExtension() == ".xkscene").Select(x => x.AsYamlAsset()).ToArray();

                // Select models with at least two nodes
                var modelAssetsWithSekeleton = modelAssets
                                               .Where(model => ((IEnumerable)model.DynamicRootNode.Nodes).Cast <object>().Count() > 1).ToArray();

                var animToModelMapping = new Dictionary <PackageLoadingAssetFile.YamlAsset, PackageLoadingAssetFile.YamlAsset>();

                // Find associations in scene
                foreach (var sceneAsset in sceneAssets)
                {
                    var hierarchy = sceneAsset.DynamicRootNode.Hierarchy;
                    foreach (dynamic entity in hierarchy.Entities)
                    {
                        var components         = entity.Entity.Components;
                        var animationComponent = components["AnimationComponent.Key"];
                        var model = components["ModelComponent.Key"]?.Model;
                        if (animationComponent != null && model != null)
                        {
                            var modelReference = DynamicYamlExtensions.ConvertTo <AssetReference>(model);
                            var modelAsset     = modelAssetsWithSekeleton.FirstOrDefault(x => x.Asset.AssetPath == modelReference.Location);

                            foreach (var animation in animationComponent.Animations)
                            {
                                var animationReference = DynamicYamlExtensions.ConvertTo <AssetReference>(animation.Value);
                                var animationAsset     = animAssets.FirstOrDefault(x => x.Asset.AssetPath == animationReference.Location);

                                if (modelAsset != null && animationAsset != null)
                                {
                                    animToModelMapping[animationAsset] = modelAsset;
                                }
                            }
                        }
                    }
                }

                // Find associations when sharing same source file
                foreach (var animationAsset in animAssets)
                {
                    // Comparing absolute path of assets
                    var modelAsset = modelAssetsWithSekeleton.FirstOrDefault(
                        x => UPath.Combine(animationAsset.Asset.AssetPath.GetParent(), new UFile((string)animationAsset.DynamicRootNode.Source))
                        == UPath.Combine(x.Asset.AssetPath.GetParent(), new UFile((string)x.DynamicRootNode.Source)));
                    if (modelAsset != null)
                    {
                        animToModelMapping[animationAsset] = modelAsset;
                    }
                }

                var modelToSkeletonMapping = new Dictionary <PackageLoadingAssetFile.YamlAsset, PackageLoadingAssetFile.YamlAsset>();

                // For each model asset, create skeleton assets
                foreach (var modelAsset in modelAssetsWithSekeleton)
                {
                    var skeletonAsset = new PackageLoadingAssetFile(modelAsset.Asset.FilePath.GetFullPathWithoutExtension() + " Skeleton.xkskel", modelAsset.Asset.SourceFolder)
                    {
                        AssetContent = System.Text.Encoding.UTF8.GetBytes("!Skeleton\r\nId: " + Guid.NewGuid())
                    };

                    using (var skeletonAssetYaml = skeletonAsset.AsYamlAsset())
                    {
                        // Set source
                        skeletonAssetYaml.DynamicRootNode.Source     = modelAsset.DynamicRootNode.Source;
                        skeletonAssetYaml.DynamicRootNode.SourceHash = modelAsset.DynamicRootNode.SourceHash;

                        // To be on the safe side, mark everything as preserved
                        var nodes = modelAsset.DynamicRootNode.Nodes;
                        foreach (var node in nodes)
                        {
                            node.Preserve = true;
                        }

                        skeletonAssetYaml.DynamicRootNode.Nodes       = nodes;
                        skeletonAssetYaml.DynamicRootNode.ScaleImport = modelAsset.DynamicRootNode.ScaleImport;

                        // Update model to point to this skeleton
                        modelAsset.DynamicRootNode.Skeleton = new AssetReference(AssetId.Parse((string)skeletonAssetYaml.DynamicRootNode.Id), skeletonAsset.AssetPath.MakeRelative(modelAsset.Asset.AssetPath.GetParent()));
                        modelToSkeletonMapping.Add(modelAsset, skeletonAssetYaml);
                    }

                    assetFiles.Add(skeletonAsset);
                }

                // Update animation to point to skeleton, and set preview default model
                foreach (var animToModelEntry in animToModelMapping)
                {
                    var animationAsset = animToModelEntry.Key;
                    var modelAsset     = animToModelEntry.Value;

                    var skeletonAsset = modelToSkeletonMapping[modelAsset];
                    animationAsset.DynamicRootNode.Skeleton     = new AssetReference(AssetId.Parse((string)skeletonAsset.DynamicRootNode.Id), skeletonAsset.Asset.AssetPath.MakeRelative(animationAsset.Asset.AssetPath.GetParent()));
                    animationAsset.DynamicRootNode.PreviewModel = new AssetReference(AssetId.Parse((string)modelAsset.DynamicRootNode.Id), modelAsset.Asset.AssetPath.MakeRelative(animationAsset.Asset.AssetPath.GetParent()));
                }

                // Remove Nodes from models
                foreach (var modelAsset in modelAssets)
                {
                    modelAsset.DynamicRootNode.Nodes = DynamicYamlEmpty.Default;
                    modelAsset.DynamicRootNode["~Base"].Asset.Nodes = DynamicYamlEmpty.Default;
                }

                // Save back
                foreach (var modelAsset in modelAssets)
                {
                    modelAsset.Dispose();
                }
                foreach (var animAsset in animAssets)
                {
                    animAsset.Dispose();
                }
            }

            if (dependency.Version.MinVersion < new PackageVersion("1.6.0-beta"))
            {
                // Delete EffectLogAsset
                foreach (var assetFile in assetFiles)
                {
                    if (assetFile.FilePath.GetFileName() == EffectLogAsset.DefaultFile)
                    {
                        assetFile.Deleted = true;
                    }
                }
            }

            if (dependency.Version.MinVersion < new PackageVersion("1.7.0-alpha02"))
            {
                foreach (var assetFile in assetFiles)
                {
                    if (!IsYamlAsset(assetFile))
                    {
                        continue;
                    }

                    using (var assetYaml = assetFile.AsYamlAsset())
                    {
                        if (assetYaml == null)
                        {
                            continue;
                        }

                        var sourceNode     = assetYaml.DynamicRootNode.Source;
                        var sourceHashNode = assetYaml.DynamicRootNode.SourceHash;
                        if (sourceHashNode != null)
                        {
                            var source     = DynamicYamlExtensions.ConvertTo <UFile>(sourceNode);
                            var sourceHash = DynamicYamlExtensions.ConvertTo <ObjectId>(sourceHashNode);
                            var dictionary = new Dictionary <UFile, ObjectId> {
                                { source, sourceHash }
                            };
                            var yamlDic = DynamicYamlExtensions.ConvertFrom(dictionary);
                            yamlDic.Node.Tag = null;
                            assetYaml.DynamicRootNode["~SourceHashes"] = yamlDic;
                            assetYaml.DynamicRootNode.SourceHash       = DynamicYamlEmpty.Default;
                        }
                        assetYaml.DynamicRootNode.ImporterId           = DynamicYamlEmpty.Default;
                        assetYaml.DynamicRootNode.SourceKeepSideBySide = DynamicYamlEmpty.Default;

                        var assetBase = assetYaml.DynamicRootNode["~Base"];
                        if (assetBase != null)
                        {
                            if (assetBase.Location == "--import--")
                            {
                                assetYaml.DynamicRootNode["~Base"] = DynamicYamlEmpty.Default;
                            }
                        }
                    }
                }
            }

            //Audio refactor
            if (dependency.Version.MinVersion < new PackageVersion("1.7.0-alpha03"))
            {
                var audioAssets = assetFiles.Where(f => f.FilePath.GetFileExtension() == ".xksnd").Select(x => x.AsYamlAsset()).ToArray();
                foreach (var assetFile in audioAssets)
                {
                    //dispose will save back
                    using (var assetYaml = assetFile)
                    {
                        if (assetYaml == null)
                        {
                            continue;
                        }

                        if (assetYaml.RootNode.Tag == "!SoundMusic")
                        {
                            assetYaml.RootNode.Tag = "!Sound";
                            assetYaml.DynamicRootNode.Spatialized    = false;
                            assetYaml.DynamicRootNode.StreamFromDisk = true;
                        }
                        else
                        {
                            assetYaml.RootNode.Tag = "!Sound";
                            assetYaml.DynamicRootNode.Spatialized    = true;
                            assetYaml.DynamicRootNode.StreamFromDisk = false;
                        }
                    }
                }
            }

            if (dependency.Version.MinVersion < new PackageVersion("1.7.0-alpha03"))
            {
                // Delete EffectLogAsset (now, most of it is auto generated automatically by drawing one frame of the game)
                foreach (var assetFile in assetFiles)
                {
                    if (assetFile.FilePath.GetFileName() == EffectLogAsset.DefaultFile)
                    {
                        assetFile.Deleted = true;
                    }
                }
            }

            if (dependency.Version.MinVersion < new PackageVersion("1.8.4-beta"))
            {
                // Add new generic parameter of MaterialSurfaceNormalMap to effect logs
                var regex = new Regex(@"(?<=ClassName:\s+MaterialSurfaceNormalMap\s+GenericArguments:\s+\[[^\]]*)(?=\])");
                foreach (var assetFile in assetFiles.Where(f => f.FilePath.GetFileExtension() == ".xkeffectlog"))
                {
                    var filePath = assetFile.FilePath;

                    // Load asset data, so the renamed file will have it's AssetContent set
                    if (assetFile.AssetContent == null)
                    {
                        assetFile.AssetContent = File.ReadAllBytes(filePath);
                    }

                    var sourceText      = System.Text.Encoding.UTF8.GetString(assetFile.AssetContent);
                    var newSourceText   = regex.Replace(sourceText, ", true");
                    var newAssetContent = System.Text.Encoding.UTF8.GetBytes(newSourceText);

                    if (newSourceText != sourceText)
                    {
                        assetFile.AssetContent = newAssetContent;
                    }

                    //File.WriteAllBytes(newFileName, newAssetContent);
                }
            }

            if (dependency.Version.MinVersion < new PackageVersion("1.9.0-beta"))
            {
                foreach (var assetFile in assetFiles)
                {
                    if (!IsYamlAsset(assetFile))
                    {
                        continue;
                    }

                    // This upgrader will also mark every yaml asset as dirty. We want to re-save everything with the new serialization system
                    using (var assetYaml = assetFile.AsYamlAsset())
                    {
                        if (assetYaml == null)
                        {
                            continue;
                        }

                        try
                        {
                            if (assetYaml.DynamicRootNode["~Base"] != null)
                            {
                                var location = ((YamlScalarNode)assetYaml.DynamicRootNode["~Base"].Location.Node).Value;
                                if (location != "--import--")
                                {
                                    var id       = ((YamlScalarNode)assetYaml.DynamicRootNode["~Base"].Asset.Id.Node).Value;
                                    var assetUrl = $"{id}:{location}";
                                    assetYaml.DynamicRootNode["Archetype"] = assetUrl;
                                }
                                assetYaml.DynamicRootNode["~Base"] = DynamicYamlEmpty.Default;
                            }
                        }
                        catch
                        (Exception e)
                        {
                            e.Ignore();
                        }
                    }
                }
            }

            return(true);
        }
Пример #5
0
        public override bool Upgrade(PackageSession session, ILogger log, Package dependentPackage, PackageDependency dependency, Package dependencyPackage, IList <PackageLoadingAssetFile> assetFiles)
        {
            // Paradox 1.1 projects didn't have their dependency properly updated (they might have been marked as 1.0).
            // We know they are 1.1 only because there is a .props file.
            // This check shouldn't be necessary from 1.2.
            var packagePath   = dependentPackage.FullPath;
            var propsFilePath = UPath.Combine(packagePath.GetParent(), (UFile)(packagePath.GetFileName() + ".props"));

            if (!File.Exists(propsFilePath) && dependency.Version.MinVersion < new PackageVersion("1.1.0-beta"))
            {
                log.Error("Can't upgrade old projects from {0} 1.0 to 1.1", dependency.Name);
                return(false);
            }

            // Nothing to do for now, most of the work is already done by individual asset upgraders
            // We can later add logic here for package-wide upgrades (i.e. GameSettingsAsset)
            if (dependency.Version.MinVersion < new PackageVersion("1.2.0-beta"))
            {
                // UIImageGroups and SpriteGroups asset have been merged into a single SpriteSheet => rename the assets and modify the tag
                var uiImageGroups = assetFiles.Where(f => f.FilePath.GetFileExtension() == ".pdxuiimage");
                var spritesGroups = assetFiles.Where(f => f.FilePath.GetFileExtension() == ".pdxsprite");
                RenameAndChangeTag(assetFiles, uiImageGroups, "!UIImageGroup");
                RenameAndChangeTag(assetFiles, spritesGroups, "!SpriteGroup");
            }

            if (dependency.Version.MinVersion < new PackageVersion("1.3.0-alpha01"))
            {
                // Create GameSettingsAsset
                GameSettingsAsset.UpgraderVersion130.Upgrade(session, log, dependentPackage, dependency, dependencyPackage, assetFiles);
            }

            if (dependency.Version.MinVersion < new PackageVersion("1.3.0-alpha02"))
            {
                // Delete EffectLogAsset
                foreach (var assetFile in assetFiles)
                {
                    if (assetFile.FilePath.GetFileName() == EffectLogAsset.DefaultFile)
                    {
                        assetFile.Deleted = true;
                    }
                }
            }

            if (dependency.Version.MinVersion < new PackageVersion("1.4.0-beta"))
            {
                // Update file extensions with Xenko prefix
                var legacyAssets = from assetFile in assetFiles
                                   where !assetFile.Deleted
                                   let extension = assetFile.FilePath.GetFileExtension()
                                                   where extension.StartsWith(".pdx")
                                                   select new { AssetFile = assetFile, NewExtension = ".xk" + extension.Substring(4) };

                foreach (var legacyAsset in legacyAssets.ToArray())
                {
                    var assetFile = legacyAsset.AssetFile;
                    var filePath  = assetFile.FilePath;

                    // Load asset data, so the renamed file will have it's AssetContent set
                    if (assetFile.AssetContent == null)
                    {
                        assetFile.AssetContent = File.ReadAllBytes(filePath);
                    }

                    // Change legacy namespaces and default effect names in all shader source files
                    // TODO: Use syntax analysis? What about shaders referenced in other assets?
                    if (legacyAsset.NewExtension == ".xksl" || legacyAsset.NewExtension == ".xkfx" || legacyAsset.NewExtension == ".xkeffectlog")
                    {
                        var sourceText      = System.Text.Encoding.UTF8.GetString(assetFile.AssetContent);
                        var newSourceText   = sourceText.Replace("Paradox", "Xenko");
                        var newAssetContent = System.Text.Encoding.UTF8.GetBytes(newSourceText);

                        if (newSourceText != sourceText)
                        {
                            assetFile.AssetContent = newAssetContent;
                        }

                        // Write SourceCodeAssets to new file, as they are serialized differently
                        // TODO: Handle SourceCodeAssets properly (should probably force saving)
                        var newFileName = new UFile(filePath.FullPath.Replace(filePath.GetFileExtension(), legacyAsset.NewExtension));
                        File.WriteAllBytes(newFileName, newAssetContent);
                    }

                    // Create asset copy with new extension
                    ChangeFileExtension(assetFiles, assetFile, legacyAsset.NewExtension);
                }

                // Force loading of user settings with old extension
                var userSettings = dependentPackage.UserSettings;

                // Change package extension
                dependentPackage.FullPath = new UFile(dependentPackage.FullPath.GetFullPathWithoutExtension(), Package.PackageFileExtension);

                // Make sure all assets are upgraded
                RunAssetUpgradersUntilVersion(log, dependentPackage, XenkoConfig.PackageName, assetFiles, PackageVersion.Parse("1.4.0-beta"));
            }

            if (dependency.Version.MinVersion < new PackageVersion("1.5.0-alpha01"))
            {
                RunAssetUpgradersUntilVersion(log, dependentPackage, XenkoConfig.PackageName, assetFiles, PackageVersion.Parse("1.5.0-alpha01"));
            }

            if (dependency.Version.MinVersion < new PackageVersion("1.5.0-alpha02"))
            {
                // Ideally, this should be part of asset upgrader but we can't upgrade multiple assets at once yet

                var modelAssets = assetFiles.Where(f => f.FilePath.GetFileExtension() == ".xkm3d").Select(x => x.AsYamlAsset()).ToArray();
                var animAssets  = assetFiles.Where(f => f.FilePath.GetFileExtension() == ".xkanim").Select(x => x.AsYamlAsset()).ToArray();
                var sceneAssets = assetFiles.Where(f => f.FilePath.GetFileExtension() == ".xkscene").Select(x => x.AsYamlAsset()).ToArray();

                // Select models with at least two nodes
                var modelAssetsWithSekeleton = modelAssets
                                               .Where(model => ((IEnumerable)model.DynamicRootNode.Nodes).Cast <object>().Count() > 1).ToArray();

                var animToModelMapping = new Dictionary <PackageLoadingAssetFile.YamlAsset, PackageLoadingAssetFile.YamlAsset>();

                // Find associations in scene
                foreach (var sceneAsset in sceneAssets)
                {
                    var hierarchy = sceneAsset.DynamicRootNode.Hierarchy;
                    foreach (dynamic entity in hierarchy.Entities)
                    {
                        var components         = entity.Entity.Components;
                        var animationComponent = components["AnimationComponent.Key"];
                        var model = components["ModelComponent.Key"]?.Model;
                        if (animationComponent != null && model != null)
                        {
                            var modelReference = DynamicYamlExtensions.ConvertTo <AssetReference <Asset> >(model);
                            var modelAsset     = modelAssetsWithSekeleton.FirstOrDefault(x => x.Asset.AssetPath == modelReference.Location);

                            foreach (var animation in animationComponent.Animations)
                            {
                                var animationReference = DynamicYamlExtensions.ConvertTo <AssetReference <Asset> >(animation.Value);
                                var animationAsset     = animAssets.FirstOrDefault(x => x.Asset.AssetPath == animationReference.Location);

                                if (modelAsset != null && animationAsset != null)
                                {
                                    animToModelMapping[animationAsset] = modelAsset;
                                }
                            }
                        }
                    }
                }

                // Find associations when sharing same source file
                foreach (var animationAsset in animAssets)
                {
                    // Comparing absolute path of assets
                    var modelAsset = modelAssetsWithSekeleton.FirstOrDefault(
                        x => UPath.Combine(animationAsset.Asset.AssetPath.GetParent(), new UFile((string)animationAsset.DynamicRootNode.Source))
                        == UPath.Combine(x.Asset.AssetPath.GetParent(), new UFile((string)x.DynamicRootNode.Source)));
                    if (modelAsset != null)
                    {
                        animToModelMapping[animationAsset] = modelAsset;
                    }
                }

                var modelToSkeletonMapping = new Dictionary <PackageLoadingAssetFile.YamlAsset, PackageLoadingAssetFile.YamlAsset>();

                // For each model asset, create skeleton assets
                foreach (var modelAsset in modelAssetsWithSekeleton)
                {
                    var skeletonAsset = new PackageLoadingAssetFile(modelAsset.Asset.FilePath.GetFullPathWithoutExtension() + " Skeleton.xkskel", modelAsset.Asset.SourceFolder)
                    {
                        AssetContent = System.Text.Encoding.UTF8.GetBytes("!Skeleton\r\nId: " + Guid.NewGuid())
                    };

                    using (var skeletonAssetYaml = skeletonAsset.AsYamlAsset())
                    {
                        // Set source
                        skeletonAssetYaml.DynamicRootNode.Source     = modelAsset.DynamicRootNode.Source;
                        skeletonAssetYaml.DynamicRootNode.SourceHash = modelAsset.DynamicRootNode.SourceHash;

                        // To be on the safe side, mark everything as preserved
                        var nodes = modelAsset.DynamicRootNode.Nodes;
                        foreach (var node in nodes)
                        {
                            node.Preserve = true;
                        }

                        skeletonAssetYaml.DynamicRootNode.Nodes       = nodes;
                        skeletonAssetYaml.DynamicRootNode.ScaleImport = modelAsset.DynamicRootNode.ScaleImport;

                        // Update model to point to this skeleton
                        modelAsset.DynamicRootNode.Skeleton = new AssetReference <Asset>(Guid.Parse((string)skeletonAssetYaml.DynamicRootNode.Id), skeletonAsset.AssetPath.MakeRelative(modelAsset.Asset.AssetPath.GetParent()));
                        modelToSkeletonMapping.Add(modelAsset, skeletonAssetYaml);
                    }

                    assetFiles.Add(skeletonAsset);
                }

                // Update animation to point to skeleton, and set preview default model
                foreach (var animToModelEntry in animToModelMapping)
                {
                    var animationAsset = animToModelEntry.Key;
                    var modelAsset     = animToModelEntry.Value;

                    var skeletonAsset = modelToSkeletonMapping[modelAsset];
                    animationAsset.DynamicRootNode.Skeleton     = new AssetReference <Asset>(Guid.Parse((string)skeletonAsset.DynamicRootNode.Id), skeletonAsset.Asset.AssetPath.MakeRelative(animationAsset.Asset.AssetPath.GetParent()));
                    animationAsset.DynamicRootNode.PreviewModel = new AssetReference <Asset>(Guid.Parse((string)modelAsset.DynamicRootNode.Id), modelAsset.Asset.AssetPath.MakeRelative(animationAsset.Asset.AssetPath.GetParent()));
                }

                // Remove Nodes from models
                foreach (var modelAsset in modelAssets)
                {
                    modelAsset.DynamicRootNode.Nodes = DynamicYamlEmpty.Default;
                    modelAsset.DynamicRootNode[Asset.BaseProperty].Asset.Nodes = DynamicYamlEmpty.Default;
                }

                // Save back
                foreach (var modelAsset in modelAssets)
                {
                    modelAsset.Dispose();
                }
                foreach (var animAsset in animAssets)
                {
                    animAsset.Dispose();
                }
            }

            if (dependency.Version.MinVersion < new PackageVersion("1.6.0-beta"))
            {
                // Delete EffectLogAsset
                foreach (var assetFile in assetFiles)
                {
                    if (assetFile.FilePath.GetFileName() == EffectLogAsset.DefaultFile)
                    {
                        assetFile.Deleted = true;
                    }
                }
            }

            return(true);
        }