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 spitesGroups = assetFiles.Where(f => f.FilePath.GetFileExtension() == ".pdxsprite"); RenameAndChangeTag(assetFiles, uiImageGroups, "!UIImageGroup"); RenameAndChangeTag(assetFiles, spitesGroups, "!SpriteGroup"); } return true; }
/// <inheritdoc/> public IEnumerable<IReference> EnumerateCompileTimeDependencies(PackageSession session) { var reference = AttachedReferenceManager.GetAttachedReference(Skeleton); if (reference != null) { yield return new AssetReference(reference.Id, reference.Url); } }
/// <summary> /// Create a <see cref="Package"/> that can be used to compile an <see cref="AssetItem"/> by analyzing and resolving its dependencies. /// </summary> /// <returns>The package packageSession that can be used to compile the asset item.</returns> public static Package CreateCompilePackageFromAsset(this PackageSession session, AssetItem originalAssetItem) { // create the compile root package and package session var assetPackageCloned = new Package(); var compilePackageSession = new PackageSession(assetPackageCloned); AddAssetToCompilePackage(session, originalAssetItem, assetPackageCloned); return assetPackageCloned; }
/// <summary> /// Create a <see cref="Package"/> that can be used to compile an <see cref="AssetItem"/> by analyzing and resolving its dependencies. /// </summary> /// <returns>The package packageSession that can be used to compile the asset item.</returns> public static Package CreateCompilePackageFromAsset(this PackageSession session, AssetItem originalAssetItem) { // create the compile root package and package session var assetPackageCloned = new Package(); var compilePackageSession = new PackageSession(assetPackageCloned); AddAssetToCompilePackage(session, originalAssetItem, assetPackageCloned); return(assetPackageCloned); }
public static AssetItem FindAssetFromAttachedReference(this PackageSession session, object obj) { if (obj == null) { return(null); } var reference = AttachedReferenceManager.GetAttachedReference(obj); return(reference != null ? (FindAsset(session, reference.Id) ?? FindAsset(session, reference.Url)) : null); }
/// <summary> /// Create a <see cref="Package"/> that can be used to compile an <see cref="AssetItem"/> by analyzing and resolving its dependencies. /// </summary> /// <returns>The package packageSession that can be used to compile the asset item.</returns> public static Package CreateCompilePackageFromAsset(this PackageSession session, AssetItem originalAssetItem) { // create the compile root package and package session var assetPackageCloned = new Package(); //the following line is necessary to attach a session to the package // ReSharper disable once UnusedVariable var compilePackageSession = new PackageSession(assetPackageCloned); AddAssetToCompilePackage(session, originalAssetItem, assetPackageCloned); return(assetPackageCloned); }
/// <inheritdoc/> public override bool UpgradeAfterAssetsLoaded(PackageSession session, ILogger log, Package dependentPackage, PackageDependency dependency, Package dependencyPackage, PackageVersionRange dependencyVersionBeforeUpdate) { if (dependencyVersionBeforeUpdate.MinVersion < new PackageVersion("1.3.0-alpha02")) { // Add everything as root assets (since we don't know what the project was doing in the code before) foreach (var assetItem in dependentPackage.Assets) { if (!AssetRegistry.IsAssetTypeAlwaysMarkAsRoot(assetItem.Asset.GetType())) dependentPackage.RootAssets.Add(new AssetReference<Asset>(assetItem.Id, assetItem.Location)); } } return true; }
public IEnumerable<IReference> EnumerateCompileTimeDependencies(PackageSession session) { if (Prefab != null) { // Return the prefab itself yield return Prefab; // Then we need to return used models and materials because they affects how the meshes are generated var prefab = session.FindAsset(Prefab.Location)?.Asset as PrefabAsset; if (prefab != null) { // Use a dictionary to ensure each reference is yielded only once var references = new Dictionary<AssetId, IReference>(); foreach (var entity in prefab.Hierarchy.Parts) { // Gather all entities with a model component and a valid model var modelComponent = entity.Entity.Get<ModelComponent>(); if (modelComponent?.Model != null) { var modelReference = AttachedReferenceManager.GetAttachedReference(modelComponent.Model); var model = session.FindAsset(modelReference.Url)?.Asset as IModelAsset; if (model != null) { // Build the list of material for this model var materialList = model.Materials.Select(x => x.MaterialInstance.Material).ToList(); for (var i = 0; i < modelComponent.Materials.Count && i < materialList.Count; i++) foreach (var material in modelComponent.Materials) { // Apply any material override from the model component materialList[material.Key] = material.Value; } // Add the model and the related materials to the list of reference references[modelReference.Id] = modelReference; foreach (var material in materialList) { var materialReference = AttachedReferenceManager.GetAttachedReference(material); references[materialReference.Id] = materialReference; } } } } // Finally return all the referenced models and materials foreach (var reference in references.Values) { yield return reference; } } } }
public static void AddAssetToCompilePackage(this PackageSession session, AssetItem originalAssetItem, Package assetPackageCloned) { if (originalAssetItem == null) { throw new ArgumentNullException("originalAssetItem"); } // Find the asset from the session var assetItem = originalAssetItem.Package.FindAsset(originalAssetItem.Id); if (assetItem == null) { throw new ArgumentException("Cannot find the specified AssetItem instance in the session"); } // Calculate dependencies // Search only for references var dependencies = session.DependencyManager.ComputeDependencies(assetItem.Id, AssetDependencySearchOptions.Out | AssetDependencySearchOptions.Recursive, ContentLinkType.Reference); if (dependencies == null) { throw new InvalidOperationException("The asset doesn't exist in the dependency manager anymore"); } var assetItemRootCloned = dependencies.Item.Clone(); // Store the fullpath to the sourcefolder, this avoid us to clone hierarchy of packages assetItemRootCloned.SourceFolder = assetItem.FullPath.GetParent(); if (assetPackageCloned.Assets.Find(assetItemRootCloned.Id) == null) { assetPackageCloned.Assets.Add(assetItemRootCloned); } // For each asset item dependency, clone it in the new package foreach (var assetLink in dependencies.LinksOut) { // Only add assets not already added (in case of circular dependencies) if (assetPackageCloned.Assets.Find(assetLink.Item.Id) == null) { // create a copy of the asset item and add it to the appropriate compile package var itemCloned = assetLink.Item.Clone(); // Store the fullpath to the sourcefolder, this avoid us to clone hierarchy of packages itemCloned.SourceFolder = assetLink.Item.FullPath.GetParent(); assetPackageCloned.Assets.Add(itemCloned); } } }
/// <summary> /// Create a <see cref="PackageSession"/> that can be used to compile an <see cref="AssetItem"/> by analyzing and resolving its dependencies. /// </summary> /// <returns>The package packageSession that can be used to compile the asset item.</returns> public static PackageSession CreateCompilePackageFromAsset(this PackageSession session, AssetItem originalAssetItem) { if (originalAssetItem == null) { throw new ArgumentNullException("originalAssetItem"); } // Find the asset from the session var assetItem = originalAssetItem.Package.FindAsset(originalAssetItem.Id); if (assetItem == null) { throw new ArgumentException("Cannot find the specified AssetItem instance in the session"); } // Calculate dependencies var dependencies = session.DependencyManager.ComputeDependencies(assetItem, AssetDependencySearchOptions.Out | AssetDependencySearchOptions.Recursive); var assetItemRootCloned = dependencies.Item.Clone(); // Store the fullpath to the sourcefolder, this avoid us to clone hierarchy of packages assetItemRootCloned.SourceFolder = assetItem.FullPath.GetParent(); // create the compile root package and package session var assetPackageCloned = new Package(); var compilePackageSession = new PackageSession(assetPackageCloned); assetPackageCloned.Assets.Add(assetItemRootCloned); // For each asset item dependency, clone it in the new package foreach (var assetLink in dependencies.LinksOut) { // Only add assets not already added (in case of circular dependencies) if (assetPackageCloned.Assets.Find(assetLink.Item.Id) == null) { // create a copy of the asset item and add it to the appropriate compile package var itemCloned = assetLink.Item.Clone(); // Store the fullpath to the sourcefolder, this avoid us to clone hierarchy of packages itemCloned.SourceFolder = assetLink.Item.FullPath.GetParent(); assetPackageCloned.Assets.Add(itemCloned); } } return(compilePackageSession); }
/// <summary> /// Create a <see cref="PackageSession"/> that can be used to compile an <see cref="AssetItem"/> by analyzing and resolving its dependencies. /// </summary> /// <returns>The package packageSession that can be used to compile the asset item.</returns> public static PackageSession CreateCompilePackageFromAsset(this PackageSession session, AssetItem originalAssetItem) { if (originalAssetItem == null) throw new ArgumentNullException("originalAssetItem"); // Find the asset from the session var assetItem = originalAssetItem.Package.FindAsset(originalAssetItem.Id); if (assetItem == null) { throw new ArgumentException("Cannot find the specified AssetItem instance in the session"); } // Calculate dependencies var dependencies = session.DependencyManager.ComputeDependencies(assetItem, AssetDependencySearchOptions.Out | AssetDependencySearchOptions.Recursive); var assetItemRootCloned = dependencies.Item.Clone(); // Store the fullpath to the sourcefolder, this avoid us to clone hierarchy of packages assetItemRootCloned.SourceFolder = assetItem.FullPath.GetParent(); // create the compile root package and package session var assetPackageCloned = new Package(); var compilePackageSession = new PackageSession(assetPackageCloned); assetPackageCloned.Assets.Add(assetItemRootCloned); // For each asset item dependency, clone it in the new package foreach (var assetLink in dependencies.LinksOut) { // Only add assets not already added (in case of circular dependencies) if (assetPackageCloned.Assets.Find(assetLink.Item.Id) == null) { // create a copy of the asset item and add it to the appropriate compile package var itemCloned = assetLink.Item.Clone(); // Store the fullpath to the sourcefolder, this avoid us to clone hierarchy of packages itemCloned.SourceFolder = assetLink.Item.FullPath.GetParent(); assetPackageCloned.Assets.Add(itemCloned); } } return compilePackageSession; }
public IEnumerable<IReference> EnumerateCompileTimeDependencies(PackageSession session) { if (Scene != null) { var reference = AttachedReferenceManager.GetAttachedReference(Scene); var sceneAsset = (SceneAsset)session.FindAsset(reference.Url)?.Asset; var referencedColliderShapes = new HashSet<AssetId>(); // Find collider assets to reference if (sceneAsset != null) { List<Entity> sceneEntities = sceneAsset.Hierarchy.Parts.Select(x => x.Entity).ToList(); foreach (var entity in sceneEntities) { StaticColliderComponent collider = entity.Get<StaticColliderComponent>(); bool colliderEnabled = collider != null && ((CollisionFilterGroupFlags)collider.CollisionGroup & IncludedCollisionGroups) != 0 && collider.Enabled; if (colliderEnabled) { var assetShapes = collider.ColliderShapes.OfType<ColliderShapeAssetDesc>(); foreach (var assetShape in assetShapes) { if (assetShape.Shape == null) continue; // Reference all asset collider shapes reference = AttachedReferenceManager.GetAttachedReference(assetShape.Shape); // Only need to reference each shape once if (referencedColliderShapes.Contains(reference.Id)) continue; yield return new AssetReference(reference.Id, reference.Url); referencedColliderShapes.Add(reference.Id); } } } } } }
public static void LoadSolution(PackageSession session, string filePath, List<string> packagePaths, ILogger sessionResult) { var solutionDirectory = Path.GetDirectoryName(filePath); if (solutionDirectory == null) { throw new ArgumentException("Must be absolute", "filePath"); } // The session should save back its changes to the solution session.SolutionPath = filePath; var solution = Solution.FromFile(filePath); foreach (var project in solution.Projects) { string packagePath; if (IsPackage(project, out packagePath)) { var packageFullPath = Path.Combine(solutionDirectory, packagePath); packagePaths.Add(packageFullPath); } } }
public static void LoadSolution(PackageSession session, string filePath, List <string> packagePaths, ILogger sessionResult) { var solutionDirectory = Path.GetDirectoryName(filePath); if (solutionDirectory == null) { throw new ArgumentException("Must be absolute", "filePath"); } // The session should save back its changes to the solution session.SolutionPath = filePath; var solution = Solution.FromFile(filePath); foreach (var project in solution.Projects) { string packagePath; if (IsPackage(project, out packagePath)) { var packageFullPath = Path.Combine(solutionDirectory, packagePath); packagePaths.Add(packageFullPath); } } var versionHeader = solution.Properties.FirstOrDefault(x => x.Name == "VisualStudioVersion"); Version version; if (versionHeader != null && Version.TryParse(versionHeader.Value, out version)) { session.VisualStudioVersion = version; } else { session.VisualStudioVersion = null; } }
public static void LoadSolution(PackageSession session, string filePath, List <string> packagePaths, ILogger sessionResult) { var solutionDirectory = Path.GetDirectoryName(filePath); if (solutionDirectory == null) { throw new ArgumentException("Must be absolute", "filePath"); } // The session should save back its changes to the solution session.SolutionPath = filePath; var solution = Solution.FromFile(filePath); foreach (var project in solution.Projects) { string packagePath; if (IsPackage(project, out packagePath)) { var packageFullPath = Path.Combine(solutionDirectory, packagePath); packagePaths.Add(packageFullPath); } } }
public IEnumerable<IReference> EnumerateCompileTimeDependencies(PackageSession session) { var gameSettings = session.CurrentPackage?.Assets.Find(GameSettingsAsset.GameSettingsLocation); if (gameSettings != null) { yield return new AssetReference(gameSettings.Id, gameSettings.Location); } }
public static void SaveSolution(PackageSession session, ILogger log) { // If the solution path is not set, we can't save a solution (sln) if (session.SolutionPath == null) { return; } var solutionPath = UPath.Combine(Environment.CurrentDirectory, session.SolutionPath); try { Solution solution; var solutionDir = solutionPath.GetParent(); // If the solution already exists, we need to update it if (File.Exists(solutionPath)) { solution = Solution.FromFile(solutionPath); } else { solution = new Solution { FullPath = solutionPath }; solution.Headers.Add(SolutionHeader); } // Pre-create solution wide global sections if (!solution.GlobalSections.Contains("SolutionConfigurationPlatforms")) { solution.GlobalSections.Add(new Section("SolutionConfigurationPlatforms", "GlobalSection", "preSolution", Enumerable.Empty <PropertyItem>())); } if (!solution.GlobalSections.Contains("ProjectConfigurationPlatforms")) { solution.GlobalSections.Add(new Section("ProjectConfigurationPlatforms", "GlobalSection", "postSolution", Enumerable.Empty <PropertyItem>())); } if (!solution.GlobalSections.Contains("NestedProjects")) { solution.GlobalSections.Add(new Section("NestedProjects", "GlobalSection", "preSolution", Enumerable.Empty <PropertyItem>())); } // --------------------------------------------- // 0. Pre-select only platforms effectively used by this session // --------------------------------------------- var platformsUsedBySession = new SolutionPlatformCollection(); platformsUsedBySession.AddRange(AssetRegistry.SupportedPlatforms.Where(platform => platform.Type == PlatformType.Windows)); foreach (var package in session.LocalPackages) { foreach (var profile in package.Profiles.Where(profile => profile.Platform != PlatformType.Shared && profile.ProjectReferences.Count > 0)) { var platformType = profile.Platform; if (!platformsUsedBySession.Contains(platformType)) { platformsUsedBySession.AddRange(AssetRegistry.SupportedPlatforms.Where(platform => platform.Type == platformType)); } } } // --------------------------------------------- // 1. Update configuration/platform // --------------------------------------------- var configs = new List <Tuple <string, SolutionPlatform, SolutionPlatformPart> >(); foreach (var configName in platformsUsedBySession.SelectMany(solutionPlatform => solutionPlatform.Configurations).Select(config => config.Name).Distinct()) { foreach (var platform in platformsUsedBySession) { foreach (var platformPart in platform.GetParts()) { // Skip platforms with IncludeInSolution == false if (!platformPart.IncludeInSolution) { continue; } configs.Add(new Tuple <string, SolutionPlatform, SolutionPlatformPart>(configName, platform, platformPart)); } } } // Order per config and then per platform names configs = configs.OrderBy(part => part.Item1, StringComparer.InvariantCultureIgnoreCase).ThenBy(part => part.Item3.SafeSolutionName, StringComparer.InvariantCultureIgnoreCase).ToList(); // Write configs in alphabetical order to avoid changes in sln after it is generated var solutionPlatforms = solution.GlobalSections["SolutionConfigurationPlatforms"]; solutionPlatforms.Properties.Clear(); foreach (var config in configs) { var solutionConfigPlatform = string.Format("{0}|{1}", config.Item1, config.Item3.SafeSolutionName); if (!solutionPlatforms.Properties.Contains(solutionConfigPlatform)) { solutionPlatforms.Properties.Add(new PropertyItem(solutionConfigPlatform, solutionConfigPlatform)); } } // Remove projects that are no longer available on the disk var projectToRemove = solution.Projects.Where(project => !project.IsSolutionFolder && !File.Exists(project.FullPath)).ToList(); foreach (var project in projectToRemove) { solution.Projects.Remove(project); } // --------------------------------------------- // 2. Update each package // --------------------------------------------- foreach (var package in session.LocalPackages) { if (string.IsNullOrWhiteSpace(package.Meta.Name)) { log.Error($"Error while saving solution [{solutionPath}]. Package [{package.FullPath}] should have a Meta.Name"); continue; } var packageFolder = solution.Projects.FindByGuid((Guid)package.Id); // Packages are created as solution folders in VisualStudio if (packageFolder == null) { // Create this package as a Solution Folder packageFolder = new Project(solution, (Guid)package.Id, KnownProjectTypeGuid.SolutionFolder, package.Meta.Name, package.Meta.Name, Guid.Empty, Enumerable.Empty <Section>(), Enumerable.Empty <PropertyItem>(), Enumerable.Empty <PropertyItem>()); // As it is making a copy, we need to get it back solution.Projects.Add(packageFolder); packageFolder = solution.Projects[package.Id]; } // Update the path to the solution everytime we save a package packageFolder.Sections.Clear(); var relativeUrl = package.FullPath.MakeRelative(solutionDir); packageFolder.Sections.Add(new Section(SiliconStudioPackage, "ProjectSection", "preProject", new[] { new PropertyItem(relativeUrl, relativeUrl) })); // --------------------------------------------- // 2.1. Update each project // --------------------------------------------- foreach (var profile in package.Profiles.OrderBy(x => x.Platform == PlatformType.Windows ? 0 : 1)) { foreach (var project in profile.ProjectReferences) { var projectInSolution = solution.Projects.FindByGuid(project.Id); if (projectInSolution == null) { var projectRelativePath = project.Location.MakeRelative(solutionDir); // Create this package as a Solution Folder projectInSolution = new Project(solution, project.Id, KnownProjectTypeGuid.CSharp, project.Location.GetFileNameWithoutExtension(), projectRelativePath.ToWindowsPath(), package.Id, Enumerable.Empty <Section>(), Enumerable.Empty <PropertyItem>(), Enumerable.Empty <PropertyItem>()); solution.Projects.Add(projectInSolution); // Resolve it again, as the original code is making a clone of it (why?) projectInSolution = solution.Projects.FindByGuid(project.Id); } // Projects are always in a package (solution folder) in the solution projectInSolution.ParentGuid = package.Id; // Update platforms per project (active solution and build flag per platform) // Clear all platform properties for this project and recompute them here projectInSolution.PlatformProperties.Clear(); foreach (var config in configs) { var configName = config.Item1; var platform = config.Item2; var platformPart = config.Item3; // Filter exe project types if (project.Type == ProjectType.Executable && !platformPart.UseWithExecutables) { continue; } var platformName = platformPart.SafeSolutionName; var solutionConfigPlatform = string.Format("{0}|{1}", configName, platformName); var configNameInProject = configName; var platformNameInProject = platformPart.GetProjectName(project.Type); var platformTarget = platform; if (profile.Platform != PlatformType.Shared) { platformTarget = platformsUsedBySession.FirstOrDefault(plat => plat.Type == profile.Platform); if (platformTarget == null) { // This should not happen as we control our platforms, but when we develop a new one // we might get it and it is better to cleary state why we are failing. log.Error("Project contains an unsupported platform " + profile.Platform); throw new InvalidOperationException("Unsupported platform " + profile.Platform); } } bool isPartOfBuild = platformTarget == platform; // If the config doesn't exist for this platform, just use the default config name if (!platformTarget.Configurations.Contains(configName)) { configNameInProject = platformTarget.Configurations.FirstOrDefault().Name; isPartOfBuild = false; } // If the config doesn't exist for this platform, just use the default config name if (platformTarget.GetParts().All(part => part.GetProjectName(project.Type) != platformNameInProject)) { platformNameInProject = platformTarget.GetParts().FirstOrDefault(part => part.IsProjectHandled(project.Type)).SafeSolutionName; isPartOfBuild = false; } var projectConfigPlatform = string.Format("{0}|{1}", configNameInProject, platformNameInProject); var propertyActive = solutionConfigPlatform + ".ActiveCfg"; var propertyBuild = solutionConfigPlatform + ".Build.0"; if (!projectInSolution.PlatformProperties.Contains(propertyActive)) { projectInSolution.PlatformProperties.Remove(propertyActive); projectInSolution.PlatformProperties.Add(new PropertyItem(propertyActive, projectConfigPlatform)); } // Only add Build and Deploy for supported configs if (isPartOfBuild) { projectInSolution.PlatformProperties.Remove(propertyBuild); projectInSolution.PlatformProperties.Add(new PropertyItem(propertyBuild, projectConfigPlatform)); // If the project is an executable, mark it as deploy if (project.Type == ProjectType.Executable) { var propertyDeploy = solutionConfigPlatform + ".Deploy.0"; projectInSolution.PlatformProperties.Remove(propertyDeploy); projectInSolution.PlatformProperties.Add(new PropertyItem(propertyDeploy, projectConfigPlatform)); } } } } } // --------------------------------------------- // 3. Remove unused packages from the solution // --------------------------------------------- for (int i = solution.Projects.Count - 1; i >= 0; i--) { var project = solution.Projects[i]; if (IsPackage(project) && !session.Packages.ContainsById(project.Guid)) { solution.Projects.RemoveAt(i); } } } solution.Save(); } catch (Exception ex) { log.Error($"Error while saving solution [{solutionPath}]", ex); } }
public static void SaveSolution(PackageSession session, ILogger log) { // If the solution path is not set, we can't save a solution (sln) if (session.SolutionPath == null) { return; } var solutionPath = UPath.Combine(Environment.CurrentDirectory, session.SolutionPath); try { Solution solution; var solutionDir = solutionPath.GetParent(); // If the solution already exists, we need to update it if (File.Exists(solutionPath)) { solution = Solution.FromFile(solutionPath); } else { solution = new Solution { FullPath = solutionPath }; solution.Headers.Add(SolutionHeader); } // Pre-create solution wide global sections if (!solution.GlobalSections.Contains("SolutionConfigurationPlatforms")) { solution.GlobalSections.Add(new Section("SolutionConfigurationPlatforms", "GlobalSection", "preSolution", Enumerable.Empty<PropertyItem>())); } if (!solution.GlobalSections.Contains("ProjectConfigurationPlatforms")) { solution.GlobalSections.Add(new Section("ProjectConfigurationPlatforms", "GlobalSection", "postSolution", Enumerable.Empty<PropertyItem>())); } if (!solution.GlobalSections.Contains("NestedProjects")) { solution.GlobalSections.Add(new Section("NestedProjects", "GlobalSection", "preSolution", Enumerable.Empty<PropertyItem>())); } // --------------------------------------------- // 0. Pre-select only platforms effectively used by this session // --------------------------------------------- var platformsUsedBySession = new SolutionPlatformCollection(); platformsUsedBySession.AddRange(AssetRegistry.SupportedPlatforms.Where(platform => platform.Type == PlatformType.Windows)); foreach (var package in session.LocalPackages) { foreach (var profile in package.Profiles.Where(profile => profile.Platform != PlatformType.Shared && profile.ProjectReferences.Count > 0)) { var platformType = profile.Platform; if (!platformsUsedBySession.Contains(platformType)) { platformsUsedBySession.AddRange(AssetRegistry.SupportedPlatforms.Where(platform => platform.Type == platformType)); } } } // --------------------------------------------- // 1. Update configuration/platform // --------------------------------------------- var configs = new List<Tuple<string, SolutionPlatform, SolutionPlatformPart>>(); foreach (var configName in platformsUsedBySession.SelectMany(solutionPlatform => solutionPlatform.Configurations).Select(config => config.Name).Distinct()) { foreach (var platform in platformsUsedBySession) { foreach (var platformPart in platform.GetParts()) { // Skip platforms with IncludeInSolution == false if (!platformPart.IncludeInSolution) continue; configs.Add(new Tuple<string, SolutionPlatform, SolutionPlatformPart>(configName, platform, platformPart)); } } } // Order per config and then per platform names configs = configs.OrderBy(part => part.Item1, StringComparer.InvariantCultureIgnoreCase).ThenBy(part => part.Item3.SafeSolutionName, StringComparer.InvariantCultureIgnoreCase).ToList(); // Write configs in alphabetical order to avoid changes in sln after it is generated var solutionPlatforms = solution.GlobalSections["SolutionConfigurationPlatforms"]; solutionPlatforms.Properties.Clear(); foreach (var config in configs) { var solutionConfigPlatform = string.Format("{0}|{1}", config.Item1, config.Item3.SafeSolutionName); if (!solutionPlatforms.Properties.Contains(solutionConfigPlatform)) { solutionPlatforms.Properties.Add(new PropertyItem(solutionConfigPlatform, solutionConfigPlatform)); } } // Remove projects that are no longer available on the disk var projectToRemove = solution.Projects.Where(project => !project.IsSolutionFolder && !File.Exists(project.FullPath)).ToList(); foreach (var project in projectToRemove) { solution.Projects.Remove(project); } // --------------------------------------------- // 2. Update each package // --------------------------------------------- foreach (var package in session.LocalPackages) { if (string.IsNullOrWhiteSpace(package.Meta.Name)) { log.Error("Error while saving solution [{0}]. Package [{1}] should have a Meta.Name", solutionPath, package.FullPath); continue; } var packageFolder = solution.Projects.FindByGuid(package.Id); // Packages are created as solution folders in VisualStudio if (packageFolder == null) { // Create this package as a Solution Folder packageFolder = new Project(solution, package.Id, KnownProjectTypeGuid.SolutionFolder, package.Meta.Name, package.Meta.Name, Guid.Empty, Enumerable.Empty<Section>(), Enumerable.Empty<PropertyItem>(), Enumerable.Empty<PropertyItem>()); // As it is making a copy, we need to get it back solution.Projects.Add(packageFolder); packageFolder = solution.Projects[package.Id]; } // Update the path to the solution everytime we save a package packageFolder.Sections.Clear(); var relativeUrl = package.FullPath.MakeRelative(solutionDir); packageFolder.Sections.Add(new Section(SiliconStudioPackage, "ProjectSection", "preProject", new[] { new PropertyItem(relativeUrl, relativeUrl) })); // --------------------------------------------- // 2.1. Update each project // --------------------------------------------- foreach (var profile in package.Profiles.OrderBy(x => x.Platform == PlatformType.Windows ? 0 : 1)) { foreach (var project in profile.ProjectReferences) { var projectInSolution = solution.Projects.FindByGuid(project.Id); if (projectInSolution == null) { var projectRelativePath = project.Location.MakeRelative(solutionDir); // Create this package as a Solution Folder projectInSolution = new Project(solution, project.Id, KnownProjectTypeGuid.CSharp, project.Location.GetFileName(), projectRelativePath.ToWindowsPath(), package.Id, Enumerable.Empty<Section>(), Enumerable.Empty<PropertyItem>(), Enumerable.Empty<PropertyItem>()); solution.Projects.Add(projectInSolution); // Resolve it again, as the original code is making a clone of it (why?) projectInSolution = solution.Projects.FindByGuid(project.Id); } // Projects are always in a package (solution folder) in the solution projectInSolution.ParentGuid = package.Id; // Update platforms per project (active solution and build flag per platform) // Clear all platform properties for this project and recompute them here projectInSolution.PlatformProperties.Clear(); foreach (var config in configs) { var configName = config.Item1; var platform = config.Item2; var platformPart = config.Item3; // Filter exe project types if (project.Type == ProjectType.Executable && !platformPart.UseWithExecutables) { continue; } var platformName = platformPart.SafeSolutionName; var solutionConfigPlatform = string.Format("{0}|{1}", configName, platformName); var configNameInProject = configName; var platformNameInProject = platformPart.GetProjectName(project.Type); var platformTarget = platform; if (profile.Platform != PlatformType.Shared) { platformTarget = platformsUsedBySession.First(plat => plat.Type == profile.Platform); } bool isPartOfBuild = platformTarget == platform; // If the config doesn't exist for this platform, just use the default config name if (!platformTarget.Configurations.Contains(configName)) { configNameInProject = platformTarget.Configurations.FirstOrDefault().Name; isPartOfBuild = false; } // If the config doesn't exist for this platform, just use the default config name if (platformTarget.GetParts().All(part => part.GetProjectName(project.Type) != platformNameInProject)) { platformNameInProject = platformTarget.GetParts().FirstOrDefault(part => part.IsProjectHandled(project.Type)).SafeSolutionName; isPartOfBuild = false; } var projectConfigPlatform = string.Format("{0}|{1}", configNameInProject, platformNameInProject); var propertyActive = solutionConfigPlatform + ".ActiveCfg"; var propertyBuild = solutionConfigPlatform + ".Build.0"; if (!projectInSolution.PlatformProperties.Contains(propertyActive)) { projectInSolution.PlatformProperties.Remove(propertyActive); projectInSolution.PlatformProperties.Add(new PropertyItem(propertyActive, projectConfigPlatform)); } // Only add Build and Deploy for supported configs if (isPartOfBuild) { projectInSolution.PlatformProperties.Remove(propertyBuild); projectInSolution.PlatformProperties.Add(new PropertyItem(propertyBuild, projectConfigPlatform)); // If the project is an executable, mark it as deploy if (project.Type == ProjectType.Executable) { var propertyDeploy = solutionConfigPlatform + ".Deploy.0"; projectInSolution.PlatformProperties.Remove(propertyDeploy); projectInSolution.PlatformProperties.Add(new PropertyItem(propertyDeploy, projectConfigPlatform)); } } } } } // --------------------------------------------- // 3. Remove unused packages from the solution // --------------------------------------------- for (int i = solution.Projects.Count - 1; i >=0; i--) { var project = solution.Projects[i]; if (IsPackage(project) && !session.Packages.ContainsById(project.Guid)) { solution.Projects.RemoveAt(i); } } } solution.Save(); } catch (Exception ex) { log.Error("Error while saving solution [{0}]", ex, solutionPath); } }
public override bool UpgradeBeforeAssembliesLoaded(PackageSession session, ILogger log, Package dependentPackage, PackageDependency dependency, Package dependencyPackage) { if (dependency.Version.MinVersion < new PackageVersion("1.4.0-alpha01")) { // Only load workspace for C# assemblies (default includes VB but not added as a NuGet package) var csharpWorkspaceAssemblies = new[] { Assembly.Load("Microsoft.CodeAnalysis.Workspaces"), Assembly.Load("Microsoft.CodeAnalysis.CSharp.Workspaces"), Assembly.Load("Microsoft.CodeAnalysis.Workspaces.Desktop") }; var workspace = MSBuildWorkspace.Create(ImmutableDictionary<string, string>.Empty, MefHostServices.Create(csharpWorkspaceAssemblies)); var tasks = dependentPackage.Profiles .SelectMany(profile => profile.ProjectReferences) .Select(projectReference => UPath.Combine(dependentPackage.RootDirectory, projectReference.Location)) .Distinct() .Select(projectFullPath => Task.Run(() => UpgradeProject(workspace, projectFullPath))) .ToArray(); Task.WaitAll(tasks); } return true; }
public void TestImportModelSimple() { var file = Path.Combine(Environment.CurrentDirectory, @"scenes\goblin.fbx"); // Create a project with an asset reference a raw file var project = new Package { FullPath = Path.Combine(Environment.CurrentDirectory, "ModelAssets", "ModelAssets" + Package.PackageFileExtension) }; using (var session = new PackageSession(project)) { var importSession = new AssetImportSession(session); // ------------------------------------------------------------------ // Step 1: Add files to session // ------------------------------------------------------------------ importSession.AddFile(file, project, UDirectory.Empty); // ------------------------------------------------------------------ // Step 2: Stage assets // ------------------------------------------------------------------ var stageResult = importSession.Stage(); Assert.IsTrue(stageResult); Assert.AreEqual(0, project.Assets.Count); // ------------------------------------------------------------------ // Step 3: Import asset directly // ------------------------------------------------------------------ importSession.Import(); Assert.AreEqual(4, project.Assets.Count); var assetItem = project.Assets.FirstOrDefault(item => item.Asset is EntityAsset); Assert.NotNull(assetItem); EntityAnalysis.UpdateEntityReferences(((EntityAsset)assetItem.Asset).Hierarchy); var assetCollection = new AssetItemCollection(); // Remove directory from the location assetCollection.Add(assetItem); Console.WriteLine(assetCollection.ToText()); //session.Save(); // Create and mount database file system var objDatabase = new ObjectDatabase("/data/db", "index", "/local/db"); var databaseFileProvider = new DatabaseFileProvider(objDatabase); AssetManager.GetFileProvider = () => databaseFileProvider; ((EntityAsset)assetItem.Asset).Hierarchy.Entities[0].Components.RemoveWhere(x => x.Key != TransformComponent.Key); //((EntityAsset)assetItem.Asset).Data.Entities[1].Components.RemoveWhere(x => x.Key != SiliconStudio.Paradox.Engine.TransformComponent.Key); var assetManager = new AssetManager(); assetManager.Save("Entity1", ((EntityAsset)assetItem.Asset).Hierarchy); assetManager = new AssetManager(); var entity = assetManager.Load<Entity>("Entity1"); var entity2 = entity.Clone(); var entityAsset = (EntityAsset)assetItem.Asset; entityAsset.Hierarchy.Entities[0].Components.Add(TransformComponent.Key, new TransformComponent()); var entityAsset2 = (EntityAsset)AssetCloner.Clone(entityAsset); entityAsset2.Hierarchy.Entities[0].Components.Get(TransformComponent.Key).Position = new Vector3(10.0f, 0.0f, 0.0f); AssetMerge.Merge(entityAsset, entityAsset2, null, AssetMergePolicies.MergePolicyAsset2AsNewBaseOfAsset1); } }
/// <summary> /// Loads a package from specified file path. /// </summary> /// <param name="filePath">The file path to a package file.</param> /// <param name="sessionResult">The session result.</param> /// <param name="loadParameters">The load parameters.</param> /// <returns>A package.</returns> /// <exception cref="System.ArgumentNullException">filePath</exception> /// <exception cref="System.ArgumentException">File [{0}] must exist.ToFormat(filePath);filePath</exception> public static void Load(string filePath, PackageSessionResult sessionResult, PackageLoadParameters loadParameters = null) { if (filePath == null) throw new ArgumentNullException("filePath"); if (sessionResult == null) throw new ArgumentNullException("sessionResult"); // Make sure with have valid parameters loadParameters = loadParameters ?? PackageLoadParameters.Default(); // Make sure to use a full path. filePath = FileUtility.GetAbsolutePath(filePath); if (!File.Exists(filePath)) throw new ArgumentException("File [{0}] must exist".ToFormat(filePath), "filePath"); try { // Enable reference analysis caching during loading AssetReferenceAnalysis.EnableCaching = true; using (var profile = Profiler.Begin(PackageSessionProfilingKeys.Loading)) { sessionResult.Clear(); sessionResult.Progress("Loading..", 0, 1); var session = new PackageSession(); var packagePaths = new List<string>(); // If we have a solution, load all packages if (PackageSessionHelper.IsSolutionFile(filePath)) { PackageSessionHelper.LoadSolution(session, filePath, packagePaths, sessionResult); } else if (PackageSessionHelper.IsPackageFile(filePath)) { packagePaths.Add(filePath); } else { sessionResult.Error("Unsupported file extension (only .sln or {0} are supported)", Package.PackageFileExtension); return; } var cancelToken = loadParameters.CancelToken; // Load all packages var packagesLoaded = new PackageCollection(); foreach (var packageFilePath in packagePaths) { PreLoadPackage(session, sessionResult, packageFilePath, false, packagesLoaded, loadParameters); // Output the session only if there is no cancellation if (cancelToken.HasValue && cancelToken.Value.IsCancellationRequested) { return; } } // Load all missing references/dependencies session.LoadMissingReferences(sessionResult, loadParameters); // Fix relative references var analysis = new PackageSessionAnalysis(session, GetPackageAnalysisParametersForLoad()); var analysisResults = analysis.Run(); analysisResults.CopyTo(sessionResult); // Run custom package session analysis foreach (var type in AssetRegistry.GetPackageSessionAnalysisTypes()) { var pkgAnalysis = (PackageSessionAnalysisBase)Activator.CreateInstance(type); pkgAnalysis.Session = session; var results = pkgAnalysis.Run(); results.CopyTo(sessionResult); } // Output the session only if there is no cancellation if (!cancelToken.HasValue || !cancelToken.Value.IsCancellationRequested) { sessionResult.Session = session; // Defer the initialization of the dependency manager //session.DependencyManager.InitializeDeferred(); } // Setup the current package when loading it if (packagePaths.Count == 1) { var currentPackagePath = new UFile(packagePaths[0]); foreach (var package in packagesLoaded) { if (package.FullPath == currentPackagePath) { session.CurrentPackage = package; break; } } } // The session is not dirty when loading it session.IsDirty = false; } } finally { // Disable reference analysis caching after loading AssetReferenceAnalysis.EnableCaching = false; } }
private static bool TryLoadAssets(PackageSession session, ILogger log, Package package, PackageLoadParameters loadParameters) { // Already loaded if (package.State >= PackageState.AssetsReady) return true; // Dependencies could not properly be loaded if (package.State < PackageState.DependenciesReady) return false; // A package upgrade has previously been tried and denied, so let's keep the package in this state if (package.State == PackageState.UpgradeFailed) return false; try { // First, check that dependencies have their assets loaded bool dependencyError = false; foreach (var dependency in package.FindDependencies(false, false)) { if (!TryLoadAssets(session, log, dependency, loadParameters)) dependencyError = true; } if (dependencyError) return false; var pendingPackageUpgrades = new List<PendingPackageUpgrade>(); // Note: Default state is upgrade failed (for early exit on error/exceptions) // We will update to success as soon as loading is finished. package.State = PackageState.UpgradeFailed; // Process store dependencies for upgraders foreach (var packageDependency in package.Meta.Dependencies) { var dependencyPackage = session.Packages.Find(packageDependency); if (dependencyPackage == null) { continue; } // Check for upgraders var packageUpgrader = session.CheckPackageUpgrade(log, package, packageDependency, dependencyPackage); if (packageUpgrader != null) { pendingPackageUpgrades.Add(new PendingPackageUpgrade(packageUpgrader, packageDependency, dependencyPackage)); } } // Prepare asset loading var newLoadParameters = loadParameters.Clone(); newLoadParameters.AssemblyContainer = session.assemblyContainer; // Default package version override newLoadParameters.ExtraCompileProperties = new Dictionary<string, string>(); var defaultPackageOverride = NugetStore.GetPackageVersionVariable(PackageStore.Instance.DefaultPackageName) + "Override"; var defaultPackageVersion = PackageStore.Instance.DefaultPackageVersion.Version; newLoadParameters.ExtraCompileProperties.Add(defaultPackageOverride, new Version(defaultPackageVersion.Major, defaultPackageVersion.Minor).ToString()); if (loadParameters.ExtraCompileProperties != null) { foreach (var property in loadParameters.ExtraCompileProperties) { newLoadParameters.ExtraCompileProperties[property.Key] = property.Value; } } if (pendingPackageUpgrades.Count > 0) { var upgradeAllowed = true; // Need upgrades, let's ask user confirmation if (loadParameters.PackageUpgradeRequested != null) { upgradeAllowed = loadParameters.PackageUpgradeRequested(package, pendingPackageUpgrades); } if (!upgradeAllowed) { log.Error("Necessary package migration for [{0}] has not been allowed", package.Meta.Name); return false; } // Perform pre assembly load upgrade foreach (var pendingPackageUpgrade in pendingPackageUpgrades) { var packageUpgrader = pendingPackageUpgrade.PackageUpgrader; var dependencyPackage = pendingPackageUpgrade.DependencyPackage; if (!packageUpgrader.UpgradeBeforeAssembliesLoaded(session, log, package, pendingPackageUpgrade.Dependency, dependencyPackage)) { log.Error("Error while upgrading package [{0}] for [{1}] from version [{2}] to [{3}]", package.Meta.Name, dependencyPackage.Meta.Name, pendingPackageUpgrade.Dependency.Version, dependencyPackage.Meta.Version); return false; } } } // Load assemblies. Set the package filename to the path on disk, in case of renaming. // TODO: Could referenced projects be associated to other packages than this one? newLoadParameters.ExtraCompileProperties.Add("SiliconStudioCurrentPackagePath", package.FullPath); package.LoadAssemblies(log, newLoadParameters); // Load list of assets newLoadParameters.AssetFiles = Package.ListAssetFiles(log, package, loadParameters.CancelToken); if (pendingPackageUpgrades.Count > 0) { // Perform upgrades foreach (var pendingPackageUpgrade in pendingPackageUpgrades) { var packageUpgrader = pendingPackageUpgrade.PackageUpgrader; var dependencyPackage = pendingPackageUpgrade.DependencyPackage; if (!packageUpgrader.Upgrade(session, log, package, pendingPackageUpgrade.Dependency, dependencyPackage, newLoadParameters.AssetFiles)) { log.Error("Error while upgrading package [{0}] for [{1}] from version [{2}] to [{3}]", package.Meta.Name, dependencyPackage.Meta.Name, pendingPackageUpgrade.Dependency.Version, dependencyPackage.Meta.Version); return false; } // Update dependency to reflect new requirement pendingPackageUpgrade.Dependency.Version = pendingPackageUpgrade.PackageUpgrader.Attribute.PackageUpdatedVersionRange; } // Mark package as dirty package.IsDirty = true; } // Load assets package.LoadAssets(log, newLoadParameters); // Validate assets from package package.ValidateAssets(newLoadParameters.GenerateNewAssetIds); if (pendingPackageUpgrades.Count > 0) { // Perform post asset load upgrade foreach (var pendingPackageUpgrade in pendingPackageUpgrades) { var packageUpgrader = pendingPackageUpgrade.PackageUpgrader; var dependencyPackage = pendingPackageUpgrade.DependencyPackage; if (!packageUpgrader.UpgradeAfterAssetsLoaded(session, log, package, pendingPackageUpgrade.Dependency, dependencyPackage, pendingPackageUpgrade.DependencyVersionBeforeUpgrade)) { log.Error("Error while upgrading package [{0}] for [{1}] from version [{2}] to [{3}]", package.Meta.Name, dependencyPackage.Meta.Name, pendingPackageUpgrade.Dependency.Version, dependencyPackage.Meta.Version); return false; } } // Mark package as dirty package.IsDirty = true; } // Mark package as ready package.State = PackageState.AssetsReady; // Freeze the package after loading the assets session.FreezePackage(package); return true; } catch (Exception ex) { log.Error("Error while loading package [{0}]", ex, package); return false; } }
private static Package PreLoadPackage(PackageSession session, ILogger log, string filePath, bool isSystemPackage, PackageCollection loadedPackages, PackageLoadParameters loadParameters) { if (session == null) { throw new ArgumentNullException("session"); } if (log == null) { throw new ArgumentNullException("log"); } if (filePath == null) { throw new ArgumentNullException("filePath"); } if (loadedPackages == null) { throw new ArgumentNullException("loadedPackages"); } if (loadParameters == null) { throw new ArgumentNullException("loadParameters"); } try { var packageId = Package.GetPackageIdFromFile(filePath); // Check that the package was not already loaded, otherwise return the same instance if (session.Packages.ContainsById(packageId)) { return(session.Packages.Find(packageId)); } // Package is already loaded, use the instance if (loadedPackages.ContainsById(packageId)) { return(loadedPackages.Find(packageId)); } // Load the package without loading assets var newLoadParameters = loadParameters.Clone(); newLoadParameters.AssemblyContainer = session.assemblyContainer; // Load the package var package = Package.Load(log, filePath, newLoadParameters); package.IsSystem = isSystemPackage; // Add the package has loaded before loading dependencies loadedPackages.Add(package); // Load package dependencies PreLoadPackageDependencies(session, log, package, loadedPackages, loadParameters); // Add the package to the session but don't freeze it yet session.Packages.Add(package); // Validate assets from package package.ValidateAssets(loadParameters.GenerateNewAssetIds); // Freeze the package after loading the assets session.FreezePackage(package); return(package); } catch (Exception ex) { log.Error("Error while pre-loading package [{0}]", ex, filePath); } return(null); }
/// <summary> /// Performs the second step of package migration, after assets have been loaded. /// </summary> /// <param name="session">The session.</param> /// <param name="log">The log.</param> /// <param name="dependentPackage">The source package.</param> /// <param name="dependency">The dependency.</param> /// <param name="dependencyPackage">The dependency package.</param> /// <param name="dependencyVersionBeforeUpdate">The version before the update.</param> /// <returns></returns> public virtual bool UpgradeAfterAssetsLoaded(PackageSession session, ILogger log, Package dependentPackage, PackageDependency dependency, Package dependencyPackage, PackageVersionRange dependencyVersionBeforeUpdate) { return(true); }
/// <summary> /// Performs the package migration, before assets are loaded /// </summary> /// <param name="session">The session.</param> /// <param name="log">The log.</param> /// <param name="dependentPackage">The source package.</param> /// <param name="dependency">The dependency.</param> /// <param name="dependencyPackage">The dependency package.</param> /// <param name="assetFiles">The asset files.</param> /// <returns></returns> public abstract bool Upgrade(PackageSession session, ILogger log, Package dependentPackage, PackageDependency dependency, Package dependencyPackage, IList <PackageLoadingAssetFile> assetFiles);
/// <summary> /// Performs a preprocessing step of package migration, before assembly references are loaded. /// </summary> /// <param name="session">The session.</param> /// <param name="log">The log.</param> /// <param name="dependentPackage">The source package.</param> /// <param name="dependency">The dependency.</param> /// <param name="dependencyPackage">The dependency package.</param> /// <returns></returns> public virtual bool UpgradeBeforeAssembliesLoaded(PackageSession session, ILogger log, Package dependentPackage, PackageDependency dependency, Package dependencyPackage) { return(true); }
private static void GenerateUnitTestProject(string outputDirectory, string templateFile, string name) { var projectTemplate = ProjectTemplate.Load(templateFile); // Force reference to Paradox.Assets (to have acess to SolutionPlatform) projectTemplate.Assemblies.Add(typeof(GraphicsProfile).Assembly.FullName); projectTemplate.Assemblies.Add(typeof(ParadoxConfig).Assembly.FullName); var options = new Dictionary<string, object>(); var session = new PackageSession(); var result = new LoggerResult(); var templateGeneratorParameters = new TemplateGeneratorParameters(); templateGeneratorParameters.OutputDirectory = outputDirectory; templateGeneratorParameters.Session = session; templateGeneratorParameters.Name = name; templateGeneratorParameters.Logger = result; templateGeneratorParameters.Description = new TemplateDescription(); PackageUnitTestGenerator.Default.Generate(templateGeneratorParameters); if (result.HasErrors) { Console.WriteLine("Error generating package: {0}", result.ToText()); return; } var package = templateGeneratorParameters.Package; var previousCurrent = session.CurrentPackage; session.CurrentPackage = package; // Compute Paradox Sdk relative path // We are supposed to be in standard output binary folder, so Paradox root should be at ..\.. var paradoxPath = UDirectory.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), new UDirectory(@"..\..")); var paradoxRelativePath = new UDirectory(paradoxPath) .MakeRelative(outputDirectory) .ToString() .Replace('/', '\\'); paradoxRelativePath = paradoxRelativePath.TrimEnd('\\'); options["Namespace"] = name; options["Package"] = package; options["Platforms"] = new List<SolutionPlatform>(AssetRegistry.SupportedPlatforms); options["ParadoxSdkRelativeDir"] = paradoxRelativePath; // Generate project template var projectGuid = Guid.NewGuid(); result = projectTemplate.Generate(outputDirectory, name, projectGuid, options); if (result.HasErrors) { Console.WriteLine("Error generating solution: {0}", result.ToText()); return; } var sharedProfile = package.Profiles[PlatformType.Shared]; // Setup the assets folder Directory.CreateDirectory(UPath.Combine(outputDirectory, (UDirectory)"Assets/Shared")); // Add Windows test as Shared library var projectWindowsRef = new ProjectReference(); projectWindowsRef.Id = projectGuid; projectWindowsRef.Location = UPath.Combine(outputDirectory, (UFile)(name + ".Windows.csproj")); projectWindowsRef.Type = SiliconStudio.Assets.ProjectType.Library; sharedProfile.ProjectReferences.Add(projectWindowsRef); // Generate executable projects for each platform foreach (var platform in AssetRegistry.SupportedPlatforms) { var platformProfile = new PackageProfile(platform.Name) { Platform = platform.Type }; platformProfile.AssetFolders.Add(new AssetFolder("Assets/"+ platform.Name)); // Log progress var projectName = name + "." + platform.Type; // Create project reference var projectPlatformRef = new ProjectReference(); projectPlatformRef.Id = projectGuid; projectPlatformRef.Location = UPath.Combine(outputDirectory, (UFile)(projectName + ".csproj")); projectPlatformRef.Type = SiliconStudio.Assets.ProjectType.Executable; platformProfile.ProjectReferences.Add(projectPlatformRef); // Add build configuration per platform platform.Properties.CopyTo(platformProfile.Properties, true); package.Profiles.Add(platformProfile); } session.CurrentPackage = previousCurrent; result = session.Save(); if (result.HasErrors) { Console.WriteLine("Error saving package: {0}", result.ToText()); return; } }
public TextureAlphaComponentSplitter(PackageSession assetSession) { this.assetSession = assetSession; }
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; }
protected AssetTracker(PackageSession session) { this.session = session; }
public void TestMultiplePrefabsInheritanceAndChildren() { // The purpose of this test is to check that modifying a prefab base is correctly propagated through all // derived prefabs. We use the following scenario: // // a1: base asset // a2: inherit from a1 by composition with 2 instances (baseParts: a1 => 2 instances) // a3: inherit from a1 by composition with 1 instances (baseParts: a1 => 1 instances) // a4: inherit from a2 and a3 by composition with 1 instances for each (baseParts: a1 => 1 instance, a2 => 1 instance) // // Unlike TestMultiplePrefabsMixedInheritance, we use only inheritance by composition for this scenario to match current use cases var package = new Package(); var assetItems = package.Assets; // First we create assets with the following configuration: // a1: a2: (baseParts: a1, 2 instances) a3: (baseParts: a1) a4: (baseParts: a2 x 1, a3 x 1) // | er | er1 (base: er) | er1' (base: er) | eRoot // | ea | ea1 (base: ea) | ea1' (base: ea) | er1* (base: er) // | eb | eb1 (base: eb) | eb1' (base: eb) | ea1* (base: ea) // | ec | ec1 (base: ec) | ec1' (base: ec) | eb1* (base: eb) // | er2 (base: er) | ec1* (base: ec) // | ea2 (base: ea) | er2* (base: er) // | eb2 (base: eb) | ea2* (base: ea) // | ec2 (base: ec) | eb2* (base: eb) // | ec2* (base: ec) // | er1'* (base: er) // | ea1'* (base: ea) // | eb1'* (base: eb) // | ec1'* (base: ec) var a1 = new PrefabAsset(); var er = new Entity("er"); var ea = new Entity("ea"); var eb = new Entity("eb"); var ec = new Entity("ec"); a1.Hierarchy.Parts.Add(new EntityDesign(er)); a1.Hierarchy.Parts.Add(new EntityDesign(ea)); a1.Hierarchy.Parts.Add(new EntityDesign(eb)); a1.Hierarchy.Parts.Add(new EntityDesign(ec)); a1.Hierarchy.RootPartIds.Add(er.Id); er.AddChild(ea); er.AddChild(eb); er.AddChild(ec); assetItems.Add(new AssetItem("a1", a1)); var member = (IMemberDescriptor)TypeDescriptorFactory.Default.Find(typeof(Entity))[nameof(Entity.Name)]; var a2 = new PrefabAsset(); var a2PartInstance1 = a1.CreatePrefabInstance(a2, "a1"); foreach (var entity in a2PartInstance1.Parts) { entity.Entity.Name += "1"; } var a2PartInstance2 = a1.CreatePrefabInstance(a2, "a1"); foreach (var entity in a2PartInstance2.Parts) { entity.Entity.Name += "2"; } a2.Hierarchy.Parts.AddRange(a2PartInstance1.Parts); a2.Hierarchy.Parts.AddRange(a2PartInstance2.Parts); a2.Hierarchy.RootPartIds.AddRange(a2PartInstance1.RootPartIds); a2.Hierarchy.RootPartIds.AddRange(a2PartInstance2.RootPartIds); Assert.AreEqual(8, a2.Hierarchy.Parts.Count); Assert.AreEqual(2, a2.Hierarchy.RootPartIds.Count); assetItems.Add(new AssetItem("a2", a2)); var a3 = new PrefabAsset(); var a3PartInstance1 = a1.CreatePrefabInstance(a3, "a1"); foreach (var entity in a3PartInstance1.Parts) { entity.Entity.Name += "1'"; } a3.Hierarchy.Parts.AddRange(a3PartInstance1.Parts); a3.Hierarchy.RootPartIds.AddRange(a3PartInstance1.RootPartIds); Assert.AreEqual(4, a3.Hierarchy.Parts.Count); Assert.AreEqual(1, a3.Hierarchy.RootPartIds.Count); assetItems.Add(new AssetItem("a3", a3)); var a4 = new PrefabAsset(); var eRoot = new Entity("eRoot"); var a2PartInstance3 = a2.CreatePrefabInstance(a4, "a2"); foreach (var entity in a2PartInstance3.Parts) { entity.Entity.Name += "*"; } foreach (var entity in a2PartInstance3.Parts.Where(t => a2PartInstance3.RootPartIds.Contains(t.Entity.Id))) { eRoot.AddChild(entity.Entity); } var a3PartInstance2 = a3.CreatePrefabInstance(a4, "a3"); foreach (var entity in a3PartInstance2.Parts) { entity.Entity.Name += "*"; } a4.Hierarchy.Parts.Add(new EntityDesign(eRoot)); a4.Hierarchy.Parts.AddRange(a2PartInstance3.Parts); a4.Hierarchy.Parts.AddRange(a3PartInstance2.Parts); a4.Hierarchy.RootPartIds.Add(eRoot.Id); a4.Hierarchy.RootPartIds.AddRange(a3PartInstance2.RootPartIds); Assert.AreEqual(13, a4.Hierarchy.Parts.Count); Assert.AreEqual(2, a4.Hierarchy.RootPartIds.Count); assetItems.Add(new AssetItem("a4", a4)); Assert.True(a1.DumpTo(Console.Out, "a1 BEFORE PrefabMergeAsset")); Assert.True(a2.DumpTo(Console.Out, "a2 BEFORE PrefabMergeAsset")); Assert.True(a3.DumpTo(Console.Out, "a3 BEFORE PrefabMergeAsset")); Assert.True(a4.DumpTo(Console.Out, "a4 BEFORE PrefabMergeAsset")); // Then we simulate a concurrent change to a1 by someone that didn't have a2/a3/a4 // - Add one component to a1, linking to an existing entity ea // - Add a root entity to a1 with a link to an existing entity eb // // a1: a2: (baseParts: a1, 2 instances) a3: (baseParts: a1) a4: (baseParts: a2 x 1, a3 x 1) // | er | er1 (base: er) | er1' (base: er) | eRoot // | ea | ea1 (base: ea) | ea1' (base: ea) | er1* (base: er) // | eb | eb1 (base: eb) | eb1' (base: eb) | ea1* (base: ea) // | ec + link ea | ec1 + link ea1 (base: ec) | ec1' + link ea1' (base: ec) | eb1* (base: eb) // | ex | er2 (base: er) | ex(1') (base: ex) | ec1* + link ea1* (base: ec) // | ey + link eb | ea2 (base: ea) | ey(1') + link eb1' | er2* (base: er) // | eb2 (base: eb) | ea2* (base: ea) // | ec2 + link ea2 (base: ec) | eb2* (base: eb) // | ex(1) | ec2* + link ea2* (base: ec) // | ey(1) + link eb1 | er1'* (base: er) // | ex(2) | ea1'* (base: ea) // | ey(2) + link eb2 | eb1'* (base: eb) // | ec1'* + link ea1'* (base: ec) // | ex(1*) // | ey(1*) + link eb1* // | ex(2*) // | ey(2*) + link eb2* // | ex(1') (base: ex) // | ey(1') + link eb1'* ec.Components.Add(new TestEntityComponent() { EntityLink = ea }); var ex = new Entity("ex"); var ey = new Entity("ey"); ey.Components.Add(new TestEntityComponent() { EntityLink = eb }); ex.AddChild(ey); a1.Hierarchy.Parts.Add(new EntityDesign(ex)); a1.Hierarchy.Parts.Add(new EntityDesign(ey)); a1.Hierarchy.RootPartIds.Add(ex.Id); Assert.AreEqual(6, a1.Hierarchy.Parts.Count); Assert.AreEqual(2, a1.Hierarchy.RootPartIds.Count); // Simulates the loading of this package using (var session = new PackageSession()) { var logger = new LoggerResult(); session.AddExistingPackage(package, logger); Assert.False(logger.HasErrors); Assert.True(a1.DumpTo(Console.Out, "a1 AFTER PrefabMergeAsset")); // ------------------------------------------------ // Check for a2 // ------------------------------------------------ // a2: (baseParts: a1, 2 instances) // | er1 (base: er) // | ea1 (base: ea) // | eb1 (base: eb) // | ec1 + link ea1 (base: ec) // | er2 (base: er) // | ea2 (base: ea) // | eb2 (base: eb) // | ec2 + link ea2 (base: ec) // | ex(1) // | ey(1) + link eb1 // | ex(2) // | ey(2) + link eb2 { Assert.True(a2.DumpTo(Console.Out, "a2 AFTER PrefabMergeAsset")); Assert.AreEqual(4, a2.Hierarchy.RootPartIds.Count); Assert.True(a2.Hierarchy.Parts.All(it => it.Base != null)); // Check that we have all expected entities Assert.AreEqual(12, a2.Hierarchy.Parts.Count); var eb1 = a2.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "eb1")?.Entity; var eb2 = a2.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "eb2")?.Entity; Assert.NotNull(eb1); Assert.NotNull(eb2); // Check that we have ex and ey var exList = a2.Hierarchy.Parts.Where(it => it.Entity.Name == ex.Name).ToList(); Assert.AreEqual(2, exList.Count); // Check that both [ex] have both 1 element [ey] and the links to eb1/eb2 are correct { var expecting = new List<Entity>() { eb1, eb2 }; for (int i = 0; i < exList.Count; i++) { var ex1 = exList[i].Entity; Assert.AreEqual(1, ex1.Transform.Children.Count); var ey1 = ex1.Transform.Children[0].Entity; Assert.AreEqual(ey.Name, ey1.Name); Assert.NotNull(ey1.Get<TestEntityComponent>()); var entityLink = ey1.Get<TestEntityComponent>().EntityLink; Assert.True(expecting.Contains(entityLink)); expecting.Remove(entityLink); } } // Check link from ec1 to ea1 { var ec1 = a2.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "ec1")?.Entity; Assert.NotNull(ec1); var ea1 = a2.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "ea1")?.Entity; Assert.NotNull(ea1); Assert.NotNull(ec1.Get<TestEntityComponent>()); Assert.AreEqual(ea1, ec1.Get<TestEntityComponent>().EntityLink); } // Check link from ec2 to ea2 { var ec2 = a2.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "ec2")?.Entity; Assert.NotNull(ec2); var ea2 = a2.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "ea2")?.Entity; Assert.NotNull(ea2); Assert.NotNull(ec2.Get<TestEntityComponent>()); Assert.AreEqual(ea2, ec2.Get<TestEntityComponent>().EntityLink); } } // ------------------------------------------------ // Check for a3 // ------------------------------------------------ // a3: (baseParts: a1) // | er1' (base: er) // | ea1' (base: ea) // | eb1' (base: eb) // | ec1' + link ea1' (base: ec) // | ex1' (base: ex) // | ey1' + link eb1' { Assert.True(a3.DumpTo(Console.Out, "a3 AFTER PrefabMergeAsset")); Assert.AreEqual(2, a3.Hierarchy.RootPartIds.Count); Assert.True(a3.Hierarchy.Parts.All(it => it.Base != null)); // Check that we have all expected entities Assert.AreEqual(6, a3.Hierarchy.Parts.Count); var eb1 = a3.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "eb1'")?.Entity; Assert.NotNull(eb1); // Check that we have ex and ey var exList = a3.Hierarchy.Parts.Where(it => it.Entity.Name == ex.Name).ToList(); Assert.AreEqual(1, exList.Count); // Check that [ex] have 1 element [ey] and the link to eb1 is correct { var ex1 = exList[0].Entity; Assert.AreEqual(1, ex1.Transform.Children.Count); var ey1 = ex1.Transform.Children[0].Entity; Assert.AreEqual(ey.Name, ey1.Name); Assert.NotNull(ey1.Get<TestEntityComponent>()); Assert.AreEqual(eb1, ey1.Get<TestEntityComponent>().EntityLink); } { var ec1 = a3.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "ec1'")?.Entity; Assert.NotNull(ec1); var ea1 = a3.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "ea1'")?.Entity; Assert.NotNull(ea1); Assert.NotNull(ec1.Get<TestEntityComponent>()); Assert.AreEqual(ea1, ec1.Get<TestEntityComponent>().EntityLink); } } // ------------------------------------------------ // Check for a4 // ------------------------------------------------ // a4: (baseParts: a2 x 1, a3 x 1) // | eNewRoot // | er1* (base: er) // | ea1* (base: ea) // | eb1* (base: eb) // | ec1* + link ea1* (base: ec) // | er2* (base: er) // | ea2* (base: ea) // | eb2* (base: eb) // | ec2* + link ea2* (base: ec) // | er1'* (base: er) // | ea1'* (base: ea) // | eb1'* (base: eb) // | ec1'* + link ea1'* (base: ec) // | ex(1*) // | ey(1*) + link eb1* // | ex(2*) // | ey(2*) + link eb2* // | ex(1') (base: ex) // | ey(1') + link eb1'* { Assert.True(a4.DumpTo(Console.Out, "a4 AFTER PrefabMergeAsset")); Assert.AreEqual(5, a4.Hierarchy.RootPartIds.Count); Assert.True(a4.Hierarchy.Parts.Where(it => it.Entity.Name != "eRoot").All(it => it.Entity.Name != "eRoot" && it.Base != null)); // Check that we have all expected entities Assert.AreEqual(19, a4.Hierarchy.Parts.Count); var eb1 = a4.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "eb1*")?.Entity; var eb1_2 = a4.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "eb1'*")?.Entity; var eb2 = a4.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "eb2*")?.Entity; Assert.NotNull(eb1); Assert.NotNull(eb1_2); Assert.NotNull(eb2); // Check that we have ex and ey var exList = a4.Hierarchy.Parts.Where(it => it.Entity.Name == ex.Name).ToList(); Assert.AreEqual(3, exList.Count); // Check that both [ex] have both 1 element [ey] and the links to eb1/eb2 are correct { var expecting = new List<Entity>() { eb1, eb1_2, eb2 }; for (int i = 0; i < exList.Count; i++) { var ex1 = exList[i].Entity; Assert.AreEqual(1, ex1.Transform.Children.Count); var ey1 = ex1.Transform.Children[0].Entity; Assert.AreEqual(ey.Name, ey1.Name); Assert.NotNull(ey1.Get<TestEntityComponent>()); var entityLink = ey1.Get<TestEntityComponent>().EntityLink; Assert.True(expecting.Contains(entityLink)); expecting.Remove(entityLink); } } // Check all [er] entities Action<string> checkErX = (erName) => { var er1 = a4.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == erName)?.Entity; Assert.NotNull(er1); Assert.AreEqual(3, er1.Transform.Children.Count); var ec1 = er1.Transform.Children.FirstOrDefault(it => it.Entity.Name.StartsWith("ec"))?.Entity; Assert.NotNull(ec1); var ea1 = er1.Transform.Children.FirstOrDefault(it => it.Entity.Name.StartsWith("ea"))?.Entity; Assert.NotNull(ea1); Assert.NotNull(ec1.Get<TestEntityComponent>()); Assert.AreEqual(ea1, ec1.Get<TestEntityComponent>().EntityLink); }; checkErX("er1*"); checkErX("er2*"); checkErX("er1'*"); } } }
public abstract IEnumerable <string> Select(PackageSession packageSession, IAssetIndexMap assetIndexMap);
private static void PreLoadPackageDependencies(PackageSession session, ILogger log, Package package, PackageCollection loadedPackages, PackageLoadParameters loadParameters) { if (session == null) throw new ArgumentNullException("session"); if (log == null) throw new ArgumentNullException("log"); if (package == null) throw new ArgumentNullException("package"); if (loadParameters == null) throw new ArgumentNullException("loadParameters"); bool packageDependencyErrors = false; // TODO: Remove and recheck Dependencies Ready if some secondary packages are removed? if (package.State >= PackageState.DependenciesReady) return; // 1. Load store package foreach (var packageDependency in package.Meta.Dependencies) { var loadedPackage = session.Packages.Find(packageDependency); if (loadedPackage == null) { var file = PackageStore.Instance.GetPackageFileName(packageDependency.Name, packageDependency.Version, session.constraintProvider); if (file == null) { // TODO: We need to support automatic download of packages. This is not supported yet when only Xenko // package is supposed to be installed, but It will be required for full store log.Error("Unable to find package {0} not installed", packageDependency); packageDependencyErrors = true; continue; } // Recursive load of the system package loadedPackage = PreLoadPackage(session, log, file, true, loadedPackages, loadParameters); } if (loadedPackage == null || loadedPackage.State < PackageState.DependenciesReady) packageDependencyErrors = true; } // 2. Load local packages foreach (var packageReference in package.LocalDependencies) { // Check that the package was not already loaded, otherwise return the same instance if (session.Packages.ContainsById(packageReference.Id)) { continue; } // Expand the string of the location var newLocation = (UFile)AssetRegistry.ExpandString(session, packageReference.Location); var subPackageFilePath = package.RootDirectory != null ? UPath.Combine(package.RootDirectory, newLocation) : newLocation; // Recursive load var loadedPackage = PreLoadPackage(session, log, subPackageFilePath.FullPath, false, loadedPackages, loadParameters); if (loadedPackage == null || loadedPackage.State < PackageState.DependenciesReady) packageDependencyErrors = true; } // 3. Update package state if (!packageDependencyErrors) { package.State = PackageState.DependenciesReady; } }
/// <summary> /// Performs the package migration, before assets are loaded /// </summary> /// <param name="session">The session.</param> /// <param name="log">The log.</param> /// <param name="dependentPackage">The source package.</param> /// <param name="dependency">The dependency.</param> /// <param name="dependencyPackage">The dependency package.</param> /// <param name="assetFiles">The asset files.</param> /// <returns></returns> public abstract bool Upgrade(PackageSession session, ILogger log, Package dependentPackage, PackageDependency dependency, Package dependencyPackage, IList<PackageLoadingAssetFile> assetFiles);
private static Package PreLoadPackage(PackageSession session, ILogger log, string filePath, bool isSystemPackage, PackageCollection loadedPackages, PackageLoadParameters loadParameters) { if (session == null) throw new ArgumentNullException("session"); if (log == null) throw new ArgumentNullException("log"); if (filePath == null) throw new ArgumentNullException("filePath"); if (loadedPackages == null) throw new ArgumentNullException("loadedPackages"); if (loadParameters == null) throw new ArgumentNullException("loadParameters"); try { var packageId = Package.GetPackageIdFromFile(filePath); // Check that the package was not already loaded, otherwise return the same instance if (session.Packages.ContainsById(packageId)) { return session.Packages.Find(packageId); } // Package is already loaded, use the instance if (loadedPackages.ContainsById(packageId)) { return loadedPackages.Find(packageId); } // Load the package without loading any assets var package = Package.LoadRaw(log, filePath); package.IsSystem = isSystemPackage; // Convert UPath to absolute (Package only) // Removed for now because it is called again in PackageSession.LoadAssembliesAndAssets (and running it twice result in dirty package) // If we remove it from here (and call it only in the other method), templates are not loaded (Because they are loaded via the package store that do not use PreLoadPackage) //if (loadParameters.ConvertUPathToAbsolute) //{ // var analysis = new PackageAnalysis(package, new PackageAnalysisParameters() // { // ConvertUPathTo = UPathType.Absolute, // SetDirtyFlagOnAssetWhenFixingAbsoluteUFile = true, // IsProcessingUPaths = true, // }); // analysis.Run(log); //} // If the package doesn't have a meta name, fix it here (This is supposed to be done in the above disabled analysis - but we still need to do it!) if (string.IsNullOrWhiteSpace(package.Meta.Name) && package.FullPath != null) { package.Meta.Name = package.FullPath.GetFileName(); package.IsDirty = true; } // Add the package has loaded before loading dependencies loadedPackages.Add(package); // Package has been loaded, register it in constraints so that we force each subsequent loads to use this one (or fails if version doesn't match) session.constraintProvider.AddConstraint(package.Meta.Name, new VersionSpec(package.Meta.Version.ToSemanticVersion())); // Load package dependencies // This will perform necessary asset upgrades // TODO: We should probably split package loading in two recursive top-level passes (right now those two passes are mixed, making it more difficult to make proper checks) // - First, load raw packages with their dependencies recursively, then resolve dependencies and constraints (and print errors/warnings) // - Then, if everything is OK, load the actual references and assets for each packages PreLoadPackageDependencies(session, log, package, loadedPackages, loadParameters); // Add the package to the session but don't freeze it yet session.Packages.Add(package); return package; } catch (Exception ex) { log.Error("Error while pre-loading package [{0}]", ex, filePath); } return null; }
public void TestPackageAssetTemplatingAnalysis() { var package = new Package(); var assetItems = package.Assets; // Before Adding Package // a1: a2: (baseParts: a1, 2 instances) a3: (base: a2) // | ea | ea1 (base: ea) | ea1' (base: ea1) // | eb | eb1 (base: eb) | eb1' (base: eb1) // | ea2 (base: ea) | ea2' (base: ea2) // | eb2 (base: eb) | eb2' (base: eb2) // After adding the package to the session // We add one entity to the base a1 // a1: a2: (baseParts: a1, 2 instances) a3: (base: a2) // | ea | ea1 (base: ea) | ea1' (base: ea1) // | eb | eb1 (base: eb) | eb1' (base: eb1) // | ec | ec1 (base: ec) | ec1' (base: ec1) // | ea2 (base: ea) | ea2' (base: ea2) // | eb2 (base: eb) | eb2' (base: eb2) // | ec2 (base: ec) | ec2' (base: ec2) var a1 = new EntityGroupAsset(); var ea = new Entity("ea"); var eb = new Entity("eb"); a1.Hierarchy.Entities.Add(ea); a1.Hierarchy.Entities.Add(eb); a1.Hierarchy.RootEntities.Add(ea.Id); a1.Hierarchy.RootEntities.Add(eb.Id); assetItems.Add(new AssetItem("a1", a1)); var a2 = new EntityGroupAsset(); var aPartInstance1 = (EntityGroupAsset)a1.CreateChildAsset("a1"); var aPartInstance2 = (EntityGroupAsset)a1.CreateChildAsset("a1"); a2.AddPart(aPartInstance1); a2.AddPart(aPartInstance2); assetItems.Add(new AssetItem("a2", a2)); // Modify a1 to add entity ec var ec = new Entity("ec"); a1.Hierarchy.Entities.Add(ec); a1.Hierarchy.RootEntities.Add(ec.Id); var a3 = (EntityGroupAsset)a2.CreateChildAsset("a2"); assetItems.Add(new AssetItem("a3", a3)); // Create a session with this project using (var session = new PackageSession()) { var logger = new LoggerResult(); session.AddExistingPackage(package, logger); Assert.False(logger.HasErrors); Assert.AreEqual(6, a2.Hierarchy.RootEntities.Count); Assert.True(a2.Hierarchy.Entities.All(it => it.Design.BaseId.HasValue && it.Design.BasePartInstanceId.HasValue)); Assert.AreEqual(6, a3.Hierarchy.RootEntities.Count); Assert.True(a3.Hierarchy.Entities.All(it => !it.Design.BasePartInstanceId.HasValue)); Assert.True(a3.Hierarchy.Entities.All(it => it.Design.BaseId.HasValue && a2.Hierarchy.Entities.ContainsKey(it.Design.BaseId.Value))); } }
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()) { // Load asset data, so the renamed file will have it's AssetContent set if (legacyAsset.AssetFile.AssetContent == null) legacyAsset.AssetFile.AssetContent = File.ReadAllBytes(legacyAsset.AssetFile.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(legacyAsset.AssetFile.AssetContent); var newSourceText = sourceText.Replace("Paradox", "Xenko"); if (newSourceText != sourceText) { legacyAsset.AssetFile.AssetContent = System.Text.Encoding.UTF8.GetBytes(newSourceText); } } // Create asset copy with new extension ChangeFileExtension(assetFiles, legacyAsset.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["~Base"].Asset.Nodes = DynamicYamlEmpty.Default; } // Save back foreach (var modelAsset in modelAssets) modelAsset.Dispose(); foreach (var animAsset in animAssets) animAsset.Dispose(); } return true; }
/// <summary> /// Finds an asset from all the packages by its location. /// </summary> /// <param name="session">The session.</param> /// <param name="location">The location of the asset.</param> /// <returns>An <see cref="AssetItem" /> or <c>null</c> if not found.</returns> public static AssetItem FindAsset(this PackageSession session, UFile location) { var packages = session.CurrentPackage != null?session.GetPackagesFromCurrent() : session.Packages; return(packages.Select(packageItem => packageItem.Assets.Find(location)).FirstOrDefault(asset => asset != null)); }
public abstract IEnumerable<string> Select(PackageSession packageSession, IAssetIndexMap assetIndexMap);
private static void PreLoadPackageDependencies(PackageSession session, ILogger log, Package package, PackageCollection loadedPackages, PackageLoadParameters loadParameters) { if (session == null) { throw new ArgumentNullException("session"); } if (log == null) { throw new ArgumentNullException("log"); } if (package == null) { throw new ArgumentNullException("package"); } if (loadParameters == null) { throw new ArgumentNullException("loadParameters"); } bool packageDependencyErrors = false; // TODO: Remove and recheck Dependencies Ready if some secondary packages are removed? if (package.State >= PackageState.DependenciesReady) { return; } // 1. Load store package foreach (var packageDependency in package.Meta.Dependencies) { var loadedPackage = session.Packages.Find(packageDependency); if (loadedPackage == null) { var file = PackageStore.Instance.GetPackageFileName(packageDependency.Name, packageDependency.Version, session.constraintProvider); if (file == null) { // TODO: We need to support automatic download of packages. This is not supported yet when only Paradox // package is supposed to be installed, but It will be required for full store log.Error("Unable to find package {0} not installed", packageDependency); packageDependencyErrors = true; continue; } // Recursive load of the system package loadedPackage = PreLoadPackage(session, log, file, true, loadedPackages, loadParameters); } if (loadedPackage == null || loadedPackage.State < PackageState.DependenciesReady) { packageDependencyErrors = true; } } // 2. Load local packages foreach (var packageReference in package.LocalDependencies) { // Check that the package was not already loaded, otherwise return the same instance if (session.Packages.ContainsById(packageReference.Id)) { continue; } // Expand the string of the location var newLocation = (UFile)AssetRegistry.ExpandString(session, packageReference.Location); var subPackageFilePath = package.RootDirectory != null?UPath.Combine(package.RootDirectory, newLocation) : newLocation; // Recursive load var loadedPackage = PreLoadPackage(session, log, subPackageFilePath.FullPath, false, loadedPackages, loadParameters); if (loadedPackage == null || loadedPackage.State < PackageState.DependenciesReady) { packageDependencyErrors = true; } } // 3. Update package state if (!packageDependencyErrors) { package.State = PackageState.DependenciesReady; } }
/// <summary> /// Loads a package from specified file path. /// </summary> /// <param name="filePath">The file path to a package file.</param> /// <param name="sessionResult">The session result.</param> /// <param name="loadParameters">The load parameters.</param> /// <returns>A package.</returns> /// <exception cref="System.ArgumentNullException">filePath</exception> /// <exception cref="System.ArgumentException">File [{0}] must exist.ToFormat(filePath);filePath</exception> public static void Load(string filePath, PackageSessionResult sessionResult, PackageLoadParameters loadParameters = null) { if (filePath == null) { throw new ArgumentNullException("filePath"); } if (sessionResult == null) { throw new ArgumentNullException("sessionResult"); } // Make sure with have valid parameters loadParameters = loadParameters ?? PackageLoadParameters.Default(); // Make sure to use a full path. filePath = FileUtility.GetAbsolutePath(filePath); if (!File.Exists(filePath)) { throw new ArgumentException("File [{0}] must exist".ToFormat(filePath), "filePath"); } try { // Enable reference analysis caching during loading AssetReferenceAnalysis.EnableCaching = true; using (var profile = Profiler.Begin(PackageSessionProfilingKeys.Loading)) { sessionResult.Clear(); sessionResult.Progress("Loading..", 0, 1); var session = new PackageSession(); var packagePaths = new List <string>(); // If we have a solution, load all packages if (PackageSessionHelper.IsSolutionFile(filePath)) { PackageSessionHelper.LoadSolution(session, filePath, packagePaths, sessionResult); } else if (PackageSessionHelper.IsPackageFile(filePath)) { packagePaths.Add(filePath); } else { sessionResult.Error("Unsupported file extension (only .sln or {0} are supported)", Package.PackageFileExtension); return; } var cancelToken = loadParameters.CancelToken; // Load all packages var packagesLoaded = new PackageCollection(); foreach (var packageFilePath in packagePaths) { PreLoadPackage(session, sessionResult, packageFilePath, false, packagesLoaded, loadParameters); // Output the session only if there is no cancellation if (cancelToken.HasValue && cancelToken.Value.IsCancellationRequested) { return; } } // Load all missing references/dependencies session.LoadMissingReferences(sessionResult, loadParameters); // Fix relative references var analysis = new PackageSessionAnalysis(session, GetPackageAnalysisParametersForLoad()); var analysisResults = analysis.Run(); analysisResults.CopyTo(sessionResult); // Run custom package session analysis foreach (var type in AssetRegistry.GetPackageSessionAnalysisTypes()) { var pkgAnalysis = (PackageSessionAnalysisBase)Activator.CreateInstance(type); pkgAnalysis.Session = session; var results = pkgAnalysis.Run(); results.CopyTo(sessionResult); } // Output the session only if there is no cancellation if (!cancelToken.HasValue || !cancelToken.Value.IsCancellationRequested) { sessionResult.Session = session; // Defer the initialization of the dependency manager //session.DependencyManager.InitializeDeferred(); } // The session is not dirty when loading it session.IsDirty = false; } } finally { // Disable reference analysis caching after loading AssetReferenceAnalysis.EnableCaching = false; } }
private static Package PreLoadPackage(PackageSession session, ILogger log, string filePath, bool isSystemPackage, PackageCollection loadedPackages, PackageLoadParameters loadParameters) { if (session == null) { throw new ArgumentNullException("session"); } if (log == null) { throw new ArgumentNullException("log"); } if (filePath == null) { throw new ArgumentNullException("filePath"); } if (loadedPackages == null) { throw new ArgumentNullException("loadedPackages"); } if (loadParameters == null) { throw new ArgumentNullException("loadParameters"); } try { var packageId = Package.GetPackageIdFromFile(filePath); // Check that the package was not already loaded, otherwise return the same instance if (session.Packages.ContainsById(packageId)) { return(session.Packages.Find(packageId)); } // Package is already loaded, use the instance if (loadedPackages.ContainsById(packageId)) { return(loadedPackages.Find(packageId)); } // Load the package without loading any assets var package = Package.LoadRaw(log, filePath); package.IsSystem = isSystemPackage; // Convert UPath to absolute (Package only) // Removed for now because it is called again in PackageSession.LoadAssembliesAndAssets (and running it twice result in dirty package) // If we remove it from here (and call it only in the other method), templates are not loaded (Because they are loaded via the package store that do not use PreLoadPackage) //if (loadParameters.ConvertUPathToAbsolute) //{ // var analysis = new PackageAnalysis(package, new PackageAnalysisParameters() // { // ConvertUPathTo = UPathType.Absolute, // SetDirtyFlagOnAssetWhenFixingAbsoluteUFile = true, // IsProcessingUPaths = true, // }); // analysis.Run(log); //} // If the package doesn't have a meta name, fix it here (This is supposed to be done in the above disabled analysis - but we still need to do it!) if (string.IsNullOrWhiteSpace(package.Meta.Name) && package.FullPath != null) { package.Meta.Name = package.FullPath.GetFileName(); package.IsDirty = true; } // Add the package has loaded before loading dependencies loadedPackages.Add(package); // Package has been loaded, register it in constraints so that we force each subsequent loads to use this one (or fails if version doesn't match) session.constraintProvider.AddConstraint(package.Meta.Name, new VersionSpec(package.Meta.Version.ToSemanticVersion())); // Load package dependencies // This will perform necessary asset upgrades // TODO: We should probably split package loading in two recursive top-level passes (right now those two passes are mixed, making it more difficult to make proper checks) // - First, load raw packages with their dependencies recursively, then resolve dependencies and constraints (and print errors/warnings) // - Then, if everything is OK, load the actual references and assets for each packages PreLoadPackageDependencies(session, log, package, loadedPackages, loadParameters); // Add the package to the session but don't freeze it yet session.Packages.Add(package); return(package); } catch (Exception ex) { log.Error("Error while pre-loading package [{0}]", ex, filePath); } return(null); }
/// <summary> /// Finds an asset from all the packages by its id. /// </summary> /// <param name="session">The session.</param> /// <param name="assetId">The assetId of the asset.</param> /// <returns>An <see cref="AssetItem" /> or <c>null</c> if not found.</returns> public static AssetItem FindAsset(this PackageSession session, AssetId assetId) { var packages = session.Packages; return(packages.Select(packageItem => packageItem.Assets.Find(assetId)).FirstOrDefault(asset => asset != null)); }
private static bool TryLoadAssets(PackageSession session, ILogger log, Package package, PackageLoadParameters loadParameters) { // Already loaded if (package.State >= PackageState.AssetsReady) { return(true); } // Dependencies could not properly be loaded if (package.State < PackageState.DependenciesReady) { return(false); } // A package upgrade has previously been tried and denied, so let's keep the package in this state if (package.State == PackageState.UpgradeFailed) { return(false); } try { // First, check that dependencies have their assets loaded bool dependencyError = false; foreach (var dependency in package.FindDependencies(false, false)) { if (!TryLoadAssets(session, log, dependency, loadParameters)) { dependencyError = true; } } if (dependencyError) { return(false); } var pendingPackageUpgrades = new List <PendingPackageUpgrade>(); // Note: Default state is upgrade failed (for early exit on error/exceptions) // We will update to success as soon as loading is finished. package.State = PackageState.UpgradeFailed; // Process store dependencies for upgraders foreach (var packageDependency in package.Meta.Dependencies) { var dependencyPackage = session.Packages.Find(packageDependency); if (dependencyPackage == null) { continue; } // Check for upgraders var packageUpgrader = session.CheckPackageUpgrade(log, package, packageDependency, dependencyPackage); if (packageUpgrader != null) { pendingPackageUpgrades.Add(new PendingPackageUpgrade(packageUpgrader, packageDependency, dependencyPackage)); } } // Load list of assets var assetFiles = Package.ListAssetFiles(log, package, loadParameters.CancelToken); if (pendingPackageUpgrades.Count > 0) { var upgradeAllowed = true; // Need upgrades, let's ask user confirmation if (loadParameters.PackageUpgradeRequested != null) { upgradeAllowed = loadParameters.PackageUpgradeRequested(package, pendingPackageUpgrades); } if (!upgradeAllowed) { log.Error("Necessary package migration for [{0}] has not been allowed", package.Meta.Name); return(false); } // Perform upgrades foreach (var pendingPackageUpgrade in pendingPackageUpgrades) { var packageUpgrader = pendingPackageUpgrade.PackageUpgrader; var dependencyPackage = pendingPackageUpgrade.DependencyPackage; if (!packageUpgrader.Upgrade(session, log, package, pendingPackageUpgrade.Dependency, dependencyPackage, assetFiles)) { log.Error("Error while upgrading package [{0}] for [{1}] from version [{2}] to [{3}]", package.Meta.Name, dependencyPackage.Meta.Name, pendingPackageUpgrade.Dependency.Version, dependencyPackage.Meta.Version); return(false); } // Update dependency to reflect new requirement pendingPackageUpgrade.Dependency.Version = pendingPackageUpgrade.PackageUpgrader.Attribute.PackageUpdatedVersionRange; } // Mark package as dirty package.IsDirty = true; } // Process the package for assets var newLoadParameters = loadParameters.Clone(); newLoadParameters.AssetFiles = assetFiles; newLoadParameters.AssemblyContainer = session.assemblyContainer; // Default package version override newLoadParameters.ExtraCompileProperties = new Dictionary <string, string>(); var defaultPackageOverride = NugetStore.GetPackageVersionVariable(PackageStore.Instance.DefaultPackageName) + "Override"; var defaultPackageVersion = PackageStore.Instance.DefaultPackageVersion.Version; newLoadParameters.ExtraCompileProperties.Add(defaultPackageOverride, new Version(defaultPackageVersion.Major, defaultPackageVersion.Minor).ToString()); if (loadParameters.ExtraCompileProperties != null) { foreach (var property in loadParameters.ExtraCompileProperties) { newLoadParameters.ExtraCompileProperties[property.Key] = property.Value; } } // Load assemblies and assets package.LoadAssembliesAndAssets(log, newLoadParameters); // Validate assets from package package.ValidateAssets(newLoadParameters.GenerateNewAssetIds); // Mark package as ready package.State = PackageState.AssetsReady; // Freeze the package after loading the assets session.FreezePackage(package); return(true); } catch (Exception ex) { log.Error("Error while loading package [{0}]", ex, package); return(false); } }
public override void Clear() { base.Clear(); Session = null; }
public override bool UpgradeBeforeAssembliesLoaded(PackageSession session, ILogger log, Package dependentPackage, PackageDependency dependency, Package dependencyPackage) { if (dependency.Version.MinVersion < new PackageVersion("1.4.0-alpha01")) { UpgradeCode(dependentPackage, log, new RenameToXenkoCodeUpgrader()); } else if (dependency.Version.MinVersion < new PackageVersion("1.6.0-beta")) { UpgradeCode(dependentPackage, log, new NewComponentsCodeUpgrader()); } return true; }
/// <summary> /// Performs a preprocessing step of package migration, before assembly references are loaded. /// </summary> /// <param name="session">The session.</param> /// <param name="log">The log.</param> /// <param name="dependentPackage">The source package.</param> /// <param name="dependency">The dependency.</param> /// <param name="dependencyPackage">The dependency package.</param> /// <returns></returns> public virtual bool UpgradeBeforeAssembliesLoaded(PackageSession session, ILogger log, Package dependentPackage, PackageDependency dependency, Package dependencyPackage) { return true; }
public void TestMultiplePrefabsMixedInheritance() { // The purpose of this test is to check that modifying a prefab base is correctly propagated through all // derived prefabs. We use the following scenario: // a1: base asset) // a2: inherit from a1 by composition with 2 instances (baseParts: a1, 2 instances) // a3: direct inheritance from a2 (base: a2) // This scenario doesn't happen in practice, as we have restricted only to inheritance by composition for prefabs // but we verify that the code is actually working for this scenario var package = new Package(); var assetItems = package.Assets; // Before Adding Package // a1: a2: (baseParts: a1, 2 instances) a3: (base: a2) // | ea | ea1 (base: ea) | ea1' (base: ea1) // | eb | eb1 (base: eb) | eb1' (base: eb1) // | ea2 (base: ea) | ea2' (base: ea2) // | eb2 (base: eb) | eb2' (base: eb2) // After adding the package to the session // We add one entity to the base a1 // a1: a2: (baseParts: a1, 2 instances) a3: (base: a2) // | ea | ea1 (base: ea) | ea1' (base: ea1) // | eb | eb1 (base: eb) | eb1' (base: eb1) // | ec | ec1 (base: ec) | ec1' (base: ec1) // | ea2 (base: ea) | ea2' (base: ea2) // | eb2 (base: eb) | eb2' (base: eb2) // | ec2 (base: ec) | ec2' (base: ec2) var a1 = new PrefabAsset(); var ea = new Entity("ea"); var eb = new Entity("eb"); a1.Hierarchy.Parts.Add(new EntityDesign(ea)); a1.Hierarchy.Parts.Add(new EntityDesign(eb)); a1.Hierarchy.RootPartIds.Add(ea.Id); a1.Hierarchy.RootPartIds.Add(eb.Id); assetItems.Add(new AssetItem("a1", a1)); var a2 = new PrefabAsset(); var aPartInstance1 = a1.CreatePrefabInstance(a2, "a1"); var aPartInstance2 = a1.CreatePrefabInstance(a2, "a1"); a2.Hierarchy.Parts.AddRange(aPartInstance1.Parts); a2.Hierarchy.Parts.AddRange(aPartInstance2.Parts); a2.Hierarchy.RootPartIds.AddRange(aPartInstance1.RootPartIds); a2.Hierarchy.RootPartIds.AddRange(aPartInstance2.RootPartIds); assetItems.Add(new AssetItem("a2", a2)); // Modify a1 to add entity ec var ec = new Entity("ec"); a1.Hierarchy.Parts.Add(new EntityDesign(ec)); a1.Hierarchy.RootPartIds.Add(ec.Id); var a3 = (PrefabAsset)a2.CreateDerivedAsset("a2"); assetItems.Add(new AssetItem("a3", a3)); // Create a session with this project using (var session = new PackageSession()) { var logger = new LoggerResult(); session.AddExistingPackage(package, logger); Assert.False(logger.HasErrors); Assert.AreEqual(6, a2.Hierarchy.RootPartIds.Count); Assert.True(a2.Hierarchy.Parts.All(it => it.Base != null)); Assert.AreEqual(6, a3.Hierarchy.RootPartIds.Count); Assert.True(a3.Hierarchy.Parts.All(it => it.Base != null && a2.Hierarchy.Parts.ContainsKey(it.Base.BasePartId))); } }
/// <summary> /// Performs the second step of package migration, after assets have been loaded. /// </summary> /// <param name="session">The session.</param> /// <param name="log">The log.</param> /// <param name="dependentPackage">The source package.</param> /// <param name="dependency">The dependency.</param> /// <param name="dependencyPackage">The dependency package.</param> /// <param name="dependencyVersionBeforeUpdate">The version before the update.</param> /// <returns></returns> public virtual bool UpgradeAfterAssetsLoaded(PackageSession session, ILogger log, Package dependentPackage, PackageDependency dependency, Package dependencyPackage, PackageVersionRange dependencyVersionBeforeUpdate) { return true; }
public abstract IEnumerable <string> Select(PackageSession packageSession, IContentIndexMap contentIndexMap);
public abstract IEnumerable<string> Select(PackageSession packageSession, IContentIndexMap contentIndexMap);
private static void GenerateUnitTestProject(string outputDirectory, string templateFile, string name, string projectNamespace) { var projectTemplate = ProjectTemplate.Load(templateFile); // Force reference to Xenko.Assets (to have acess to SolutionPlatform) projectTemplate.Assemblies.Add(typeof(GraphicsProfile).Assembly.FullName); projectTemplate.Assemblies.Add(typeof(XenkoConfig).Assembly.FullName); var options = new Dictionary<string, object>(); // When generating over an existing set of files, retrieve the existing IDs // for better incrementality Guid projectGuid, assetId; GetExistingGuid(outputDirectory, name + ".Windows.csproj", out projectGuid); GetExistingAssetId(outputDirectory, name + ".xkpkg", out assetId); var session = new PackageSession(); var result = new LoggerResult(); var templateGeneratorParameters = new SessionTemplateGeneratorParameters(); templateGeneratorParameters.OutputDirectory = outputDirectory; templateGeneratorParameters.Session = session; templateGeneratorParameters.Name = name; templateGeneratorParameters.Logger = result; templateGeneratorParameters.Description = new TemplateDescription(); templateGeneratorParameters.Id = assetId; if (!PackageUnitTestGenerator.Default.PrepareForRun(templateGeneratorParameters).Result) { Console.WriteLine(@"Error generating package: PackageUnitTestGenerator.PrepareForRun returned false"); return; } if (!PackageUnitTestGenerator.Default.Run(templateGeneratorParameters)) { Console.WriteLine(@"Error generating package: PackageUnitTestGenerator.Run returned false"); return; } if (result.HasErrors) { Console.WriteLine($"Error generating package: {result.ToText()}"); return; } var package = session.LocalPackages.Single(); var previousCurrent = session.CurrentPackage; session.CurrentPackage = package; // Compute Xenko Sdk relative path // We are supposed to be in standard output binary folder, so Xenko root should be at ..\.. var xenkoPath = UPath.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), new UDirectory(@"..\..")); var xenkoRelativePath = new UDirectory(xenkoPath) .MakeRelative(outputDirectory) .ToString() .Replace('/', '\\'); xenkoRelativePath = xenkoRelativePath.TrimEnd('\\'); options["Namespace"] = projectNamespace ?? name; options["Package"] = package; options["Platforms"] = new List<SolutionPlatform>(AssetRegistry.SupportedPlatforms); options["XenkoSdkRelativeDir"] = xenkoRelativePath; // Generate project template result = projectTemplate.Generate(outputDirectory, name, projectGuid, options); if (result.HasErrors) { Console.WriteLine("Error generating solution: {0}", result.ToText()); return; } var sharedProfile = package.Profiles.FindSharedProfile(); // Setup the assets folder Directory.CreateDirectory(UPath.Combine(outputDirectory, (UDirectory)"Assets/Shared")); // Add Windows test as Shared library var projectWindowsRef = new ProjectReference { Id = projectGuid, Location = UPath.Combine(outputDirectory, (UFile)(name + ".Windows.csproj")), Type = SiliconStudio.Assets.ProjectType.Library }; sharedProfile.ProjectReferences.Add(projectWindowsRef); // Generate executable projects for each platform foreach (var platform in AssetRegistry.SupportedPlatforms) { var platformProfile = new PackageProfile(platform.Name) { Platform = platform.Type }; platformProfile.AssetFolders.Add(new AssetFolder("Assets/"+ platform.Name)); // Log progress var projectName = name + "." + platform.Type; // Create project reference var projectPlatformRef = new ProjectReference { Id = projectGuid, Location = UPath.Combine(outputDirectory, (UFile)(projectName + ".csproj")), Type = SiliconStudio.Assets.ProjectType.Executable }; platformProfile.ProjectReferences.Add(projectPlatformRef); // Add build configuration per platform platform.Properties.CopyTo(platformProfile.Properties, true); package.Profiles.Add(platformProfile); } session.CurrentPackage = previousCurrent; result = session.Save(); if (result.HasErrors) { Console.WriteLine("Error saving package: {0}", result.ToText()); return; } }