/// <summary> /// Initializes a new instance of the <see cref="MaterialDescriptor"/> class. /// </summary> public MaterialDescriptor() { Attributes = new MaterialAttributes(); Layers = new MaterialBlendLayers(); // An instance id, only used to match descriptor MaterialId = AssetId.New(); }
/// <summary> /// Registers an asset identifier for usage. /// </summary> /// <param name="assetId">The asset identifier.</param> /// <param name="newGuid">The new unique identifier if an asset has already been registered with the same id.</param> /// <returns><c>true</c> if the asset id is already in used. <paramref name="newGuid" /> contains a new guid, <c>false</c> otherwise.</returns> public bool RegisterId(AssetId assetId, out AssetId newGuid) { newGuid = assetId; var result = AlwaysCreateNewId || IsContainingId(assetId); if (result) { newGuid = AssetId.New(); } ExistingIds.Add(newGuid); return(result); }
public void TestHash() { var obj1 = new TestAssetClonerObject { Name = "Test1", SubObject = new TestAssetClonerObject() { Name = "Test2" }, ObjectWithAttachedReference = new TestObjectReference() }; // Create a fake reference to make sure that the attached reference will not be serialized var attachedReference = AttachedReferenceManager.GetOrCreateAttachedReference(obj1.ObjectWithAttachedReference); attachedReference.Url = "just_for_test"; attachedReference.Id = AssetId.New(); var obj2 = AssetCloner.Clone(obj1); var hash1 = AssetHash.Compute(obj1); var hash2 = AssetHash.Compute(obj2); Assert.AreEqual(hash1, hash2); obj1.Name = "Yes"; var hash11 = AssetHash.Compute(obj1); Assert.AreNotEqual(hash11, hash2); obj1.Name = "Test1"; var hash12 = AssetHash.Compute(obj1); Assert.AreEqual(hash12, hash2); obj2 = AssetCloner.Clone(obj1); var hash1WithOverrides = AssetHash.Compute(obj1); var hash2WithOverrides = AssetHash.Compute(obj2); Assert.AreEqual(hash1WithOverrides, hash2WithOverrides); }
public override bool Upgrade(PackageLoadParameters loadParameters, PackageSession session, ILogger log, Package dependentPackage, PackageDependency dependency, Package dependencyPackage, IList <PackageLoadingAssetFile> assetFiles) { #if XENKO_SUPPORT_BETA_UPGRADE // Graphics Compositor asset if (dependency.Version.MinVersion < new PackageVersion("1.11.0.0")) { // Find game settings (if there is none, it's not a game and nothing to do) var gameSettings = assetFiles.FirstOrDefault(x => x.AssetLocation == GameSettingsAsset.GameSettingsLocation); if (gameSettings != null) { RunAssetUpgradersUntilVersion(log, dependentPackage, dependency.Name, gameSettings.Yield().ToList(), new PackageVersion("1.10.0-alpha02")); using (var gameSettingsYaml = gameSettings.AsYamlAsset()) { // Figure out graphics profile; default is Level_10_0 (which is same as GraphicsCompositor default) var graphicsProfile = GraphicsProfile.Level_10_0; try { foreach (var mapping in gameSettingsYaml.DynamicRootNode.Defaults) { if (mapping.Node.Tag == "!Xenko.Graphics.RenderingSettings,Xenko.Graphics") { if (mapping.DefaultGraphicsProfile != null) { Enum.TryParse((string)mapping.DefaultGraphicsProfile, out graphicsProfile); } break; } } } catch { // If something goes wrong, keep going with the default value } // Add graphics compositor asset by creating a derived asset of Compositing/DefaultGraphicsCompositor.xkgfxcomp var graphicsCompositorUrl = graphicsProfile >= GraphicsProfile.Level_10_0 ? DefaultGraphicsCompositorLevel10Url : DefaultGraphicsCompositorLevel9Url; var defaultGraphicsCompositor = dependencyPackage.Assets.Find(graphicsCompositorUrl); if (defaultGraphicsCompositor == null) { log.Error($"Could not find graphics compositor in Xenko package at location [{graphicsCompositorUrl}]"); return(false); } // Note: we create a derived asset without its content // We don't use defaultGraphicsCompositor content because it might be a newer version that next upgrades might not understand. // The override system will restore all the properties for us. var graphicsCompositorAssetId = AssetId.New(); var graphicsCompositorAsset = new PackageLoadingAssetFile(dependentPackage, "GraphicsCompositor.xkgfxcomp", null) { AssetContent = System.Text.Encoding.UTF8.GetBytes($"!GraphicsCompositorAsset\r\nId: {graphicsCompositorAssetId}\r\nSerializedVersion: {{Xenko: 1.10.0-beta01}}\r\nArchetype: {defaultGraphicsCompositor.ToReference()}"), }; assetFiles.Add(graphicsCompositorAsset); // Update game settings to point to our newly created compositor gameSettingsYaml.DynamicRootNode.GraphicsCompositor = new AssetReference(graphicsCompositorAssetId, graphicsCompositorAsset.AssetLocation).ToString(); } } // Delete EffectLogAsset foreach (var assetFile in assetFiles) { if (assetFile.FilePath.GetFileNameWithoutExtension() == EffectLogAsset.DefaultFile) { assetFile.Deleted = true; } } } if (dependency.Version.MinVersion < new PackageVersion("1.11.1.0")) { ConvertNormalMapsInvertY(assetFiles); } // Skybox/Background separation if (dependency.Version.MinVersion < new PackageVersion("1.11.1.1")) { SplitSkyboxLightingUpgrader upgrader = new SplitSkyboxLightingUpgrader(); foreach (var skyboxAsset in assetFiles.Where(f => f.FilePath.GetFileExtension() == ".xksky")) { upgrader.ProcessSkybox(skyboxAsset); } foreach (var sceneAsset in assetFiles.Where(f => (f.FilePath.GetFileExtension() == ".xkscene") || (f.FilePath.GetFileExtension() == ".xkprefab"))) { using (var yaml = sceneAsset.AsYamlAsset()) { upgrader.UpgradeAsset(yaml.DynamicRootNode); } } } if (dependency.Version.MinVersion < new PackageVersion("1.11.1.2")) { var navigationMeshAssets = assetFiles.Where(f => f.FilePath.GetFileExtension() == ".xknavmesh"); var scenes = assetFiles.Where(f => f.FilePath.GetFileExtension() == ".xkscene"); UpgradeNavigationBoundingBox(navigationMeshAssets, scenes); // Upgrade game settings to have groups for navigation meshes var gameSettingsAsset = assetFiles.FirstOrDefault(x => x.AssetLocation == GameSettingsAsset.GameSettingsLocation); if (gameSettingsAsset != null) { // Upgrade the game settings first to contain navigation mesh settings entry RunAssetUpgradersUntilVersion(log, dependentPackage, dependency.Name, gameSettingsAsset.Yield().ToList(), new PackageVersion("1.11.1.2")); UpgradeNavigationMeshGroups(navigationMeshAssets, gameSettingsAsset); } } if (dependency.Version.MinVersion < new PackageVersion("2.0.0.2")) { RunAssetUpgradersUntilVersion(log, dependentPackage, dependency.Name, assetFiles, new PackageVersion("2.0.0.0")); Guid defaultCompositorId = Guid.Empty; var defaultGraphicsCompositorCameraSlot = Guid.Empty; // Step one: find the default compositor, that will be the reference one to patch scenes var gameSettings = assetFiles.FirstOrDefault(x => x.AssetLocation == GameSettingsAsset.GameSettingsLocation); if (gameSettings != null) { using (var gameSettingsYaml = gameSettings.AsYamlAsset()) { dynamic asset = gameSettingsYaml.DynamicRootNode; string compositorReference = asset.GraphicsCompositor?.ToString(); var guidString = compositorReference?.Split(':').FirstOrDefault(); Guid.TryParse(guidString, out defaultCompositorId); // Figure out graphics profile; default is Level_10_0 (which is same as GraphicsCompositor default) var graphicsProfile = GraphicsProfile.Level_10_0; try { foreach (var mapping in gameSettingsYaml.DynamicRootNode.Defaults) { if (mapping.Node.Tag == "!Xenko.Graphics.RenderingSettings,Xenko.Graphics") { if (mapping.DefaultGraphicsProfile != null) { Enum.TryParse((string)mapping.DefaultGraphicsProfile, out graphicsProfile); } break; } } } catch { // If something goes wrong, keep going with the default value } // store the camera slot of the default graphics compositor, because the one from the project will be empty since upgrade relies on reconcile with base, which happens after defaultGraphicsCompositorCameraSlot = graphicsProfile >= GraphicsProfile.Level_10_0 ? DefaultGraphicsCompositorLevel10CameraSlot : DefaultGraphicsCompositorLevel9CameraSlot; } } // Step two: add an Guid for each item in the SceneCameraSlotCollection of each graphics compositor Dictionary <int, Guid> slotIds = new Dictionary <int, Guid>(); // This upgrades a projects that already had a graphics compositor before (ie. a project created with public 1.10) // In this case, the compositor that has been created above is empty, and the upgrade relies on reconciliation with base // to fill it properly, which means that for now we have no camera slot. Fortunately, we know the camera slot id from the archetype. slotIds.Add(0, defaultGraphicsCompositorCameraSlot); var graphicsCompositorAssets = assetFiles.Where(f => f.FilePath.GetFileExtension() == ".xkgfxcomp"); foreach (var graphicsCompositorAsset in graphicsCompositorAssets) { using (var yamlAsset = graphicsCompositorAsset.AsYamlAsset()) { dynamic asset = yamlAsset.DynamicRootNode; int i = 0; var localSlotIds = new Dictionary <int, Guid>(); if (asset.Cameras != null) { // This upgrades a projects that already had a graphics compositor before (ie. an internal project created with 1.11) foreach (dynamic cameraSlot in asset.Cameras) { var guid = Guid.NewGuid(); Guid assetId; if (Guid.TryParse(asset.Id.ToString(), out assetId) && assetId == defaultCompositorId) { slotIds[i] = guid; } localSlotIds.Add(i, guid); cameraSlot.Value.Id = guid; ++i; } var indexString = asset.Game?.Camera?.Index?.ToString(); int index; int.TryParse(indexString, out index); if (localSlotIds.ContainsKey(index) && asset.Game?.Camera != null) { asset.Game.Camera = $"ref!! {localSlotIds[index]}"; } } else { asset.Cameras = new YamlMappingNode(); asset.Cameras.de2e75c3b2b23e54162686363f3f138e = new YamlMappingNode(); asset.Cameras.de2e75c3b2b23e54162686363f3f138e.Id = defaultGraphicsCompositorCameraSlot; asset.Cameras.de2e75c3b2b23e54162686363f3f138e.Name = "Main"; } } } // Step three: patch every CameraComponent to reference the Guid instead of an index var entityHierarchyAssets = assetFiles.Where(f => f.FilePath.GetFileExtension() == ".xkscene" || f.FilePath.GetFileExtension() == ".xkprefab"); foreach (var entityHierarchyAsset in entityHierarchyAssets) { using (var yamlAsset = entityHierarchyAsset.AsYamlAsset()) { dynamic asset = yamlAsset.DynamicRootNode; foreach (var entity in asset.Hierarchy.Parts) { foreach (var component in entity.Entity.Components) { if (component.Value.Node.Tag == "!CameraComponent") { var indexString = component.Value.Slot?.Index?.ToString() ?? "0"; int index; if (int.TryParse(indexString, out index)) { if (slotIds.ContainsKey(index)) { component.Value.Slot = slotIds[index].ToString(); } else { component.Value.Slot = Guid.Empty.ToString(); } } } } } } } } #endif // Put any new upgrader after this #endif if (dependency.Version.MinVersion < new PackageVersion("2.2.0.1")) { foreach (var assetFile in assetFiles) { // Add new generic parameter to ShadowMapReceiverDirectional in effect log if (assetFile.FilePath.GetFileExtension() == ".xkeffectlog") { var assetContent = assetFile.AssetContent ?? File.ReadAllBytes(assetFile.FilePath.FullPath); var assetContentString = System.Text.Encoding.UTF8.GetString(assetContent); var newAssetContentString = System.Text.RegularExpressions.Regex.Replace(assetContentString, @"(\s*- ClassName: ShadowMapReceiverDirectional\r\n\s* GenericArguments: \[\w*, \w*, \w*, \w*, \w*)\]", "$1, false]"); newAssetContentString = newAssetContentString.Replace("EffectName: SkyboxShader\r\n", "EffectName: SkyboxShaderCubemap\r\n"); if (assetContentString != newAssetContentString) { // Need replacement, update with replaced text assetFile.AssetContent = System.Text.Encoding.UTF8.GetBytes(newAssetContentString); } } // Set BackgroundComponent.Is2D when necessary if (assetFile.FilePath.GetFileExtension() == ".xkscene" || assetFile.FilePath.GetFileExtension() == ".xkprefab") { using (var yamlAsset = assetFile.AsYamlAsset()) { dynamic asset = yamlAsset.DynamicRootNode; foreach (var entity in asset.Hierarchy.Parts) { foreach (var component in entity.Entity.Components) { if (component.Value.Node.Tag == "!BackgroundComponent" && component.Value.Texture != null) { if (!AssetReference.TryParse((string)component.Value.Texture, out var textureReference)) { continue; } // Find texture var textureAssetFile = assetFiles.FirstOrDefault(x => x.AssetLocation == textureReference.Location); if (textureAssetFile == null) { continue; } // Get texture source try { using (var yamlTextureAsset = textureAssetFile.AsYamlAsset()) { dynamic textureAsset = yamlTextureAsset.DynamicRootNode; if (textureAsset.Source == null) { continue; } var textureSource = UFile.Combine(textureAssetFile.FilePath.GetFullDirectory(), new UFile((string)textureAsset.Source)); if (!File.Exists(textureSource)) { continue; } var texTool = new TextureTool(); var image = texTool.Load(textureSource, false); if (image != null) { if (image.Dimension != TexImage.TextureDimension.TextureCube) { // We have a texture which is not a cubemap, mark background as 2D component.Value.Is2D = true; } image.Dispose(); } texTool.Dispose(); } } catch { // If something goes wrong, keep default value (assume cubemap) } } } } } } } } if (dependency.Version.MinVersion < new PackageVersion("3.0.0.0")) { // Delete EffectLogAsset foreach (var assetFile in assetFiles) { var assetContent = assetFile.AssetContent ?? File.ReadAllBytes(assetFile.FilePath.FullPath); var assetContentString = System.Text.Encoding.UTF8.GetString(assetContent); var newAssetContentString = RemoveSiliconStudioNamespaces(assetContentString); if (assetContentString != newAssetContentString) { // Need replacement, update with replaced text assetFile.AssetContent = System.Text.Encoding.UTF8.GetBytes(newAssetContentString); } } } return(true); }