acoppes / unity-history-window

A simple selection history window for Unity.
MIT License
293 stars 24 forks source link

UnityException: Creating asset at path Assets/Gemserk.SelectionHistory.asset failed. #48

Closed rhys-vdw closed 8 months ago

rhys-vdw commented 10 months ago
UnityException: Creating asset at path Assets/Gemserk.SelectionHistory.asset failed.
Gemserk.SelectionHistoryReference..cctor () (at ./Library/PackageCache/com.gemserk.selectionhistory@1.1.16/Editor/SelectionHistoryReference.cs:25)
Rethrow as TypeInitializationException: The type initializer for 'Gemserk.SelectionHistoryReference' threw an exception.
Gemserk.SelectionHistoryWindowUtils.SelectionRecorder () (at ./Library/PackageCache/com.gemserk.selectionhistory@1.1.16/Editor/SelectionHistoryWindowUtils.cs:49)
UnityEditor.Selection.Internal_CallSelectionChanged () (at <53ddbed73faf4fe3b980a493ab4e6639>:0)

Not sure what to make of this. It happened on a full project reimport.

https://github.com/acoppes/unity-history-window/blob/3d2f3d551e91919639e39fd3a05239c23795f996/Assets/Gemserk.SelectionHistory/Editor/SelectionHistoryReference.cs#L25

Can't see anything obviously wrong with the code...

acoppes commented 10 months ago

Hi, yes, I have that issue on first import, I can replicate it always with big project but with small almost empty test projects I can't. It is strange, the asset is created but it is like trying to execute that twice and it fails and keeps an invalid reference in memory, so the selection history fails but the asset is there. If you close and reopen unity it works.

rhys-vdw commented 10 months ago

Yep, same here. Just that error once and it's all good since then.

Orthopoxvirus commented 9 months ago

For me the editor windows were not usable after this error. It worked after recompiling.

acoppes commented 9 months ago

Yeah, you have to reopen unity or recompile yes since there is when the static field is initialized with the asset, my guess is there is an issue like it is being called, it tries to create the asset and fails to get the reference (maybe unity is in a state that assets can't be created yet) so the static field is null but the asset was created anyways (you can find it in the assets folder). My plan to try to fix it is to just try to get the asset all the time if it is null but there is another issue with standalone profiler in that case, it fails to create the asset all the time and becomes unusable and I don't know how to fix that either (yet).

Orthopoxvirus commented 9 months ago

Oh, 'static field' triggers some brain cells. I have domain reloading off for less pauses while developping. I'm used to recompile once at startup to initialize all static fields in my code. I couldn't be bothered to fix that issue for now. I'll get back to if I ever fix it 😄

rhys-vdw commented 9 months ago

Oh, 'static field' triggers some brain cells. I have domain reloading off for less pauses while developping.

But the static field should be being re-initialized because of this: https://github.com/acoppes/unity-history-window/blob/3d2f3d551e91919639e39fd3a05239c23795f996/Assets/Gemserk.SelectionHistory/Editor/SelectionHistoryReference.cs#L5

rhys-vdw commented 8 months ago

I think I have the solution for this btw. Unity has a mechanism for this exact pattern. ScriptableSingleton.

You can do this:

using UnityEngine;

namespace Gemserk
{
    [UnityEditor.InitializeOnLoad]
    [FilePath("Gemserk.SelectionHistory.asset", FilePathAttribute.Location.PreferencesFolder)]
    public static class SelectionHistoryAsset : ScriptableSingleton<SelectionHistoryAsset>
    {
        public SelectionHistory selectionHistory = new SelectionHistory();

#if UNITY_EDITOR
        private void OnEnable()
        {
            selectionHistory.OnNewEntryAdded += OnNewEntryAdded;
        }

        private void OnDisable()
        {
            selectionHistory.OnNewEntryAdded -= OnNewEntryAdded;
        }

        private void OnNewEntryAdded(SelectionHistory obj)
        {
             Save(true);
        }
#endif
    }
}

And simply remove the SelectionHistoryReference entirely.

This also has the advantage of putting the SO in your preferences folder, which (appropriately) takes it out of version control.

I haven't tested it, but I'm assuming InitializeOnLoad will trigger the static instance initialization. If not then maybe this could work:

static SelectionHistoryAsset() {
  _ = instance;
}

Gets the instance of the Singleton. Unity creates the Singleton instance when this property is accessed for the first time. If you use the FilePathAttribute, then Unity loads the data on the first access as well. - https://docs.unity3d.com/2020.1/Documentation/ScriptReference/ScriptableSingleton_1-instance.html

I can open a PR if you're keen.

Orthopoxvirus commented 8 months ago

I got the error just the very first time when I imported the asset, so I can't really test if it solves the problem now. But I will use your code for sure, because of the version control improvement. I will try it in about 12 hours. Thanks.

rhys-vdw commented 8 months ago

I haven't tested it yet, just wrote the code in the comment as a suggestion of how it could be solved.

I'm pretty sure the error occurs every time library is deleted and reimported.

acoppes commented 8 months ago

I would love a PR yeah, thanks !! I didn't know about the ScriptableSingleton

UPDATE: I have to change supported version to Unity 2020.x in order to use this API, I suppose it is not an issue but it is a change, I will test it, maybe with a #ifdef or something

UPDATE: also, have to use Project folder not preferences since I don't want to share the file between different projects, however would be nice to have them in preferences, maybe in the future I could use a project key or something to differentiate and use preferences folder to avoid having that file in the project (and having to ignore it in git or others)

Orthopoxvirus commented 8 months ago

Sorry I can't test rn. The kids got sick.

acoppes commented 8 months ago

I updated to use the ScriptableSingleton in both SelectionHistoryAsset and FavoritesAsset and moved both to editor assembly. Will lose previous data with this update and also changed to only support unity 2020+

UPDATE: didn't validate the fix yet but at least it work normally in almost empty projects.

rhys-vdw commented 8 months ago

@acoppes I noticed you put the assets in Projects folder instead of preferences. This means that when people use git their favourites and history will be shared/cause conflicts.

rhys-vdw commented 8 months ago

have to use Project folder not preferences since I don't want to share the file between different projects, however would be nice to have them in preferences, maybe in the future I could use a project key or something to differentiate and use preferences folder to avoid having that file in the project (and having to ignore it in git or others)

Oh sorry, just read this. Is the Preferences folder global? I thought it was project-folder/UserSettings/ (that's where other preferences are saved).

Admittedly I've rarely, if ever, used ScriptableSinglton.

acoppes commented 8 months ago

@acoppes I noticed you put the assets in Projects folder instead of preferences. This means that when people use git their favourites and history will be shared/cause conflicts.

It is already like this, the idea is to add to git ignore. Also, I changed where it is stored from previous versions, so the previous data will be lost, had to do it like that since I had an issue with storing it inside the Assets folder since Unity was trying to process the asset twice and there could be only one singleton.

About Location.PreferencesFolder =>

image

It says it is shared across projects, I really liked it to be hidden in preferences folder and not having an asset over there but I don't want the shared behaviour, I have to change how I store stuff to avoid conflicts there.

rhys-vdw commented 8 months ago

Ah, my mistake. I wonder why they don't have Location.UserSettings.