public override void Execute(ModScriptDatabaseHelper database) { VltCollection srcCollection = GetCollection(database, ClassName, SourceCollectionName); VltCollection dstCollection = GetCollection(database, ClassName, DestinationCollectionName); Dictionary <VltClassField, VLTBaseType> values = new Dictionary <VltClassField, VLTBaseType>(); if ((Options & CopyOptions.Base) != 0) { foreach (var baseField in srcCollection.Class.BaseFields) { values.Add(baseField, ValueCloningUtils.CloneValue(database.Database, srcCollection.GetRawValue(baseField.Name), srcCollection.Class, baseField, dstCollection)); } } if ((Options & CopyOptions.Optional) != 0) { foreach (var(key, value) in srcCollection.GetData()) { var field = srcCollection.Class[key]; if (!field.IsInLayout) { values.Add(field, ValueCloningUtils.CloneValue(database.Database, value, srcCollection.Class, field, dstCollection)); } } } // base will always overwrite // optional by itself will copy anything that doesn't exist // optional + overwrite will copy nonexistent fields and overwrite the other ones(optional only) if ((Options & CopyOptions.Base) != 0) { foreach (var(key, value) in values) { if (key.IsInLayout) { dstCollection.SetRawValue(key.Name, value); } } } if ((Options & CopyOptions.Optional) != 0) { foreach (var(field, value) in values) { if (!field.IsInLayout && (!dstCollection.HasEntry(field.Name) || (Options & CopyOptions.OverwriteOptional) != 0)) { dstCollection.SetRawValue(field.Name, value); } } } }
public override void Execute(ModScriptDatabaseHelper database) { VltCollection collection = GetCollection(database, ClassName, CollectionName); VltClassField field = collection.Class[FieldName]; if (field.IsInLayout) { throw new InvalidDataException($"add_field failed because field '{field.Name}' is a base field"); } if (collection.HasEntry(field.Name)) { throw new InvalidDataException($"add_field failed because collection '{collection.ShortPath}' already has field '{field.Name}'"); } var vltBaseType = TypeRegistry.CreateInstance(database.Database.Options.GameId, collection.Class, field, collection); if (vltBaseType is VLTArrayType array) { if (ArrayCapacity > field.MaxCount) { throw new ModScriptCommandExecutionException( $"Cannot add field {ClassName}[{FieldName}] with capacity beyond maximum (requested {ArrayCapacity} but limit is {field.MaxCount})"); } array.Capacity = ArrayCapacity; array.ItemAlignment = field.Alignment; array.FieldSize = field.Size; array.Items = new List <VLTBaseType>(); for (var i = 0; i < ArrayCapacity; i++) { array.Items.Add(TypeRegistry.ConstructInstance(array.ItemType, collection.Class, field, collection)); } } collection.SetRawValue(field.Name, vltBaseType); }
/// <summary> /// Deserializes the files. /// </summary> public LoadedDatabase Deserialize() { var deserializer = new DeserializerBuilder().Build(); using var dbs = new StreamReader(Path.Combine(_inputDirectory, "info.yml")); var loadedDatabase = deserializer.Deserialize <LoadedDatabase>(dbs); var isX86 = _database.Options.Type == DatabaseType.X86Database; foreach (var loadedDatabaseClass in loadedDatabase.Classes) { var vltClass = new VltClass(loadedDatabaseClass.Name); foreach (var loadedDatabaseClassField in loadedDatabaseClass.Fields) { var field = new VltClassField( isX86 ? VLT32Hasher.Hash(loadedDatabaseClassField.Name) : VLT64Hasher.Hash(loadedDatabaseClassField.Name), loadedDatabaseClassField.Name, loadedDatabaseClassField.TypeName, loadedDatabaseClassField.Flags, loadedDatabaseClassField.Alignment, loadedDatabaseClassField.Size, loadedDatabaseClassField.MaxCount, loadedDatabaseClassField.Offset); // Handle static value if (loadedDatabaseClassField.StaticValue != null) { field.StaticValue = ConvertSerializedValueToDataValue(_database.Options.GameId, _inputDirectory, vltClass, field, null, loadedDatabaseClassField.StaticValue); } vltClass.Fields.Add(field.Key, field); } _database.AddClass(vltClass); } foreach (var loadedDatabaseType in loadedDatabase.Types) { _database.Types.Add(new DatabaseTypeInfo { Name = loadedDatabaseType.Name, Size = loadedDatabaseType.Size }); } var collectionParentDictionary = new Dictionary <string, string>(); var collectionDictionary = new Dictionary <string, VltCollection>(); var vaultsToSaveDictionary = new Dictionary <string, List <Vault> >(); var collectionsToBeAdded = new List <VltCollection>(); foreach (var file in loadedDatabase.Files) { file.LoadedVaults = new List <Vault>(); var baseDirectory = Path.Combine(_inputDirectory, file.Group, file.Name); vaultsToSaveDictionary[file.Name] = new List <Vault>(); foreach (var vault in file.Vaults) { var vaultDirectory = Path.Combine(baseDirectory, vault).Trim(); var newVault = new Vault(vault) { Database = _database, IsPrimaryVault = vault == "db" }; if (Directory.Exists(vaultDirectory)) { HashSet <string> trackedCollections = new HashSet <string>(); foreach (var dataFile in Directory.GetFiles(vaultDirectory, "*.yml")) { var className = Path.GetFileNameWithoutExtension(dataFile); var vltClass = _database.FindClass(className); if (vltClass == null) { throw new InvalidDataException($"Unknown class: {className} ({dataFile})"); } //#if DEBUG // Debug.WriteLine("Processing class '{0}' in vault '{1}' (file: {2})", className, vault, dataFile); //#else // Console.WriteLine("Processing class '{0}' in vault '{1}' (file: {2})", className, vault, dataFile); //#endif using var vr = new StreamReader(dataFile); var collections = deserializer.Deserialize <List <LoadedCollection> >(vr); foreach (var loadedCollection in collections) { // BUG 16.02.2020: we have to do this to get around a YamlDotNet bug if (loadedCollection.Name == null) { loadedCollection.Name = "null"; } foreach (var k in loadedCollection.Data.Keys.ToList().Where(k => loadedCollection.Data[k] == null)) { loadedCollection.Data[k] = "null"; } } var newCollections = new List <VltCollection>(); void AddCollectionsToList(ICollection <VltCollection> collectionList, IEnumerable <LoadedCollection> collectionsToAdd) { if (collectionList == null) { throw new Exception("collectionList should not be null!"); } collectionsToAdd ??= new List <LoadedCollection>(); foreach (var loadedCollection in collectionsToAdd) { var newVltCollection = new VltCollection(newVault, vltClass, loadedCollection.Name); foreach (var(key, value) in loadedCollection.Data) { newVltCollection.SetRawValue(key, ConvertSerializedValueToDataValue(_database.Options.GameId, vaultDirectory, vltClass, vltClass[key], newVltCollection, value)); } collectionParentDictionary[newVltCollection.ShortPath] = loadedCollection.ParentName; collectionList.Add(newVltCollection); collectionDictionary[newVltCollection.ShortPath] = newVltCollection; } } AddCollectionsToList(newCollections, collections); foreach (var newCollection in newCollections) { if (!trackedCollections.Add(newCollection.ShortPath)) { throw new SerializedDatabaseLoaderException($"Duplicate collection found! Multiple collections at '{newCollection.ShortPath}' have been defined in your YML files."); } collectionsToBeAdded.Add(newCollection); } } } else { Console.WriteLine("WARN: vault {0} has no folder; looked for {1}", vault, vaultDirectory); } vaultsToSaveDictionary[file.Name].Add(newVault); _database.Vaults.Add(newVault); file.LoadedVaults.Add(newVault); } } // dependency resolution var resolved = new List <VaultDependencyNode>(); var unresolved = new List <VaultDependencyNode>(); foreach (var vault in _database.Vaults) { var vaultCollections = collectionsToBeAdded.Where(c => c.Vault.Name == vault.Name).ToList(); VaultDependencyNode node = new VaultDependencyNode(vault); foreach (var vaultCollection in vaultCollections) { string parentKey = collectionParentDictionary[vaultCollection.ShortPath]; if (!string.IsNullOrEmpty(parentKey)) { var parentCollection = collectionDictionary[$"{vaultCollection.Class.Name}/{parentKey}"]; if (parentCollection.Vault.Name != vault.Name) { node.AddEdge(new VaultDependencyNode(parentCollection.Vault)); } } } ResolveDependencies(node, resolved, unresolved); Debug.WriteLine("Vault {0}: {1} collections", vault.Name, vaultCollections.Count); } resolved = resolved.Distinct(VaultDependencyNode.VaultComparer).ToList(); unresolved = unresolved.Distinct(VaultDependencyNode.VaultComparer).ToList(); if (unresolved.Count != 0) { throw new SerializedDatabaseLoaderException("Cannot continue loading - unresolved vault dependencies"); } foreach (var node in resolved) { var vault = node.Vault; var vaultCollections = collectionsToBeAdded.Where(c => c.Vault.Name == vault.Name).ToList(); Debug.WriteLine("Loading collections for vault {0} ({1})", vault.Name, vaultCollections.Count); foreach (var collection in vaultCollections) { string parentKey = collectionParentDictionary[collection.ShortPath]; if (string.IsNullOrEmpty(parentKey)) { // Add collection directly _database.RowManager.AddCollection(collection); } else { var parentCollection = collectionDictionary[$"{collection.Class.Name}/{parentKey}"]; parentCollection.AddChild(collection); } } } _loadedDatabase = loadedDatabase; return(loadedDatabase); }