o3de / sig-core

5 stars 6 forks source link

Proposed RFC Feature per-engine recently used project path #24

Open AMZN-alexpete opened 2 years ago

AMZN-alexpete commented 2 years ago

Summary:

When launched without a project path parameter, O3DE tools (Editor, Asset Processor etc.) will attempt to use the most recently used project for that engine. These paths will be stored in a .setreg file in .o3de/Registry or inside the engine in user/Registry.

What is the relevance of this feature?

Currently, when a user directly runs tools like Editor.exe or AssetProcessor.exe without specifying a project path, and the these tools are not inside a project folder, they will launch the Project Manager (o3de.exe) from which the user can select the project they want to use. There are a few misses here:

  1. Needlessly asking the user what project they want to use for a specific tool introduces unnecessary friction and time lost.
  2. Some tools cannot be launched from the Project Manager (yet), for example AssetProcessor.exe
  3. Users that ran the installer and only have a single project on their machine are confused that running the Editor desktop shortcut, or Editor.exe does not launch the only project they have and keeps opening Project Manager.
  4. Most past and present users that work on a team get their engine and single project from source control in a format where the engine and project are in separate folders, and typically include pre-built binaries outside the project folder so their use case is similar to the users that run an installer.

Feature design description:

From a user perspective there will be no UI change.

  1. When users launch the Editor from the Project Manager, it writes that project path for that engine to a .setreg file. Each engine will have its own list of recently used project paths.
  2. When the user attempts to run an O3DE tool (Editor.exe, AssetProcessor.exe etc) without specifying a project path, the tool will in-addition to the existing project path detection logic, look for this recently used project path.

NOTE: Users that distribute a custom engine and project via source control can already provide a default relative project path using a .setreg file in their engine's Registry folder, which is great for advanced users, but this recently used project feature will provide similar benefits to non-advanced users.

! 3/4/2022 NOTE: The technical design description will be updated in the comments section.  
! This original description will be here for now to see the original proposal.

Technical design description:

The most recent used project path will be written by Project Manager (o3de.exe) to a .setreg inside the .o3de folder

Option 1: .o3de/Registry/recent_projects.setreg

PRO CON
guaranteed writeable location may break if engine name changes
lives alongside other user config data
specific to user

Option 2: user/Registry/recent_projects.setreg

PRO CON
survives engine name changes not guaranteed writeable
shared by every user on machine

What are the advantages of the feature?

What are the disadvantages of the feature?

How will this be implemented or integrated into the O3DE environment?

Are there any alternatives to this feature?

How will users learn this feature?

Are there any open questions?

lemonade-dm commented 2 years ago

Feature wise, I do think this proposal could help users get into tooling applications a little easier. Now this proposal will hit some restrictions in how we treat the engine as well and will need some guard rails against missing projects.

So first the restrictions, are that we have to treat the settings files within the engine locations as immutable. This is needed as the location where the Engine is installed might only have read only access for the user(C:\Program Files, /opt/ /usr/share/ etc...). Settings file wouldn't be able to be persisted to that location. Furthermore the purpose of the Engine SDK is to be redistributable and proejct related data in breaks the portability of the engine itself.

The 2nd option of having a registry file with the recently launched project for the engine within a <engine-root>/user is not viable. Furthermore the C++ applications do not support scanning the <engine-root>/user purposefully to prevent the storage of settings within the engine.

Now on to the guard rails that would be needed with this proposal to prevent a worse user experience.

I believe the recent project registry file within the ~/.o3de/Registry directory should use the SettingsRegistry specialization tagging system to restrict the loading of the recent_projects settings file to only the ones associated with the engine name. The naming scheme that can be used for the file is recent_project.<engine-name>.setreg. The limitations of such a naming scheme is that if the "engine_name" changes in the engine.json file, the recent project registry would no longer be able to found as the "engine_name" tag that is being used has changed. The benefits however, is that the would only load the recent_project.<engine-name>.setreg and will not have to deal with filtering out other engines recent project list Next the AZCore::Util::GetProjectPath function should NOT be touched to get this functionality working. That function is just meant to query the project path once it has been set within the SettingsRegistry There is a centralized API in the SettingsRegistryMergeUtils that follows an algorithm for determining the root of the project. It is the SettingsRegistryMergeUtils::FindProjectRoot function. That function would be the one location that would need to be updated to include the logic to scan through the recent_project.<engine-name>.setreg file if the project-path hasn't been set and cannot be detected.

It would need to cross check the recent projects "engine" field with the running engine's "engine_name" field to make sure the project is actually associated with the engine.

Finally I believe we need some a strategy for the open question of

How do we best handle the situation where a tool cannot be launched because the most recently used project is misconfigured?

There are a couple of one here. If the engine has been used to launch multiple projects, Imagine the recent projects settings file would have that projects listed in most to least recently accessed.

  1. Attempt to iterate through that list and attempt to find a project whose 1. path exist, 2. "engine" field matches the current engine name.
  2. Only attempt to load the most recent project in the recent project settings file.

After each of those options I still believe we need the logic that if no recently used projects can be open by the engine, then proceed to use the same logic as if the application has never launched with a project. (i.e The Editor would launch the Project Manager).

Out of the two options posted above, I think number 2 is more user "safe". It could be unexpected if an application opened the second most recently used project, if the first could not be open. The user would probably not notice the Editor or AP launched a project that wasn't there most recent until started to work within those application.


Now I did notice this RFC brought up the alternative of using the set-global-project command. That command should just writes out the /Amazon/AzCore/Bootstrap/project_path key to a bootstrap.setreg

Using the alternative for all the work that goes into this proposal, it would be simpler to just update the set-global-project/get-global-project command to be engine specific, by add a tag to the filename of bootstrap.<engine-name>.setreg. All that would have to change in that case is to update the DEFAULT_BOOTSTRAP_SETREG constant to be a method that returns bootstrap.<engine-name>.setreg. It is easy enough to get the engine name via manifest.get_engine_json_data(engine_path=manifest.get_this_engine_path())) and add that to the filename.

Once the the global_project commands are updated, the only other thing that needs to be done is to update the C++ code to add the "engine_name" as a specialization tag, which can done at the bottom of SettingsRegistryMergeUtils:FindEngineRoot by merging the engine.json to the settings registry and setting specialization key

AMZN-alexpete commented 2 years ago

@lumberyard-employee-dm wow! This is excellent feedback and I agree with all the recommendations. Regarding the "global" project approach, my only question is, are we planning on deprecating the concept of a "global" project? I wasn't sure if it was a hold over from before we had external projects working.

lemonade-dm commented 2 years ago

@lumberyard-employee-dm wow! This is excellent feedback and I agree with all the recommendations. Regarding the "global" project approach, my only question is, are we planning on deprecating the concept of a "global" project? I wasn't sure if it was a hold over from before we had external projects working.

The global project was added during pre-O3DE development to help ease developers off setting their user specific project inside of the team-wide shared <engine-root>/bootstrap.cfg file.

The logic of adding a "global" project is having the user add a setreg file with no specialization tag to their personal user ~/.o3de/Registry directory and inside that setreg file just set the /Amazon/AzCore/Bootstrap/project_path key.

Since we can convert the concept of a global project to a recent per engine project, just by adding .<engine_name> to a setreg filename, I think we should just rid of the global concept altogether. A recent per engine concept is at a bit safer since the project in question wouldn't try to launch with any engine, it would only be a project that was associated with the engine in the first place. Furthermore we can validate that the project being stored in the setreg file actually registers the engine it is associated with.

I would deprecate the set-global-project/get-global-project command for a newer set-recent-project or set-engine-recent-project command.

Removing the set-global-project command wouldn't affect any users that have used that command to populate a bootstrap.setreg, since the Settings Registry loading logic wouldn't change.

If the user has a boostrap.setreg - it will always be loaded. If the user has a bootstrap.o3de.setreg - it will be loaded when the engine with the name "o3de" is launched.