private void SetupMenus()
        {
            _FileMenu         = new GenericMenu();
            _AddressablesMenu = new GenericMenu();
            _ItemsMenu        = new GenericMenu();

            AddPlugins(GetAddressablePlugins());

            // ***********************************************************************************
            // File Menu items
            // ***********************************************************************************
            AddMenuItemWithCallback(FileMenu, "Rebuild From Project", () =>
            {
                UAI.Clear();
                UAI.AddEverything(false);
                Resources.UnloadUnusedAssets();
                m_Initialized = false;
                Repaint();
            });

            AddMenuItemWithCallback(FileMenu, "Rebuild From Project (include text assets)", () =>
            {
                UAI.Clear();
                UAI.AddEverything(true);
                Resources.UnloadUnusedAssets();
                m_Initialized = false;
                Repaint();
            });
            AddMenuItemWithCallback(FileMenu, "Cleanup References", () =>
            {
                UAI.UpdateReferences();
                Resources.UnloadUnusedAssets();
                m_Initialized = false;
                Repaint();
                EditorUtility.DisplayDialog("Repair", "References cleaned", "OK");
            });

            AddMenuItemWithCallback(FileMenu, "Repair and remove invalid items", () =>
            {
                UAI.RepairAndCleanup();
                Resources.UnloadUnusedAssets();
                m_Initialized = false;
                Repaint();
                EditorUtility.DisplayDialog("Repair", "AssetIndex successfully repaired", "OK");
            });

            /* AddMenuItemWithCallback(FileMenu, "Add Build refs to all non-addressables", () =>
             * {
             *      UAI.AddReferences();
             *      RecountTypes();
             *      Resources.UnloadUnusedAssets();
             *      Repaint();
             * });
             * AddMenuItemWithCallback(FileMenu, "Clear build refs from all items", () =>
             * {
             *      UAI.ClearReferences();
             *      Resources.UnloadUnusedAssets();
             *      RecountTypes();
             *      Repaint();
             * }); */
            FileMenu.AddSeparator("");
            AddMenuItemWithCallback(FileMenu, "Toggle Utilities Panel", () =>
            {
                ShowUtilities = !ShowUtilities;
                Repaint();
            });
            FileMenu.AddSeparator("");

            AddMenuItemWithCallback(FileMenu, "Empty Index", () =>
            {
                UAI.Clear();
                m_Initialized = false;
                Repaint();
            });

#if UMA_ADDRESSABLES
            foreach (IUMAAddressablePlugin plugin in addressablePlugins)
            {
                AddMenuItemWithCallbackParm(_AddressablesMenu, "Generators/" + plugin.Menu, (object o) =>
                {
                    IUMAAddressablePlugin addrplug = o as IUMAAddressablePlugin;
                    UMAAddressablesSupport.Instance.GenerateAddressables(addrplug);
                    Resources.UnloadUnusedAssets();
                    m_Initialized = false;
                    Repaint();
                }, plugin);
            }

            _AddressablesMenu.AddSeparator("Generators/");

            // ***********************************************************************************
            // Addressables Menu items
            // ***********************************************************************************
            AddMenuItemWithCallback(_AddressablesMenu, "Generators/Generate Groups (optimized)", () =>
            {
                UMAAddressablesSupport.Instance.CleanupAddressables();
                UMAAddressablesSupport.Instance.GenerateAddressables();
                Resources.UnloadUnusedAssets();
                m_Initialized = false;
                Repaint();
            });

            /* AddMenuItemWithCallback(AddressablesMenu, "Generators/Generate Shared Group (fast)", () =>
             * {
             *      UAI.CleanupAddressables();
             *      UAI.GenerateSingleGroup();
             *      Resources.UnloadUnusedAssets();
             *      m_Initialized = false;
             *      Repaint();
             * });
             *
             * AddMenuItemWithCallback(AddressablesMenu, "Generators/Generate Shared Group (incl recipes)", () =>
             * {
             *      UAI.CleanupAddressables();
             *      UAI.GenerateSingleGroup(true);
             *      Resources.UnloadUnusedAssets();
             *      m_Initialized = false;
             *      Repaint();
             * }); */

            AddMenuItemWithCallback(_AddressablesMenu, "Remove Addressables", () =>
            {
                UMAAddressablesSupport.Instance.CleanupAddressables(false, true);
                m_Initialized = false;
                Repaint();
            });
            AddMenuItemWithCallback(_AddressablesMenu, "Delete Empty Groups", () =>
            {
                UMAAddressablesSupport.Instance.CleanupAddressables(true);
            });

            /*
             * AddMenuItemWithCallback(AddressablesMenu, "Force Add Refs (Bad!!)", () =>
             * {
             *      UAI.AddReferences(true);
             *      RecountTypes();
             *      Resources.UnloadUnusedAssets();
             *      Repaint();
             * }); */

            AddMenuItemWithCallback(_AddressablesMenu, "Remove Orphaned Slots", () =>
            {
                if (EditorUtility.DisplayDialog("Warning!", "You *must* build the addressable groups, and mark any slots you want to keep as 'keep' before running this!", "OK", "Cancel"))
                {
                    UMAAddressablesSupport.Instance.CleanupOrphans(typeof(SlotDataAsset));
                    m_Initialized = false;
                    Repaint();
                }
            });
            AddMenuItemWithCallback(_AddressablesMenu, "Remove Orphaned Overlays", () =>
            {
                if (EditorUtility.DisplayDialog("Warning!", "You *must* build the addressable groups, and mark any slots you want to keep as 'keep' before running this.", "OK", "Cancel"))
                {
                    UMAAddressablesSupport.Instance.CleanupOrphans(typeof(OverlayDataAsset));
                    m_Initialized = false;
                    Repaint();
                }
            });
#else
            AddMenuItemWithCallback(_AddressablesMenu, "Enable Addressables (Package must be installed first)", () =>
            {
                if (EditorUtility.DisplayDialog("Warning!", "The Addressables Package must be installed first before enabling Addressables support in UMA. Enabling addressables will trigger a recompile during which the library will be unavailable.", "OK", "Cancel"))
                {
                    var defineSymbols = new HashSet <string>(PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup).Split(';'));
                    defineSymbols.Add("UMA_ADDRESSABLES");
                    PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, string.Join(";", defineSymbols));
                    m_Initialized = false;
                    Repaint();
                }
            });
#endif
            // ***********************************************************************************
            // Items Menu items
            // ***********************************************************************************
            AddMenuItemWithCallback(ItemsMenu, "Select All", () =>
            {
                var treeElements = new List <AssetTreeElement>();
                TreeElementUtility.TreeToList <AssetTreeElement>(treeView.treeModel.root, treeElements);
                foreach (AssetTreeElement ate in treeElements)
                {
                    ate.Checked = true;
                }
                treeView.RecalcTypeChecks();
                Repaint();
                return;
            });

            AddMenuItemWithCallback(ItemsMenu, "Clear Selection", () =>
            {
                var treeElements = new List <AssetTreeElement>();
                TreeElementUtility.TreeToList <AssetTreeElement>(treeView.treeModel.root, treeElements);
                foreach (AssetTreeElement ate in treeElements)
                {
                    ate.Checked = false;
                }
                treeView.RecalcTypeChecks();
                Repaint();
                return;
            });

            foreach (RaceData rc in UAI.GetAllAssets <RaceData>())
            {
                if (rc != null)
                {
                    AddMenuItemWithCallbackParm(ItemsMenu, "Select Slots + Overlays By Race/" + rc.raceName, SelectByRace, rc);
                    AddMenuItemWithCallbackParm(ItemsMenu, "Select Slots By Race/" + rc.raceName, SelectSlotsByRace, rc);
                    AddMenuItemWithCallbackParm(ItemsMenu, "Select Overlays By Race/" + rc.raceName, SelectOverlaysByRace, rc);
                }
            }

            ItemsMenu.AddSeparator("");

            AddMenuItemWithCallback(ItemsMenu, "Add Keep Flag to Selected Items", () =>
            {
                MarkKeep(true);
                Repaint();
                return;
            });

            AddMenuItemWithCallback(ItemsMenu, "Clear Keep Flag from Selected Items", () =>
            {
                MarkKeep(false);
                Repaint();
                return;
            });

            ItemsMenu.AddSeparator("");

            AddMenuItemWithCallback(ItemsMenu, "Remove Selected", () =>
            {
                RemoveSelected();
                m_Initialized = false;
                Repaint();
                return;
            });
            AddMenuItemWithCallback(ItemsMenu, "Force Selected Items to Save", () =>
            {
                ForceSave();
                m_Initialized = false;
                Repaint();
                return;
            });
        }
        public void GenerateAddressables(IUMAAddressablePlugin plugin)
        {
            bool OK = plugin.Prepare();

            if (!OK)
            {
                return;
            }

            foreach (Type t in UMAAssetIndexer.Instance.GetTypes())
            {
                ClearAddressableFlags(t);
            }

            AddressableAssetGroup sharedGroup = AddressableUtility.AddressableSettings.FindGroup(SharedGroupName);

            if (sharedGroup == null)
            {
                sharedGroup = AddressableUtility.AddressableSettings.CreateGroup(SharedGroupName, false, false, true, AddressableUtility.AddressableSettings.DefaultGroup.Schemas);
                sharedGroup.GetSchema <BundledAssetGroupSchema>().BundleMode = BundledAssetGroupSchema.BundlePackingMode.PackSeparately;
            }

            var items = GetAddressableRecipes();

            foreach (AssetItem ai in items)
            {
                plugin.ProcessRecipe(ai.Item as UMAPackedRecipeBase);
            }

            StringBuilder sb = new StringBuilder();

            List <AssetItem> SerializedItems = UMAAssetIndexer.Instance.UpdateSerializedList();

            foreach (AssetItem ai in SerializedItems)
            {
                List <string> labels = plugin.ProcessItem(ai);
                if (labels != null && labels.Count > 0)
                {
                    bool found = AssetDatabase.TryGetGUIDAndLocalFileIdentifier(ai.Item.GetInstanceID(), out string itemGUID, out long localID);
                    if (found)
                    {
                        ai.IsAddressable      = true;
                        ai.AddressableAddress = ""; // let the system assign it if we are generating.
                        ai.AddressableGroup   = sharedGroup.name;

                        AddItemToSharedGroup(itemGUID, ai.AddressableAddress, labels, sharedGroup);
#if INCL_TEXTURES
                        if (IsOverlayItem(ai))
                        {
                            OverlayDataAsset od = ai.Item as OverlayDataAsset;
                            if (od == null)
                            {
                                Debug.Log("Invalid overlay in recipe: " + ai._Name + ". Skipping.");
                                continue;
                            }
                            foreach (Texture tex in od.textureList)
                            {
                                if (tex == null)
                                {
                                    continue;
                                }
                                if (tex as Texture2D == null)
                                {
                                    Debug.Log("Texture is not Texture2D!!! " + tex.name);
                                    continue;
                                }
                                string Address = "Texture2D-" + tex.name + "-" + tex.GetInstanceID();

                                found = AssetDatabase.TryGetGUIDAndLocalFileIdentifier(tex.GetInstanceID(), out string texGUID, out long texlocalID);
                                if (found)
                                {
                                    AddItemToSharedGroup(texGUID, AssetItem.AddressableFolder + Address, labels, sharedGroup);
                                }
                            }
                        }
#endif
                        sb.Clear();
                        foreach (string s in labels)
                        {
                            // add the label to the item
                            sb.Append(s);
                            sb.Append(';');
                        }
                        ai.AddressableLabels = sb.ToString();
                    }
                }
            }

            plugin.Complete();
        }