/// <summary> /// Remove the asset mapping from the table entry and also cleans up the Addressables if necessary. /// </summary> /// <param name="table"></param> /// <param name="entryReference"></param> /// <param name="createUndo"></param> public void RemoveAssetFromTable(AssetTable table, TableEntryReference entryReference, bool createUndo = false) { using (new UndoScope("Remove asset from table", createUndo)) { // Clear the asset but keep the key var tableEntry = table.GetEntryFromReference(entryReference); if (tableEntry == null) { return; } var removedAssetGuid = tableEntry.Guid; tableEntry.Guid = string.Empty; var aaSettings = LocalizationEditorSettings.Instance.GetAddressableAssetSettings(false); if (aaSettings == null) { return; } EditorUtility.SetDirty(table); EditorUtility.SetDirty(table.SharedData); RemoveEntryAssetType(tableEntry.KeyId, table.LocaleIdentifier.Code); // If the entry has metadata then we will leave an empty entry otherwise we just remove the whole thing. if (tableEntry.MetadataEntries.Count == 0) { table.RemoveEntry(tableEntry.KeyId); } // Determine if the asset is being referenced by any entries or tables with the same locale, if not then we can // remove the locale label and if no other labels exist also remove the asset from the Addressables system. var assetTableCollections = LocalizationEditorSettings.GetAssetTableCollections(); foreach (var collection in assetTableCollections) { if (collection.GetTable(table.LocaleIdentifier) is AssetTable tableWithMatchingLocaleId && tableWithMatchingLocaleId.ContainsValue(removedAssetGuid)) { // The asset is referenced elsewhere by a table with the same Locale so we can not remove the locale label or asset. return; } } // Remove the locale label for this asset var assetEntry = aaSettings.FindAssetEntry(removedAssetGuid); if (assetEntry != null) { if (createUndo) { Undo.RecordObject(assetEntry.parentGroup, "Remove asset from table"); } var assetLabel = AddressHelper.FormatAssetLabel(table.LocaleIdentifier); assetEntry.SetLabel(assetLabel, false); UpdateAssetGroup(aaSettings, assetEntry, createUndo); } LocalizationEditorSettings.EditorEvents.RaiseAssetTableEntryRemoved(this, table, tableEntry, removedAssetGuid); } }
/// <summary> /// Add a localized asset to the asset table. /// This function will ensure the localization system adds the asset to the Addressables system and sets the asset up for use. /// </summary> /// <param name="table">The table to add the asset to, must be part of the collection.</param> /// <param name="entryReference">The table entry Key or Key Id.</param> /// <param name="asset">The asset to add.</param> /// <param name="createUndo">Should an undo operation be created?</param> public virtual void AddAssetToTable(AssetTable table, TableEntryReference entryReference, Object asset, bool createUndo = false) { if (table == null) { throw new ArgumentNullException(nameof(table), "Can not add asset to null table"); } if (asset == null) { throw new ArgumentNullException(nameof(asset), "Can not add null asset to table"); } if (!ContainsTable(table)) { throw new Exception("The table does not belong to this collection."); } if (!EditorUtility.IsPersistent(table)) { throw new AssetNotPersistentException(table); } if (!EditorUtility.IsPersistent(asset)) { throw new AssetNotPersistentException(asset); } // Add the asset to the Addressables system and setup the table with the key to guid mapping. var aaSettings = LocalizationEditorSettings.Instance.GetAddressableAssetSettings(true); if (aaSettings == null) { return; } var undoGroup = Undo.GetCurrentGroup(); if (createUndo) { Undo.RecordObject(aaSettings, "Add asset to table"); } // Remove the old asset first var assetGuid = LocalizationEditorSettings.Instance.GetAssetGuid(asset); var tableEntry = table.GetEntryFromReference(entryReference); if (tableEntry != null) { if (tableEntry.Guid == assetGuid) { return; } RemoveAssetFromTable(table, entryReference, createUndo); } // Has the asset already been added? Perhaps it is being used by multiple tables or the user has added it manually. var entry = aaSettings.FindAssetEntry(assetGuid); var entryLabel = AddressHelper.FormatAssetLabel(table.LocaleIdentifier.Code); aaSettings.AddLabel(entryLabel); if (entry == null) { var group = LocalizationEditorSettings.Instance.GetGroup(aaSettings, FormatAssetTableCollectionName(table.LocaleIdentifier), true, createUndo); if (createUndo) { Undo.RecordObject(group, "Add asset to table"); } entry = aaSettings.CreateOrMoveEntry(assetGuid, group, true); entry.SetLabel(entryLabel, true); entry.address = LocalizationEditorSettings.Instance.FindUniqueAssetAddress(asset.name); } else { Undo.RecordObject(entry.parentGroup, "Add asset to table"); entry.SetLabel(entryLabel, true); UpdateAssetGroup(aaSettings, entry, createUndo); } // Update the table if (createUndo) { Undo.RecordObject(table, "Add asset to table"); Undo.RecordObject(table.SharedData, "Add asset to table"); } //else // Asset changes are not being saved correctly at the moment when using Undo. (LOC-82) { EditorUtility.SetDirty(table); EditorUtility.SetDirty(table.SharedData); } tableEntry = table.AddEntryFromReference(entryReference, assetGuid); // Update type metadata AssetTypeMetadata entryMetadata = null; AssetTypeMetadata typeMetadata = null; var assetType = asset.GetType(); // We cant use a foreach here as we are sometimes inside of a loop and exceptions will be thrown (Collection was modified). for (int i = 0; i < table.SharedData.Metadata.MetadataEntries.Count; ++i) { var md = table.SharedData.Metadata.MetadataEntries[i]; if (md is AssetTypeMetadata at) { if (at.Contains(tableEntry.KeyId)) { if (!at.Type.IsAssignableFrom(assetType)) { tableEntry.RemoveSharedMetadata(at); // Are other tables still using the type for the same id? if (at.Contains(tableEntry.KeyId)) { var name = SharedData.GetEntry(tableEntry.KeyId); Debug.LogWarning($"Table entry {name}({tableEntry.KeyId}) contains mixed types. Both {at.Type} and {assetType} are used."); } } else { entryMetadata = at; break; } } if (at.Type == assetType) { typeMetadata = at; break; } } } var foundMetadata = entryMetadata ?? typeMetadata; if (foundMetadata == null) { foundMetadata = new AssetTypeMetadata() { Type = assetType }; } tableEntry.AddSharedMetadata(foundMetadata); if (createUndo) { Undo.CollapseUndoOperations(undoGroup); } LocalizationEditorSettings.EditorEvents.RaiseAssetTableEntryAdded(this, table, tableEntry); }
/// <summary> /// Remove the asset mapping from the table entry and also cleans up the Addressables if necessary. /// </summary> /// <param name="table"></param> /// <param name="entryReference"></param> /// <param name="createUndo"></param> public void RemoveAssetFromTable(AssetTable table, TableEntryReference entryReference, bool createUndo = false) { var undoGroup = Undo.GetCurrentGroup(); if (createUndo) { Undo.RecordObject(table, "Remove asset from table"); // We modify the table entry. Undo.RecordObject(table.SharedData, "Remove asset from table"); // We modify the shared table metadata. } //else // Asset changes are not being saved correctly at the moment when using Undo. (LOC-82) { EditorUtility.SetDirty(table); EditorUtility.SetDirty(table.SharedData); } // Clear the asset but keep the key var tableEntry = table.GetEntryFromReference(entryReference); if (tableEntry == null) { return; } var removedAssetGuid = tableEntry.Guid; tableEntry.Guid = string.Empty; var aaSettings = LocalizationEditorSettings.Instance.GetAddressableAssetSettings(false); if (aaSettings == null) { return; } // Update type metadata // We cant use a foreach here as we are sometimes inside of a loop and exceptions will be thrown (Collection was modified). for (int i = 0; i < table.SharedData.Metadata.MetadataEntries.Count; ++i) { var md = table.SharedData.Metadata.MetadataEntries[i]; if (md is AssetTypeMetadata at) { if (at.Contains(tableEntry.KeyId)) { tableEntry.RemoveSharedMetadata(at); } } } // If the entry has metadata then we will leave an empty entry otherwise we just remove the whole thing. if (tableEntry.MetadataEntries.Count == 0) { table.RemoveEntry(tableEntry.KeyId); } // Determine if the asset is being referenced by any entries or tables with the same locale, if not then we can // remove the locale label and if no other labels exist also remove the asset from the Addressables system. var assetTableCollections = LocalizationEditorSettings.GetAssetTableCollections(); foreach (var collection in assetTableCollections) { var tableWithMatchingLocaleId = collection.GetTable(table.LocaleIdentifier) as AssetTable; if (tableWithMatchingLocaleId == null) { continue; } if (tableWithMatchingLocaleId.ContainsValue(removedAssetGuid)) { // The asset is referenced elsewhere so we can not remove the label or asset. return; } } // Remove the locale label for this asset var assetEntry = aaSettings.FindAssetEntry(removedAssetGuid); if (assetEntry != null) { if (createUndo) { Undo.RecordObject(assetEntry.parentGroup, "Remove asset from table"); } var assetLabel = AddressHelper.FormatAssetLabel(table.LocaleIdentifier); assetEntry.SetLabel(assetLabel, false); UpdateAssetGroup(aaSettings, assetEntry, createUndo); } if (createUndo) { Undo.CollapseUndoOperations(undoGroup); } LocalizationEditorSettings.EditorEvents.RaiseAssetTableEntryRemoved(this, table, tableEntry, removedAssetGuid); }
public void IsLocaleLabel_WorksWithLabelsGeneratedUsing_FormatAssetLabel(Locale locale) { var label = AddressHelper.FormatAssetLabel(locale.Identifier); Assert.IsTrue(AddressHelper.IsLocaleLabel(label), "Expected the Addressables Locale label to be recognized by IsLocaleLabel."); }
public void LocaleLabelToId_WorksWithLabelsGeneratedUsing_FormatAssetLabel(Locale locale) { var label = AddressHelper.FormatAssetLabel(locale.Identifier); LocaleLabelToId_CorrectlyConvertsLabel(label, locale.Identifier.Code); }
protected virtual void Analyze(AddressableAssetSettings settings, GroupResolver resolver) { try { EditorUtility.DisplayProgressBar(ruleName, "Finding Tables", 0); var tables = AssetDatabase.FindAssets($"t:{typeof(TTable).Name}"); // Collate the groups so we can check them at the end. var groups = new HashSet <AddressableAssetGroup>(); for (var i = 0; i < tables.Length; ++i) { var progress = i / (float)tables.Length; var guid = tables[i]; var entry = settings.FindAssetEntry(guid); var path = AssetDatabase.GUIDToAssetPath(guid); var table = AssetDatabase.LoadAssetAtPath <TTable>(path); var label = $"{table} - {path}"; EditorUtility.DisplayProgressBar(ruleName, $"Checking Table {path}", progress); var collection = LocalizationEditorSettings.GetCollectionForSharedTableData(table.SharedData); if (collection == null) { m_Results.Add(new TableResult { resultName = $"{table} - {path}:Loose Table.", severity = MessageType.Info, // TODO: Create collection for it? }); continue; } CheckContents(table, label, settings, collection); if (entry == null) { m_Results.Add(new TableResult { resultName = $"{label}:Not Marked as Addressable", severity = MessageType.Error, FixAction = () => { collection.AddTable(table); collection.AddSharedTableDataToAddressables(); } }); continue; } groups.Add(entry.parentGroup); // Group Name var groupName = resolver.GetExpectedGroupName(new[] { table.LocaleIdentifier }, table, settings); if (entry.parentGroup.Name != groupName) { m_Results.Add(new TableResult { resultName = $"{label}:Incorrect Group:Expected `{groupName}` but was `{entry.parentGroup.Name}`", severity = MessageType.Warning, FixAction = () => resolver.AddToGroup(table, new[] { table.LocaleIdentifier }, settings, false) }); } // Label var expectedLabel = AddressHelper.FormatAssetLabel(table.LocaleIdentifier); if (!entry.labels.Contains(expectedLabel)) { m_Results.Add(new TableResult { resultName = $"{label}:Missing Locale label.", severity = MessageType.Warning, FixAction = () => entry.SetLabel(expectedLabel, true, true) }); } // Address var expectedAddress = AddressHelper.GetTableAddress(table.TableCollectionName, table.LocaleIdentifier); if (!entry.labels.Contains(expectedLabel)) { m_Results.Add(new TableResult { resultName = $"{label}:Incorrect Address:Expected `{expectedAddress}` but was `{entry.address}`", severity = MessageType.Error, FixAction = () => entry.address = expectedAddress }); } // Shared Table Data var sharedGuid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(table.SharedData)); var g = new Guid(sharedGuid); if (table.SharedData.TableCollectionNameGuid != g) { m_Results.Add(new TableResult { resultName = $"{label}:Incorrect Shared Table Guid:Expected {g} but was {table.SharedData.TableCollectionNameGuid}", severity = MessageType.Error, FixAction = () => { table.SharedData.TableCollectionNameGuid = g; EditorUtility.SetDirty(table.SharedData); } }); } var sharedEntry = settings.FindAssetEntry(sharedGuid); if (sharedEntry == null) { m_Results.Add(new TableResult { resultName = $"{label}:Shared Table Not Marked as Addressable", severity = MessageType.Warning, FixAction = () => resolver.AddToGroup(table.SharedData, null, settings, false) }); continue; } groups.Add(sharedEntry.parentGroup); // Shared Group Name var sharedGroupName = resolver.GetExpectedGroupName(null, table.SharedData, settings); if (sharedEntry.parentGroup.Name != sharedGroupName) { m_Results.Add(new TableResult { resultName = $"{label}:Incorrect Shared Table Data Group:Expected `{sharedGroupName}` but was `{sharedEntry.parentGroup.Name}`", severity = MessageType.Warning, FixAction = () => resolver.AddToGroup(table.SharedData, null, settings, false) }); } var expectedSharedGroupName = resolver.GetExpectedGroupName(null, table.SharedData, settings); if (sharedEntry.parentGroup.Name != expectedSharedGroupName) { m_Results.Add(new TableResult { resultName = $"{label}:Incorrect Group:Expected `{expectedSharedGroupName}` but was `{sharedEntry.parentGroup.Name}`", severity = MessageType.Warning, FixAction = () => resolver.AddToGroup(table.SharedData, null, settings, false) }); } } if (groups.Count > 0) { foreach (var g in groups) { if (g.Schemas.Count == 0 || g.Schemas.All(s => s == null)) { m_Results.Add(new TableResult { resultName = $"{g.Name}:Addressables Group Contains No Schemas", severity = MessageType.Error, FixAction = () => { g.AddSchema <BundledAssetGroupSchema>(); g.AddSchema <ContentUpdateGroupSchema>(); } }); } } } } finally { EditorUtility.ClearProgressBar(); } }
/// <summary> /// Add a localized asset to the asset table. /// This function will ensure the localization system adds the asset to the Addressables system and sets the asset up for use. /// </summary> /// <param name="table">The table to add the asset to, must be part of the collection.</param> /// <param name="entryReference">The table entry Key or Key Id.</param> /// <param name="asset">The asset to add.</param> /// <param name="createUndo">Should an undo operation be created?</param> public virtual void AddAssetToTable(AssetTable table, TableEntryReference entryReference, Object asset, bool createUndo = false) { if (table == null) { throw new ArgumentNullException(nameof(table), "Can not add asset to null table"); } if (asset == null) { throw new ArgumentNullException(nameof(asset), "Can not add null asset to table"); } if (!ContainsTable(table)) { throw new Exception("The table does not belong to this collection."); } if (!EditorUtility.IsPersistent(table)) { throw new AssetNotPersistentException(table); } if (!EditorUtility.IsPersistent(asset)) { throw new AssetNotPersistentException(asset); } // Add the asset to the Addressables system and setup the table with the key to guid mapping. var aaSettings = LocalizationEditorSettings.Instance.GetAddressableAssetSettings(true); if (aaSettings == null) { return; } using (new UndoScope("Add asset to table", createUndo)) { if (createUndo) { Undo.RecordObject(aaSettings, "Add asset to table"); } // Remove the old asset first var assetGuid = LocalizationEditorSettings.Instance.GetAssetGuid(asset); var tableEntry = table.GetEntryFromReference(entryReference); if (tableEntry != null) { if (tableEntry.Guid != assetGuid) { RemoveAssetFromTable(table, entryReference, createUndo); } } // Has the asset already been added? Perhaps it is being used by multiple tables or the user has added it manually. var entry = aaSettings.FindAssetEntry(assetGuid); var entryLabel = AddressHelper.FormatAssetLabel(table.LocaleIdentifier.Code); aaSettings.AddLabel(entryLabel); if (entry == null) { entry = AddressableGroupRules.AddAssetToGroup(asset, new[] { table.LocaleIdentifier }, aaSettings, createUndo); entry.SetLabel(entryLabel, true, true); entry.address = LocalizationEditorSettings.Instance.FindUniqueAssetAddress(asset.name); } else { if (createUndo) { Undo.RecordObject(entry.parentGroup, "Add asset to table"); } entry.SetLabel(entryLabel, true, true); UpdateAssetGroup(aaSettings, entry, createUndo); } if (createUndo) { Undo.RecordObjects(new Object[] { table, table.SharedData }, "Add asset to table"); } EditorUtility.SetDirty(table); EditorUtility.SetDirty(table.SharedData); tableEntry = table.AddEntryFromReference(entryReference, assetGuid); SetEntryAssetType(tableEntry.KeyId, asset.GetType(), table.LocaleIdentifier.Code); LocalizationEditorSettings.EditorEvents.RaiseAssetTableEntryAdded(this, table, tableEntry); } }