public void TestClone() { var originAsset = CreateOriginAsset(); var newAsset = (EntityGroupAsset)AssetCloner.Clone(originAsset); CheckAsset(originAsset, newAsset); }
public void TestClone() { var originAsset = CreateOriginAsset(); var newAsset = (PrefabAsset)AssetCloner.Clone(originAsset); CheckAsset(originAsset, newAsset); }
private bool MergeAsset(AssetItem item, AssetItem existingBase, List <AssetBase> existingBaseParts) { // No need to clone existingBaseParts as they are already cloned var baseCopy = (Asset)AssetCloner.Clone(item.Asset.Base?.Asset); var newBaseCopy = (Asset)AssetCloner.Clone(existingBase?.Asset); // Delegates actual merge to the asset implem var result = item.Asset.Merge(baseCopy, newBaseCopy, existingBaseParts); if (result.HasErrors) { result.CopyTo(log); return(false); } item.Asset = (Asset)result.Asset; if (item.Asset.Base != null) { item.Asset.Base = newBaseCopy != null ? new AssetBase(item.Asset.Base.Location, newBaseCopy) : null; } // Use new existing base parts if (existingBaseParts != null) { item.Asset.BaseParts = existingBaseParts; } item.IsDirty = true; return(true); }
/// <summary> /// This method is called when an asset needs to be tracked /// </summary> /// <returns>AssetDependencies.</returns> private void TrackAsset(AssetId assetId) { lock (ThisLock) { if (trackedAssets.ContainsKey(assetId)) { return; } // TODO provide an optimized version of TrackAsset method // taking directly a well known asset (loaded from a Package...etc.) // to avoid session.FindAsset var assetItem = session.FindAsset(assetId); if (assetItem == null) { return; } // Clone the asset before using it in this instance to make sure that // we have some kind of immutable state // TODO: This is not handling shadow registry // No need to clone assets from readonly package var clonedAsset = assetItem.Package.IsSystem ? assetItem.Asset : AssetCloner.Clone(assetItem.Asset); var trackedAsset = new TrackedAsset(this, assetItem.Asset, clonedAsset); // Adds to global list trackedAssets.Add(assetId, trackedAsset); } }
public void TestNoChanges() { var baseAsset = new TestDiffAsset() { Name = "Red", Value = 1, Dynamic = new DiffValueTypeA() { Text = "Test1" } }; var newBaseAsset = (TestDiffAsset)AssetCloner.Clone(baseAsset); var baseItem = new AssetItem("/base", baseAsset); var childAsset = (TestDiffAsset)baseItem.CreateChildAsset(); var diff = new AssetDiff(baseAsset, childAsset, newBaseAsset) { UseOverrideMode = true }; var diffResult = diff.Compute(); var diffResultStripped = diffResult.FindLeafDifferences().ToList(); // 6: BuildOrder+Name+Value+(Dynamic: Text+Text2+Text3) Assert.AreEqual(6, diffResultStripped.Count); // Check that everything is merging from asset2 Assert.True(diffResultStripped.All(node => node.ChangeType == Diff3ChangeType.MergeFromAsset2)); }
protected virtual object CloneObjectForGameSide(object assetSideObject, IAssetNode assetNode, IGraphNode gameSideNode) { // Null references, they will be handled by the editor asset loader var gameSideValue = AssetCloner.Clone(assetSideObject, AssetClonerFlags.ReferenceAsNull); return(gameSideValue); }
/// <inheritdoc /> public override bool ProcessDeserializedData(AssetPropertyGraphContainer graphContainer, object targetRootObject, Type targetMemberType, ref object data, bool isRootDataObjectReference, AssetId?sourceId, YamlAssetMetadata <OverrideType> overrides, YamlAssetPath basePath) { if (targetRootObject == null) { throw new ArgumentNullException(nameof(targetRootObject)); } if (data == null) { throw new ArgumentNullException(nameof(data)); } var collectionDescriptor = (CollectionDescriptor)TypeDescriptorFactory.Default.Find(targetRootObject.GetType()); var collection = data as IList <AssetItem>; if (collection == null) { collection = (IList <AssetItem>)Activator.CreateInstance(collectionDescriptor.Type, true); collectionDescriptor.Add(collection, data); } for (var i = 0; i < collection.Count; i++) { var assetItem = collection[i]; // If the asset already exists, clone it with new identifiers if (session.GetAssetById(assetItem.Id) != null) { // Create a derived asset and restore archetype to handle asset-specific cloning process. Dictionary <Guid, Guid> idRemapping; var clone = AssetCloner.Clone(assetItem.Asset, AssetClonerFlags.GenerateNewIdsForIdentifiableObjects, out idRemapping); var assetType = assetItem.Asset.GetType(); if (assetType.HasInterface(typeof(AssetCompositeHierarchy <,>))) { try { // TODO: Find a way to fallback to the asset or generalize for all asset composite dynamic assetComposite = clone; // Remap indices of parts in Hierarchy.Part var path = basePath.Clone(); path.PushItemId(CollectionItemIdHelper.GetCollectionItemIds(collection)[i]); AssetCloningHelper.RemapIdentifiablePaths(overrides, idRemapping, path); AssetPartsAnalysis.GenerateNewBaseInstanceIds(assetComposite.Hierarchy); } catch (RuntimeBinderException e) { e.Ignore(); } } // FIXME: rework this var postProcessor = session.ServiceProvider.Get <ICopyPasteService>().PostProcessors.FirstOrDefault(p => p.Accept(assetType)); postProcessor?.PostPasteDeserialization(clone); collection[i] = new AssetItem(assetItem.Location, clone); } } // Get the fixed-up value data = collection; return(true); }
public void TestChangeOverrideToBaseSealed() { var baseAsset = new TestDiffAsset() { Name = "Red", Value = 1 }; var newBaseAsset = (TestDiffAsset)AssetCloner.Clone(baseAsset); newBaseAsset.Value = 3; var baseItem = new AssetItem("/base", baseAsset); var childAsset = (TestDiffAsset)baseItem.CreateChildAsset(); // Change base: Name to Base|Sealed // This should result into a reset of the value overriden in child // Make New on Name value on first element var objDesc = TypeDescriptorFactory.Default.Find(typeof(TestDiffAsset)); var memberDesc = objDesc.Members.First(t => t.Name == "Value"); newBaseAsset.SetOverride(memberDesc, OverrideType.Base | OverrideType.Sealed); var diff = new AssetDiff(baseAsset, childAsset, newBaseAsset) { UseOverrideMode = true }; var diffResult = diff.Compute(); // Check that merged result on Dynamic property is instance from asset2 var mergeResult = AssetMerge.Merge(diff, AssetMergePolicies.MergePolicyAsset2AsNewBaseOfAsset1); Assert.AreEqual(3, childAsset.Value); // Value is coming from base Assert.AreEqual(OverrideType.Base | OverrideType.Sealed, childAsset.GetOverride(memberDesc)); // Value is coming from base }
private void UpdateGameSettings(GameSettingsAsset gameSettings) { currentGameSettings = AssetCloner.Clone(gameSettings, AssetClonerFlags.RemoveUnloadableObjects); bool shouldRefreshAllThumbnails = false; if (renderingMode != gameSettings.GetOrCreate <EditorSettings>().RenderingMode) { renderingMode = gameSettings.GetOrCreate <EditorSettings>().RenderingMode; shouldRefreshAllThumbnails = true; } if (colorSpace != gameSettings.GetOrCreate <RenderingSettings>().ColorSpace) { colorSpace = gameSettings.GetOrCreate <RenderingSettings>().ColorSpace; shouldRefreshAllThumbnails = true; } if (graphicsProfile != gameSettings.GetOrCreate <RenderingSettings>().DefaultGraphicsProfile) { graphicsProfile = gameSettings.GetOrCreate <RenderingSettings>().DefaultGraphicsProfile; shouldRefreshAllThumbnails = true; } if (shouldRefreshAllThumbnails) { var allAssets = session.AllAssets.Select(x => x.AssetItem).ToList(); Task.Run(() => AddThumbnailAssetItems(allAssets, QueuePosition.First)); } }
/// <inheritdoc /> protected override IEnumerable <AssetItem> CreateAssets(AssetTemplateGeneratorParameters parameters) { var importedAssets = new List <AssetItem>(); foreach (var assetItem in base.CreateAssets(parameters)) { if (assetItem.Asset is SoundAsset soundAsset) { using (var media = new FFmpegMedia()) { media.Open(soundAsset.Source.ToWindowsPath()); var audioStreams = media.Streams.OfType <AudioStream>().ToList(); foreach (var audioTrack in audioStreams) { var assetCopy = AssetCloner.Clone(soundAsset); assetCopy.Index = audioTrack.Index; assetCopy.SampleRate = audioTrack.SampleRate; // If there's more than one streams, append the track index to the asset name var fileLocation = audioStreams.Count > 1 ? (UFile)(assetItem.Location + " track " + audioTrack.Index) : assetItem.Location; importedAssets.Add(new AssetItem(fileLocation, assetCopy)); } } } } return(MakeUniqueNames(importedAssets)); }
public void TestClone() { var originAsset = CreateOriginAsset(); var newAsset = AssetCloner.Clone(originAsset); CheckAsset(originAsset, newAsset, originAsset.Hierarchy.Parts.Select(x => x.Value.Entity.Id).ToDictionary(x => x, x => x)); }
public void TestCloneCollectionIds() { var obj = new TestObjectWithCollection { Name = "Test", Items = { "aaa", "bbb" } }; var ids = CollectionItemIdHelper.GetCollectionItemIds(obj.Items); ids.Add(0, new ItemId()); ids.Add(1, new ItemId()); ids.MarkAsDeleted(new ItemId()); var clone = AssetCloner.Clone(obj); CollectionItemIdentifiers cloneIds; var idsExist = CollectionItemIdHelper.TryGetCollectionItemIds(clone.Items, out cloneIds); Assert.True(idsExist); Assert.AreEqual(ids.KeyCount, cloneIds.KeyCount); Assert.AreEqual(ids.DeletedCount, cloneIds.DeletedCount); Assert.AreEqual(ids[0], cloneIds[0]); Assert.AreEqual(ids[1], cloneIds[1]); Assert.AreEqual(ids.DeletedItems.Single(), cloneIds.DeletedItems.Single()); clone = AssetCloner.Clone(obj, AssetClonerFlags.RemoveItemIds); idsExist = CollectionItemIdHelper.TryGetCollectionItemIds(clone.Items, out cloneIds); Assert.False(idsExist); }
protected override void Prepare(AssetCompilerContext context, AssetItem assetItem, string targetUrlInStorage, AssetCompilerResult result) { var asset = (SpriteFontAsset)assetItem.Asset; UFile assetAbsolutePath = assetItem.FullPath; var colorSpace = context.GetColorSpace(); var fontTypeSdf = asset.FontType as SignedDistanceFieldSpriteFontType; if (fontTypeSdf != null) { // copy the asset and transform the source and character set file path to absolute paths var assetClone = AssetCloner.Clone(asset); var assetDirectory = assetAbsolutePath.GetParent(); assetClone.FontSource = asset.FontSource; fontTypeSdf.CharacterSet = !string.IsNullOrEmpty(fontTypeSdf.CharacterSet) ? UPath.Combine(assetDirectory, fontTypeSdf.CharacterSet) : null; result.BuildSteps = new AssetBuildStep(assetItem); result.BuildSteps.Add(new SignedDistanceFieldFontCommand(targetUrlInStorage, assetClone, assetItem.Package)); } else if (asset.FontType is RuntimeRasterizedSpriteFontType) { UFile fontPathOnDisk = asset.FontSource.GetFontPath(result); if (fontPathOnDisk == null) { result.Error($"Runtime rasterized font compilation failed. Font {asset.FontSource.GetFontName()} was not found on this machine."); result.BuildSteps = new AssetBuildStep(assetItem); result.BuildSteps.Add(new FailedFontCommand()); return; } var fontImportLocation = FontHelper.GetFontPath(asset.FontSource.GetFontName(), asset.FontSource.Style); result.BuildSteps = new AssetBuildStep(assetItem); result.BuildSteps.Add(new ImportStreamCommand { SourcePath = fontPathOnDisk, Location = fontImportLocation }); result.BuildSteps.Add(new RuntimeRasterizedFontCommand(targetUrlInStorage, asset, assetItem.Package)); } else { var fontTypeStatic = asset.FontType as OfflineRasterizedSpriteFontType; if (fontTypeStatic == null) { throw new ArgumentException("Tried to compile a non-offline rasterized sprite font with the compiler for offline resterized fonts!"); } // copy the asset and transform the source and character set file path to absolute paths var assetClone = AssetCloner.Clone(asset); var assetDirectory = assetAbsolutePath.GetParent(); assetClone.FontSource = asset.FontSource; fontTypeStatic.CharacterSet = !string.IsNullOrEmpty(fontTypeStatic.CharacterSet) ? UPath.Combine(assetDirectory, fontTypeStatic.CharacterSet): null; result.BuildSteps = new AssetBuildStep(assetItem); result.BuildSteps.Add(new OfflineRasterizedFontCommand(targetUrlInStorage, assetClone, colorSpace, assetItem.Package) { InputFilesGetter = () => GetInputFiles(assetItem) }); } }
public void TestCloneAndShadowObject() { var obj = new TestAssetClonerObject { Name = "Test1", SubObject = new TestAssetClonerObject() { Name = "Test2" } }; var objDesc = TypeDescriptorFactory.Default.Find(typeof(TestAssetClonerObject)); var memberDesc = objDesc.Members.First(t => t.Name == "Name"); obj.SetOverride(memberDesc, OverrideType.New); obj.SubObject.SetOverride(memberDesc, OverrideType.Sealed); var newInstance = (TestAssetClonerObject)AssetCloner.Clone(obj); // Check that we are getting shadow objects Assert.AreEqual(OverrideType.New, newInstance.GetOverride(memberDesc)); Assert.AreEqual(OverrideType.Sealed, newInstance.SubObject.GetOverride(memberDesc)); // Change original object to default, but check that we are working on a shadow object copy on the cloned object obj.SetOverride(memberDesc, OverrideType.Base); Assert.AreEqual(OverrideType.New, newInstance.GetOverride(memberDesc)); }
/// <inheritdoc /> protected override IEnumerable <AssetItem> CreateAssets(AssetTemplateGeneratorParameters parameters) { var importedAssets = new List <AssetItem>(); foreach (var assetItem in base.CreateAssets(parameters)) { if (assetItem.Asset is SoundAsset soundAsset) { using (var media = new FFmpegMedia()) { media.Open(soundAsset.Source.ToWindowsPath()); foreach (var audioTrack in media.Streams.OfType <AudioStream>().ToList()) { var assetCopy = AssetCloner.Clone(soundAsset); assetCopy.Index = audioTrack.Index; assetCopy.SampleRate = audioTrack.SampleRate; importedAssets.Add(new AssetItem(assetItem.Location + (audioTrack.Index > 0 ? " track " + audioTrack.Index : ""), assetCopy)); } } } } return(MakeUniqueNames(importedAssets)); }
private static List <IInlineColliderShapeDesc> CloneDescs(IEnumerable <IInlineColliderShapeDesc> descs) { var res = new List <IInlineColliderShapeDesc>(); foreach (var desc in descs) { if (desc == null) { res.Add(null); } else { if (desc.GetType() == typeof(ColliderShapeAssetDesc)) { var sourceDesc = (ColliderShapeAssetDesc)desc; var assetDesc = new ColliderShapeAssetDesc { Shape = sourceDesc.Shape }; res.Add(assetDesc); } else { var cloned = AssetCloner.Clone(desc, AssetClonerFlags.KeepReferences); res.Add(cloned); } } } return(res); }
public void TestMergePropertyContainer() { var baseDic = new ObjectWithPropertyContainer(); var newDic = new ObjectWithPropertyContainer(); var newBaseDic = new ObjectWithPropertyContainer() { Items = new PropertyContainer() { { DiffComponent.Key, new DiffComponent() { Name = "NewComponent" } }, } }; var diff = new AssetDiff(AssetCloner.Clone(baseDic), newDic, AssetCloner.Clone(newBaseDic)) { UseOverrideMode = true }; var result = AssetMerge.Merge(diff, AssetMergePolicies.MergePolicyAsset2AsNewBaseOfAsset1); Assert.False(result.HasErrors); Assert.AreEqual(1, newDic.Items.Count); }
protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { // Reduce trees on CPU //var materialReducer = new MaterialTreeReducer(material); //materialReducer.ReduceTrees(); //foreach (var reducedTree in materialReducer.ReducedTrees) //{ // material.Nodes[reducedTree.Key] = reducedTree.Value; //} // Reduce on GPU // TODO: Use the build engine processed output textures instead of the imported one (not existing any more) // TODO: Set the reduced texture output format // TODO: The graphics device cannot be shared with the Previewer //var graphicsDevice = (GraphicsDevice)context.Attributes.GetOrAdd(CompilerContext.GraphicsDeviceKey, key => GraphicsDevice.New(DeviceCreationFlags.None, GraphicsProfile.Level_11_0)); //using (var materialTextureLayerFlattener = new MaterialTextureLayerFlattener(material, graphicsDevice)) //{ // materialTextureLayerFlattener.PrepareForFlattening(new UDirectory(assetUrl.Directory)); // if (materialTextureLayerFlattener.HasCommands) // { // var compiler = EffectCompileCommand.GetOrCreateEffectCompiler(context); // materialTextureLayerFlattener.Run(compiler); // // store Material with modified textures // material = materialTextureLayerFlattener.Material; // } //} // TODO: Check with Ben why DoCommandOverride is called without going through the constructor? var assetManager = new ContentManager(MicrothreadLocalDatabases.ProviderService); var materialContext = new MaterialGeneratorContext { GraphicsProfile = graphicsProfile, Content = assetManager, ColorSpace = colorSpace }; materialContext.AddLoadingFromSession(AssetFinder); var materialClone = AssetCloner.Clone(Parameters); var result = MaterialGenerator.Generate(new MaterialDescriptor { MaterialId = materialClone.Id, Attributes = materialClone.Attributes, Layers = materialClone.Layers }, materialContext, string.Format("{0}:{1}", materialClone.Id, assetUrl)); if (result.HasErrors) { result.CopyTo(commandContext.Logger); return(Task.FromResult(ResultStatus.Failed)); } // Create the parameters //var materialParameterCreator = new MaterialParametersCreator(material, assetUrl); //if (materialParameterCreator.CreateParameterCollectionData(commandContext.Logger)) // return Task.FromResult(ResultStatus.Failed); assetManager.Save(assetUrl, result.Material); return(Task.FromResult(ResultStatus.Successful)); }
public void TestCloneWithNewIds() { var originAsset = CreateOriginAsset(); Dictionary <Guid, Guid> idRemapping; var newAsset = AssetCloner.Clone(originAsset, AssetClonerFlags.GenerateNewIdsForIdentifiableObjects, out idRemapping); CheckAsset(originAsset, newAsset, idRemapping); }
public static GameSettingsAsset CloneGameSettingsAsset(this Package package) { lock (package) { var gameSettings = package.GetGameSettingsAssetOrDefault(); return((GameSettingsAsset)AssetCloner.Clone(gameSettings)); } }
/// <summary> /// Clones a sub-hierarchy of this asset. /// </summary> /// <param name="sourceRootEntity">The entity that is the root of the sub-hierarchy to clone</param> /// <param name="cleanReference">If true, any reference to an entity external to the cloned hierarchy will be set to null.</param> /// <param name="entityMapping">A dictionary containing the mapping of ids from the source entites to the new entities.</param> /// <returns>A <see cref="EntityHierarchyData"/> corresponding to the cloned entities.</returns> public EntityHierarchyData CloneSubHierarchy(Guid sourceRootEntity, bool cleanReference, out Dictionary <Guid, Guid> entityMapping) { if (!Hierarchy.Entities.ContainsKey(sourceRootEntity)) { throw new ArgumentException(@"The source root entity must be an entity of this asset.", nameof(sourceRootEntity)); } // Note: Instead of copying the whole asset (with its potentially big hierarchy), // we first copy the asset only (without the hierarchy), then the sub-hierarchy to extract. var subTreeRoot = Hierarchy.Entities[sourceRootEntity]; var subTreeHierarchy = new EntityHierarchyData { Entities = { subTreeRoot }, RootEntities = { sourceRootEntity } }; foreach (var subTreeEntity in EnumerateChildren(subTreeRoot, true)) { subTreeHierarchy.Entities.Add(Hierarchy.Entities[subTreeEntity.Entity.Id]); } // clone the entities of the sub-tree var clonedHierarchy = (EntityHierarchyData)AssetCloner.Clone(subTreeHierarchy); clonedHierarchy.Entities[sourceRootEntity].Entity.Transform.Parent = null; if (cleanReference) { // set to null reference outside of the sub-tree EntityAnalysis.FixupEntityReferences(clonedHierarchy); } // temporary nullify the hierarchy to avoid to clone it var sourceHierarchy = Hierarchy; Hierarchy = null; // revert the source hierarchy Hierarchy = sourceHierarchy; // Generate entity mapping entityMapping = new Dictionary <Guid, Guid>(); foreach (var entityDesign in clonedHierarchy.Entities) { // Generate new Id var newEntityId = Guid.NewGuid(); // Update mappings entityMapping.Add(entityDesign.Entity.Id, newEntityId); // Update entity with new id entityDesign.Entity.Id = newEntityId; } // Rewrite entity references // Should we nullify invalid references? EntityAnalysis.RemapEntitiesId(clonedHierarchy, entityMapping); return(clonedHierarchy); }
public void TestListWithIdsNoConflicts() { var baseAsset = new TestDiffAsset() { Name = "Red", Value = 1 }; baseAsset.List.Add(new DiffComponent() { Name = "Test1", Position = new Vector4(1, 0, 0, 0) }); baseAsset.List.Add(new DiffComponent() { Name = "Test2", Position = new Vector4(1, 0, 0, 0) }); baseAsset.List.Add(new DiffComponent() { Name = "Test3", Position = new Vector4(1, 0, 0, 0) }); var newBaseAsset = (TestDiffAsset)AssetCloner.Clone(baseAsset); var baseItem = new AssetItem("/base", baseAsset); var childAsset = (TestDiffAsset)baseItem.CreateChildAsset(); var diff = new AssetDiff(baseAsset, childAsset, newBaseAsset) { UseOverrideMode = true }; var diffResult = diff.Compute(); var diffResultStripped = diffResult.FindLeafDifferences().ToList(); // Expecting only 2 diff from TestDiffAsset (3 properties + BuildOrder) Assert.AreEqual(4, diffResultStripped.Where(item => item.BaseNode.Parent?.Instance is TestDiffAsset).Count()); // Expecting 6 diffs for DiffComponent (3 elements, 5 properties (Name + Vector4)) Assert.AreEqual(3 * 5, diffResultStripped.Where(item => item.BaseNode.Parent?.Instance is DiffComponent || item.BaseNode.Parent?.Parent?.Instance is DiffComponent).Count()); // All changes must be from asset2 (considered as new base), as everything is setting base Assert.True(diffResultStripped.All(item => item.ChangeType == Diff3ChangeType.MergeFromAsset2)); foreach (var node in diffResultStripped.Where(item => item.BaseNode.Parent.Instance is DiffComponent)) { var base1 = (DiffComponent)node.BaseNode.Parent.Instance; var asset1 = (DiffComponent)node.Asset1Node.Parent.Instance; var asset2 = (DiffComponent)node.Asset2Node.Parent.Instance; var baseIndex = baseAsset.List.IndexOf(base1); var asset1Index = childAsset.List.IndexOf(asset1); var asset2Index = newBaseAsset.List.IndexOf(asset2); Assert.AreEqual(baseIndex, asset1Index); Assert.AreEqual(baseIndex, asset2Index); } }
public void TestAssetClonerContent() { var obj1 = new TestAssetClonerContent { Content = new TestContent() }; var obj2 = AssetCloner.Clone(obj1, AssetClonerFlags.KeepReferences); Assert.Equal(obj1.Content, obj2.Content); }
protected override void Compile(AssetCompilerContext context, string urlInStorage, UFile assetAbsolutePath, SpriteFontAsset asset, AssetCompilerResult result) { var colorSpace = context.GetColorSpace(); if (asset.FontType is SignedDistanceFieldSpriteFontType) { var fontTypeSDF = asset.FontType as SignedDistanceFieldSpriteFontType; // copy the asset and transform the source and character set file path to absolute paths var assetClone = (SpriteFontAsset)AssetCloner.Clone(asset); var assetDirectory = assetAbsolutePath.GetParent(); assetClone.FontSource = asset.FontSource; fontTypeSDF.CharacterSet = !string.IsNullOrEmpty(fontTypeSDF.CharacterSet) ? UPath.Combine(assetDirectory, fontTypeSDF.CharacterSet) : null; result.BuildSteps = new AssetBuildStep(AssetItem) { new SignedDistanceFieldFontCommand(urlInStorage, assetClone) }; } else if (asset.FontType is RuntimeRasterizedSpriteFontType) { UFile fontPathOnDisk; fontPathOnDisk = asset.FontSource.GetFontPath(); var fontImportLocation = FontHelper.GetFontPath(asset.FontSource.GetFontName(), asset.FontSource.Style); result.BuildSteps = new AssetBuildStep(AssetItem) { new ImportStreamCommand { SourcePath = fontPathOnDisk, Location = fontImportLocation }, new RuntimeRasterizedFontCommand(urlInStorage, asset) }; } else { var fontTypeStatic = asset.FontType as OfflineRasterizedSpriteFontType; if (fontTypeStatic == null) { throw new ArgumentException("Tried to compile a dynamic sprite font with compiler for signed distance field fonts"); } // copy the asset and transform the source and character set file path to absolute paths var assetClone = (SpriteFontAsset)AssetCloner.Clone(asset); var assetDirectory = assetAbsolutePath.GetParent(); assetClone.FontSource = asset.FontSource; fontTypeStatic.CharacterSet = !string.IsNullOrEmpty(fontTypeStatic.CharacterSet) ? UPath.Combine(assetDirectory, fontTypeStatic.CharacterSet): null; result.BuildSteps = new AssetBuildStep(AssetItem) { new OfflineRasterizedFontCommand(urlInStorage, assetClone, colorSpace) }; } }
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 = Guid.NewGuid(); // Setup some proper id on objects so serialization is stable IdentifiableHelper.SetId(obj1, new Guid("EC86143E-896F-45C5-9A4D-627317D22955")); IdentifiableHelper.SetId(obj1.SubObject, new Guid("34E160CD-1D94-468E-8BFD-F82FF96013FC")); var obj2 = (TestAssetClonerObject)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); // Test the same with overrides var objDesc = TypeDescriptorFactory.Default.Find(typeof(TestAssetClonerObject)); var memberDesc = objDesc.Members.First(t => t.Name == "Name"); obj1.SetOverride(memberDesc, OverrideType.New); obj1.SubObject.SetOverride(memberDesc, OverrideType.Sealed); obj2 = (TestAssetClonerObject)AssetCloner.Clone(obj1); var hash1WithOverrides = AssetHash.Compute(obj1); var hash2WithOverrides = AssetHash.Compute(obj2); Assert.AreNotEqual(hash1, hash1WithOverrides); Assert.AreNotEqual(hash2, hash2WithOverrides); Assert.AreEqual(hash1WithOverrides, hash2WithOverrides); }
/// <inheritdoc /> public override bool ProcessDeserializedData(AssetPropertyGraphContainer graphContainer, object targetRootObject, Type targetMemberType, ref object data, bool isRootDataObjectReference, AssetId?sourceId, YamlAssetMetadata <OverrideType> overrides, YamlAssetPath basePath) { var asset = (AssetCompositeHierarchy <TAssetPartDesign, TAssetPart>)targetRootObject; var hierarchy = data as AssetCompositeHierarchyData <TAssetPartDesign, TAssetPart>; if (hierarchy == null) { return(false); } // Create a temporary asset to host the hierarchy to paste, so we have a property graph to manipulate it. var tempAsset = (AssetCompositeHierarchy <TAssetPartDesign, TAssetPart>)Activator.CreateInstance(asset.GetType()); tempAsset.Hierarchy = hierarchy; // Use temporary containers so that any created nodes are discarded after the processing. var tempNodeContainer = new AssetNodeContainer { NodeBuilder = { NodeFactory = new AssetNodeFactory() } }; var definition = AssetQuantumRegistry.GetDefinition(asset.GetType()); var rootNode = tempNodeContainer.GetOrCreateNode(tempAsset); // If different asset or if at least one part already exists, create a custom clone. if (asset.Id != sourceId || hierarchy.Parts.Values.Any(part => asset.ContainsPart(part.Part.Id))) { // Clone again to create new ids for any IIdentifiable, but keep references to external object intact. var cloneExternalReferences = ExternalReferenceCollector.GetExternalReferences(definition, rootNode); hierarchy = AssetCloner.Clone(hierarchy, AssetClonerFlags.GenerateNewIdsForIdentifiableObjects, cloneExternalReferences, out var idRemapping); // Remap indices of parts in Hierarchy.Part AssetCloningHelper.RemapIdentifiablePaths(overrides, idRemapping, basePath); // Make new base instances ids in case the part are inherited. AssetPartsAnalysis.GenerateNewBaseInstanceIds(hierarchy); // Update the temporary asset with this cloned hierarchy. rootNode[nameof(AssetCompositeHierarchy <TAssetPartDesign, TAssetPart> .Hierarchy)].Update(hierarchy); } // Collect all referenceable objects from the target asset (where we're pasting) var targetPropertyGraph = graphContainer.TryGetGraph(asset.Id); var referenceableObjects = IdentifiableObjectCollector.Collect(targetPropertyGraph.Definition, targetPropertyGraph.RootNode); // Replace references in the hierarchy being pasted by the real objects from the target asset. var externalReferences = new HashSet <Guid>(ExternalReferenceCollector.GetExternalReferences(definition, rootNode).Select(x => x.Id)); var visitor = new ObjectReferencePathGenerator(definition) { ShouldOutputReference = x => externalReferences.Contains(x) }; visitor.Visit(rootNode); FixupObjectReferences.FixupReferences(tempAsset, visitor.Result, referenceableObjects, true); data = hierarchy; return(true); }
protected override void Compile(AssetCompilerContext context, string urlInStorage, UFile assetAbsolutePath, SpriteFontAsset asset, AssetCompilerResult result) { var colorSpace = context.GetColorSpace(); if (asset.IsDynamic) { UFile fontPathOnDisk; if (!string.IsNullOrEmpty(asset.Source)) { var assetDirectory = assetAbsolutePath.GetParent(); fontPathOnDisk = UPath.Combine(assetDirectory, asset.Source); if (!File.Exists(fontPathOnDisk)) { result.Error("The font source '{0}' does not exist on the PC.", asset.FontName); return; } // set the source filename as font name instead of the font family. asset.FontName = fontPathOnDisk.GetFileName(); } else { fontPathOnDisk = GetFontPath(asset, result); if (fontPathOnDisk == null) { result.Error("The font named '{0}' could not be located on the PC.", asset.FontName); return; } } var fontImportLocation = FontHelper.GetFontPath(asset.FontName, asset.Style); result.BuildSteps = new AssetBuildStep(AssetItem) { new ImportStreamCommand { SourcePath = fontPathOnDisk, Location = fontImportLocation }, new DynamicFontCommand(urlInStorage, asset) }; } else { // copy the asset and transform the source and character set file path to absolute paths var assetClone = (SpriteFontAsset)AssetCloner.Clone(asset); var assetDirectory = assetAbsolutePath.GetParent(); assetClone.Source = !string.IsNullOrEmpty(asset.Source) ? UPath.Combine(assetDirectory, asset.Source): null; assetClone.CharacterSet = !string.IsNullOrEmpty(asset.CharacterSet) ? UPath.Combine(assetDirectory, asset.CharacterSet): null; result.BuildSteps = new AssetBuildStep(AssetItem) { new StaticFontCommand(urlInStorage, assetClone, colorSpace) }; } }
/// <summary> /// Merges the specified assets from <c>base</c> and <c>from2</c> into <c>from1</c>. /// </summary> /// <param name="assetBase">The asset base.</param> /// <param name="assetFrom1">The asset from1.</param> /// <param name="assetFrom2">The asset from2.</param> /// <param name="mergePolicy">The merge policy. See <see cref="AssetMergePolicies" /> for default policies.</param> /// <returns>The result of the merge.</returns> /// <exception cref="System.ArgumentNullException"> /// assetFrom1 /// or /// mergePolicy /// </exception> public static MergeResult Merge(Asset assetBase, Asset assetFrom1, Asset assetFrom2, MergePolicyDelegate mergePolicy) { if (assetFrom1 == null) { throw new ArgumentNullException("assetFrom1"); } if (mergePolicy == null) { throw new ArgumentNullException("mergePolicy"); } return(Merge(new AssetDiff((Asset)AssetCloner.Clone(assetBase), (Asset)AssetCloner.Clone(assetFrom1), (Asset)AssetCloner.Clone(assetFrom2)), mergePolicy)); }
private void EnsureClonedSceneAndHash() { if (!sceneCloned) { // Hash relevant scene objects if (asset.Scene != null) { string sceneUrl = AttachedReferenceManager.GetUrl(asset.Scene); var sceneAsset = (SceneAsset)package.Session.FindAsset(sceneUrl)?.Asset; // Clone scene asset because we update the world transformation matrices clonedSceneAsset = (SceneAsset)AssetCloner.Clone(sceneAsset); // Turn the entire entity hierarchy into a single list sceneEntities = clonedSceneAsset.Hierarchy.Parts.Select(x => x.Entity).ToList(); sceneHash = 0; foreach (var entity in sceneEntities) { StaticColliderComponent collider = entity.Get <StaticColliderComponent>(); // Only process enabled colliders bool colliderEnabled = collider != null && ((CollisionFilterGroupFlags)collider.CollisionGroup & asset.IncludedCollisionGroups) != 0 && collider.Enabled; if (colliderEnabled) // Removed or disabled { // Update world transform before hashing entity.Transform.UpdateWorldMatrix(); // Load collider shape assets since the scene asset is being used, which does not have these loaded by default foreach (var desc in collider.ColliderShapes) { var shapeAssetDesc = desc as ColliderShapeAssetDesc; if (shapeAssetDesc?.Shape != null) { var assetReference = AttachedReferenceManager.GetAttachedReference(shapeAssetDesc.Shape); PhysicsColliderShape loadedColliderShape; if (!loadedColliderShapes.TryGetValue(assetReference.Url, out loadedColliderShape)) { loadedColliderShape = contentManager.Load <PhysicsColliderShape>(assetReference.Url); loadedColliderShapes.Add(assetReference.Url, loadedColliderShape); // Store where we loaded the shapes from } shapeAssetDesc.Shape = loadedColliderShape; } } // Finally compute the hash for this collider sceneHash += NavigationMeshBuildUtils.HashEntityCollider(collider); } } } sceneCloned = true; } }
public void TestListWithIdsChangeType() { var baseAsset = new TestDiffAsset() { Name = "Red", Value = 1 }; baseAsset.List.Add(new DiffComponent() { Name = "Test1", Position = new Vector4(1, 0, 0, 0) }); baseAsset.List.Add(new DiffComponent() { Name = "Test2", Position = new Vector4(1, 0, 0, 0) }); baseAsset.List.Add(new DiffComponent() { Name = "Test3", Position = new Vector4(1, 0, 0, 0) }); // Change type of 2nd element in newBase list var newBaseAsset = (TestDiffAsset)AssetCloner.Clone(baseAsset); newBaseAsset.List[1] = new DiffComponentSub() { Value = 1 }; var baseItem = new AssetItem("/base", baseAsset); var childAsset = (TestDiffAsset)baseItem.CreateChildAsset(); var diff = new AssetDiff(baseAsset, childAsset, newBaseAsset) { UseOverrideMode = true }; var diffResult = diff.Compute(); var diffList = diffResult.Members.First(node => ((DataVisitMember)node.Asset1Node).MemberDescriptor.Name == "List"); // Check that we have only 3 items Assert.AreEqual(3, diffList.Items.Count); Assert.AreEqual(Diff3ChangeType.MergeFromAsset2, diffList.Items[1].ChangeType); var mergeResult = AssetMerge.Merge(diff, AssetMergePolicies.MergePolicyAsset2AsNewBaseOfAsset1); Assert.False(mergeResult.HasErrors); Assert.AreEqual(3, childAsset.List.Count); Assert.AreEqual("Test1", childAsset.List[0].Name); Assert.True(childAsset.List[1] is DiffComponentSub); Assert.AreEqual("Test3", childAsset.List[2].Name); }