Skip to content

Commit

Permalink
feat: handle moved assets (close: #20)
Browse files Browse the repository at this point in the history
Squashed commit of the following:

commit fa88724649544fadb589e6044ab6878a2201b587
Author: Favo Yang <favoyang@gmail.com>
Date:   Sun Apr 26 15:22:27 2020 +0800

    docs: check grammar

commit decd13b
Author: Haruki Yano <haruki.y.11g@gmail.com>
Date:   Sun Apr 26 13:01:55 2020 +0900

    Remove code for debug.

commit 8cb2602
Author: Haruki Yano <haruki.y.11g@gmail.com>
Date:   Sun Apr 26 12:55:31 2020 +0900

    fix: Fix how to remove empty groups

commit 77e799f
Author: Haruki Yano <haruki.y.11g@gmail.com>
Date:   Sun Apr 26 12:10:36 2020 +0900

    fix: Not delete unmanaged entries

commit a6f289a
Author: Haruki Yano <haruki.y.11g@gmail.com>
Date:   Tue Apr 21 00:36:54 2020 +0900

    Apply import rules to moved assets.
  • Loading branch information
favoyang committed Apr 26, 2020
1 parent 4691b84 commit a902a21
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 42 deletions.
33 changes: 18 additions & 15 deletions Documentation~/AddressableImporter.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ Table of Contents
- [Rule Examples](#rule-examples)
- [Group Replacement](#group-replacement)
- [Address Replacement](#address-replacement)
- [Notice for moved or re-imported assets](#notice-for-moved-or-re-imported-assets)
- [Quick assets import](#quick-assets-import)
- [Label Replacement](#label-replacement)
- [Quick assets (re)import](#quick-assets-reimport)
- [About prefab mode](#about-prefab-mode)

## Setup the Importer
Expand All @@ -16,7 +16,7 @@ You should create a single AddressableImportSettings file located at `Assets/Add

![AddressableImportSettings Create](AddressableImportSettings-Create.png)

Once the settings file selected, you can edit rules in the inspector window. Then click `File > Save Project` to apply the changes.
Once the settings file selected, you can edit rules in the inspector window. Then click the `File > Save Project` to apply the changes.

![AddressableImportSettings Inspector](AddressableImportSettings-Insepctor.png)

Expand All @@ -30,7 +30,7 @@ Once the settings file selected, you can edit rules in the inspector window. The
- `Label Mode`, defines if labels will be added or replaced.
- `Label Refs`, the labels to add.
- `Address Simplified`, simplify address to filename without extension.
- `Address Replacement`, leaves blank to use asset path as address. For dynamic address see [Address Replacement](#address-replacement).
- `Address Replacement`, leaves blank to use the asset path as address. For dynamic address see [Address Replacement](#address-replacement).

## Rule Examples

Expand All @@ -43,7 +43,7 @@ Once the settings file selected, you can edit rules in the inspector window. The

## Group Replacement

Dynamic group is supported by replacing `${name}` with extracted value from asset path, via the use of regex capture groups. Named capture groups can be referred to in `Group Name` via `${group}`. If groups are not named, they can be referred to numerically, via `$1`, `$2` and so on. For more information, refer to [Microsoft Docs - Substitutions in Regular Expressions](https://docs.microsoft.com/en-us/dotnet/standard/base-types/substitutions-in-regular-expressions). This only works for match type Regex.
The dynamic group is supported by replacing `${name}` with the extracted value from the asset path, via the use of regex capture groups. Named capture groups can be referred to in `Group Name` via `${group}`. If groups are not named, they can be referred to numerically, via `$1`, `$2`, and so on. For more information, refer to [Microsoft Docs - Substitutions in Regular Expressions](https://docs.microsoft.com/en-us/dotnet/standard/base-types/substitutions-in-regular-expressions). This only works for match type Regex.

For convenience, path elements can be referred via `${PATH[index]}`. This works for all match types.

Expand All @@ -65,20 +65,23 @@ Similar to [Group Replacement](#group-replacement), address replacement is also
| `Assets/cat/cat01.png` | `Assets/(?<category>[^/]+)/(?<asset>.*)\.png` | `${category}-${asset}` | cat-cat01 |
| `Assets/cat/cat01.png` | `Assets/(?<category>[^/]+)/(?<asset>.*)\.png` | `${PATH[0]}:${category}-${asset}` | Assets:cat-cat01 |

## Notice for moved or re-imported assets
- The importer always overrides existing labels if `LabelMode = Replace`.
- The importer always overrides existing address if
- The address looks like a path (starts with `Assets/`).
- `Address Simplified` is ticked.
- `Address Replacement` is in use.
- In another word, if you intent to manually change the address later, leave `Address Simplified` unticked, `Address Replacement` blank, and do not use `Assets/` prefix for the customized address name.
The importer always overrides existing address if
- The address looks like a path (starts with `Assets/`).
- `Address Simplified` is ticked.
- `Address Replacement` is in use.

## Quick assets import
In another word, if you are intending to manually change the address later, leave `Address Simplified` unticked, `Address Replacement` blank, and do not use `Assets/` prefix for the customized address name.

The importer will apply your rules whenever an asset being imported, moved or deleted. However you may want to apply new or modified rules to existing assets. To quickly apply importer rules, select target folder(s) in project view, right click to open the context menu, and click `AddressablesImporter: Check Folder(s)`. The action is more efficient than reimport asset(s).
## Label Replacement

The importer always overrides existing labels if `LabelMode = Replace`.

## Quick assets (re)import

The importer should apply the rules whenever an asset being imported, moved, or deleted. However, if you modified rules or want to apply rules to existing assets, you need to manually apply the rules. To quickly apply the rules, select target folder(s) in the project view, right-click to open the context menu, and then click `AddressablesImporter: Check Folder(s)`. The action is more efficient than force reimport assets.

![AddressableImport Context Menu](AddressableImportSettings-ContextMenu.png)

## About prefab mode

When both prefab mode (the preview scene for editing a prefab) and the auto save feature are enabled, every modification will cause the asset to be saved and trigger the importer, leads to slow response. For performance reason, the importer will ignore current editing asset.
When both prefab mode (the preview scene for editing a prefab) and the autosave feature are enabled, every modification will cause the asset to be saved and trigger the importer, leads to slow response. For performance reasons, the importer will ignore the current editing asset.
108 changes: 82 additions & 26 deletions Editor/AddressableImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,47 +26,86 @@ static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAsse
Debug.LogWarningFormat("[AddressableImporter] import settings file not found.\nPlease go to Assets/AddressableAssetsData folder, right click in the project window and choose 'Create > Addressable Assets > Import Settings'.");
return;
}
else if (importSettings.rules == null || importSettings.rules.Count == 0)
if (importSettings.rules == null || importSettings.rules.Count == 0)
return;
var entriesAdded = new List<AddressableAssetEntry>();

var dirty = false;

// Apply import rules.
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
foreach (string assetPath in importedAssets)
foreach (var importedAsset in importedAssets)
{
// Ignore current editing prefab asset.
if (prefabStage != null && prefabStage.prefabAssetPath == assetPath)
continue;
foreach (var rule in importSettings.rules)
{
if (rule.Match(assetPath))
{
var entry = CreateOrUpdateAddressableAssetEntry(settings, importSettings, rule, assetPath);
if (entry != null)
{
entriesAdded.Add(entry);
if (rule.HasLabel)
Debug.LogFormat("[AddressableImporter] Entry created/updated for {0} with address {1} and labels {2}", assetPath, entry.address, string.Join(", ", entry.labels));
else
Debug.LogFormat("[AddressableImporter] Entry created/updated for {0} with address {1}", assetPath, entry.address);
}
}
}
if (prefabStage == null || prefabStage.prefabAssetPath != importedAsset) // Ignore current editing prefab asset.
dirty |= ApplyImportRule(importedAsset, null, settings, importSettings);
}
if (entriesAdded.Count > 0)

for (var i = 0; i < movedAssets.Length; i++)
{
settings.SetDirty(AddressableAssetSettings.ModificationEvent.EntryMoved, entriesAdded, true);
AssetDatabase.SaveAssets();
var movedAsset = movedAssets[i];
var movedFromAssetPath = movedFromAssetPaths[i];
if (prefabStage == null || prefabStage.prefabAssetPath != movedAsset) // Ignore current editing prefab asset.
dirty |= ApplyImportRule(movedAsset, movedFromAssetPath, settings, importSettings);
}

// Remove empty groups.
if (importSettings.removeEmtpyGroups)
{
settings.groups.RemoveAll(_ => _.entries.Count == 0 && !_.IsDefaultGroup());
var emptyGroups = settings.groups.Where(x => x.entries.Count == 0 && !x.IsDefaultGroup()).ToArray();
for (var i = 0; i < emptyGroups.Length; i++)
{
settings.RemoveGroup(emptyGroups[i]);
dirty = true;
}
}

if (dirty)
AssetDatabase.SaveAssets();
}

static AddressableAssetGroup CreateAssetGroup<SchemaType>(AddressableAssetSettings settings, string groupName)
{
return settings.CreateGroup(groupName, false, false, false, new List<AddressableAssetGroupSchema> { settings.DefaultGroup.Schemas[0] }, typeof(SchemaType));
}

static bool ApplyImportRule(
string assetPath,
string movedFromAssetPath,
AddressableAssetSettings settings,
AddressableImportSettings importSettings)
{
var dirty = false;
if (TryGetMatchedRule(assetPath, importSettings, out var matchedRule))
{
// Apply the matched rule.
var entry = CreateOrUpdateAddressableAssetEntry(settings, importSettings, matchedRule, assetPath);
if (entry != null)
{
if (matchedRule.HasLabel)
Debug.LogFormat("[AddressableImporter] Entry created/updated for {0} with address {1} and labels {2}", assetPath, entry.address, string.Join(", ", entry.labels));
else
Debug.LogFormat("[AddressableImporter] Entry created/updated for {0} with address {1}", assetPath, entry.address);
}

dirty = true;
}
else
{
// If assetPath doesn't match any of the rules, try to remove the entry.
// But only if movedFromAssetPath has the matched rule, because the importer should not remove any unmanaged entries.
if (!string.IsNullOrEmpty(movedFromAssetPath) && TryGetMatchedRule(movedFromAssetPath, importSettings, out matchedRule))
{
var guid = AssetDatabase.AssetPathToGUID(assetPath);
if (settings.RemoveAssetEntry(guid))
{
dirty = true;
Debug.LogFormat("[AddressableImporter] Entry removed for {0}", assetPath);
}
}
}

return dirty;
}

static AddressableAssetEntry CreateOrUpdateAddressableAssetEntry(
AddressableAssetSettings settings,
AddressableImportSettings importSettings,
Expand Down Expand Up @@ -123,6 +162,23 @@ static AddressableAssetEntry CreateOrUpdateAddressableAssetEntry(
return entry;
}

static bool TryGetMatchedRule(
string assetPath,
AddressableImportSettings importSettings,
out AddressableImportRule rule)
{
foreach (var r in importSettings.rules)
{
if (!r.Match(assetPath))
continue;
rule = r;
return true;
}

rule = null;
return false;
}

/// <summary>
/// Find asset group by given name. Return default group if given name is null.
/// </summary>
Expand Down Expand Up @@ -183,7 +239,7 @@ private static void CheckFolders()
if (filesToImport.Count > 0)
{
Debug.Log($"AddressablesImporter: Found {filesToImport.Count} assets...");
OnPostprocessAllAssets(filesToImport.ToArray(), null, null, null);
OnPostprocessAllAssets(filesToImport.ToArray(), new string[0], new string[0], new string[0]);
}
else
{
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</a>
</p>

A simple rule based addressable asset importer. The importer marks assets as addressable, by applying to files having a path matching the rule pattern.
A simple rule-based addressable asset importer. The importer marks assets as addressable, by applying to files having a path matching the rule pattern.

Table of Contents

Expand Down

0 comments on commit a902a21

Please sign in to comment.