Skip to content

Add custom package settings #5027

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Mar 18, 2021
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
# Environemnt logfile
*Project.log

# Custom settings asset
*.settings.asset*

# Visual Studio 2015 cache directory
/Project/.vs/

Expand Down
4 changes: 3 additions & 1 deletion Project/ProjectSettings/EditorBuildSettings.asset
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ EditorBuildSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Scenes: []
m_configObjects: {}
m_configObjects:
com.unity.ml-agents.settings: {fileID: 11400000, guid: 8251314d30f37425fa7da540c9c35c79,
type: 2}
13 changes: 12 additions & 1 deletion Project/ProjectSettings/ProjectSettings.asset
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ PlayerSettings:
switchNVNShaderPoolsGranularity: 33554432
switchNVNDefaultPoolsGranularity: 16777216
switchNVNOtherPoolsGranularity: 16777216
switchNVNMaxPublicTextureIDCount: 0
switchNVNMaxPublicSamplerIDCount: 0
vulkanEnableSetSRGBWrite: 0
m_SupportedAspectRatios:
4:3: 1
Expand All @@ -120,7 +122,8 @@ PlayerSettings:
16:9: 1
Others: 1
bundleVersion: 1.0
preloadedAssets: []
preloadedAssets:
- {fileID: 11400000, guid: 8251314d30f37425fa7da540c9c35c79, type: 2}
metroInputSource: 0
wsaTransparentSwapchain: 0
m_HolographicPauseOnTrackingLoss: 1
Expand Down Expand Up @@ -234,6 +237,7 @@ PlayerSettings:
metalEditorSupport: 1
metalAPIValidation: 1
iOSRenderExtraFrameOnPause: 1
iosCopyPluginsCodeInsteadOfSymlink: 0
appleDeveloperTeamID:
iOSManualSigningProvisioningProfileID:
tvOSManualSigningProvisioningProfileID:
Expand Down Expand Up @@ -319,6 +323,7 @@ PlayerSettings:
switchTitleNames_12:
switchTitleNames_13:
switchTitleNames_14:
switchTitleNames_15:
switchPublisherNames_0:
switchPublisherNames_1:
switchPublisherNames_2:
Expand All @@ -334,6 +339,7 @@ PlayerSettings:
switchPublisherNames_12:
switchPublisherNames_13:
switchPublisherNames_14:
switchPublisherNames_15:
switchIcons_0: {fileID: 0}
switchIcons_1: {fileID: 0}
switchIcons_2: {fileID: 0}
Expand All @@ -349,6 +355,7 @@ PlayerSettings:
switchIcons_12: {fileID: 0}
switchIcons_13: {fileID: 0}
switchIcons_14: {fileID: 0}
switchIcons_15: {fileID: 0}
switchSmallIcons_0: {fileID: 0}
switchSmallIcons_1: {fileID: 0}
switchSmallIcons_2: {fileID: 0}
Expand All @@ -364,6 +371,7 @@ PlayerSettings:
switchSmallIcons_12: {fileID: 0}
switchSmallIcons_13: {fileID: 0}
switchSmallIcons_14: {fileID: 0}
switchSmallIcons_15: {fileID: 0}
switchManualHTML:
switchAccessibleURLs:
switchLegalInformation:
Expand Down Expand Up @@ -452,6 +460,7 @@ PlayerSettings:
ps4ShareFilePath:
ps4ShareOverlayImagePath:
ps4PrivacyGuardImagePath:
ps4ExtraSceSysFile:
ps4NPtitleDatPath:
ps4RemotePlayKeyAssignment: -1
ps4RemotePlayKeyMappingDir:
Expand Down Expand Up @@ -492,6 +501,8 @@ PlayerSettings:
ps4disableAutoHideSplash: 0
ps4videoRecordingFeaturesUsed: 0
ps4contentSearchFeaturesUsed: 0
ps4CompatibilityPS5: 0
ps4GPU800MHz: 1
ps4attribEyeToEyeDistanceSettingVR: 0
ps4IncludedModules: []
monoEnv:
Expand Down
74 changes: 74 additions & 0 deletions com.unity.ml-agents/Editor/MLAgentsSettingsBuildProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System.Linq;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be a dumb question, but why do we have a BuildSettingsProvider if none of the settings are used in a build? (They are all Editor only settings?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they are used in builds, if you don't want to train or even try to connect to a trainer in a game that's being shipped you'd want to know that in your build.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are used in builds. If you don't want to train or even try to connect to a trainer in a game that's being shipped, you'd want to know that in your build.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean the use case it to remove the command line argument listeners on the build? Because a build will not try to listen to a trainer unless a specific command line argument is passed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. Originally I made a player training port but that doesn't seem to make much sense so I removed that.
But I still think there's chance that we'll add settings that is used in player (analytics? academy stepping?)

using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;


namespace Unity.MLAgents.Editor
{
internal class MLAgentsSettingsBuildProvider : IPreprocessBuildWithReport, IPostprocessBuildWithReport
{
private MLAgentsSettings m_SettingsAddedToPreloadedAssets;

public int callbackOrder => 0;

public void OnPreprocessBuild(BuildReport report)
{
var wasDirty = IsPlayerSettingsDirty();
m_SettingsAddedToPreloadedAssets = null;

var preloadedAssets = PlayerSettings.GetPreloadedAssets().ToList();
if (!preloadedAssets.Contains(MLAgentsManager.Settings))
{
m_SettingsAddedToPreloadedAssets = MLAgentsManager.Settings;
preloadedAssets.Add(m_SettingsAddedToPreloadedAssets);
PlayerSettings.SetPreloadedAssets(preloadedAssets.ToArray());
}

if (!wasDirty)
ClearPlayerSettingsDirtyFlag();
}

public void OnPostprocessBuild(BuildReport report)
{
if (m_SettingsAddedToPreloadedAssets == null)
return;

var wasDirty = IsPlayerSettingsDirty();

var preloadedAssets = PlayerSettings.GetPreloadedAssets().ToList();
if (preloadedAssets.Contains(m_SettingsAddedToPreloadedAssets))
{
preloadedAssets.Remove(m_SettingsAddedToPreloadedAssets);
PlayerSettings.SetPreloadedAssets(preloadedAssets.ToArray());
}

m_SettingsAddedToPreloadedAssets = null;

if (!wasDirty)
ClearPlayerSettingsDirtyFlag();
}


private static bool IsPlayerSettingsDirty()
{
#if UNITY_2019_OR_NEWER
var settings = Resources.FindObjectsOfTypeAll<PlayerSettings>();
if (settings != null && settings.Length > 0)
return EditorUtility.IsDirty(settings[0]);
return false;
#else
return false;
#endif
}

private static void ClearPlayerSettingsDirtyFlag()
{
#if UNITY_2019_OR_NEWER
var settings = Resources.FindObjectsOfTypeAll<PlayerSettings>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PlayerSettings? I thought this would be an MLAgentsSettings.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're injecting our settings into the preload assets in PlayerSettings and these method is to detect/clear the dirty flag of PlayerSettings before/after we put in our settings. So PlayerSettings here is correct.

if (settings != null && settings.Length > 0)
EditorUtility.ClearDirty(settings[0]);
#endif
}
}
}
11 changes: 11 additions & 0 deletions com.unity.ml-agents/Editor/MLAgentsSettingsBuildProvider.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

188 changes: 188 additions & 0 deletions com.unity.ml-agents/Editor/MLAgentsSettingsProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
using System;
using System.Linq;
using System.IO;
using UnityEngine;
using UnityEditor;
#if UNITY_2019_4_OR_NEWER
using UnityEngine.UIElements;
#else
using UnityEngine.Experimental.UIElements;
#endif

namespace Unity.MLAgents.Editor
{
internal class MLAgentsSettingsProvider : SettingsProvider, IDisposable
{
const string k_SettingsPath = "Project/ML-Agents";
private static MLAgentsSettingsProvider s_Instance;
private string[] m_AvailableSettingsAssets;
private int m_CurrentSelectedSettingsAsset;
private SerializedObject m_SettingsObject;
[SerializeField]
private MLAgentsSettings m_Settings;


private MLAgentsSettingsProvider(string path, SettingsScope scope = SettingsScope.Project)
: base(path, scope)
{
s_Instance = this;
}

[SettingsProvider]
public static SettingsProvider CreateMLAgentsSettingsProvider()
{
return new MLAgentsSettingsProvider(k_SettingsPath, SettingsScope.Project);
}

public override void OnActivate(string searchContext, VisualElement rootElement)
{
base.OnActivate(searchContext, rootElement);
MLAgentsManager.OnSettingsChange += Reinitialize;
}

public override void OnDeactivate()
{
base.OnDeactivate();
MLAgentsManager.OnSettingsChange -= Reinitialize;
}

public void Dispose()
{
m_SettingsObject?.Dispose();
}

public override void OnTitleBarGUI()
{
if (EditorGUILayout.DropdownButton(EditorGUIUtility.IconContent("_Popup"), FocusType.Passive, EditorStyles.label))
{
var menu = new GenericMenu();
for (var i = 0; i < m_AvailableSettingsAssets.Length; i++)
menu.AddItem(ExtractDisplayName(m_AvailableSettingsAssets[i]), m_CurrentSelectedSettingsAsset == i, (path) =>
{
MLAgentsManager.Settings = AssetDatabase.LoadAssetAtPath<MLAgentsSettings>((string)path);
}, m_AvailableSettingsAssets[i]);
menu.AddSeparator("");
menu.AddItem(new GUIContent("New Settings Asset…"), false, CreateNewSettingsAsset);
menu.ShowAsContext();
Event.current.Use();
}
}

private GUIContent ExtractDisplayName(string name)
{
if (name.StartsWith("Assets/"))
name = name.Substring("Assets/".Length);
if (name.EndsWith(".asset"))
name = name.Substring(0, name.Length - ".asset".Length);
if (name.EndsWith(".mlagents.settings"))
name = name.Substring(0, name.Length - ".settings".Length);

// Ugly hack: GenericMenu iterprets "/" as a submenu path. But luckily, "/" is not the only slash we have in Unicode.
return new GUIContent(name.Replace("/", "\u29f8"));
}

private void CreateNewSettingsAsset()
{
// Asset database always use forward slashes. Use forward slashes for all the paths.
var projectName = PlayerSettings.productName;
var path = EditorUtility.SaveFilePanel("Create ML-Agents Settings File", "Assets",
projectName + ".mlagents.settings", "asset");
if (string.IsNullOrEmpty(path))
return;

path = path.Replace("\\", "/"); // Make sure we only get '/' separators.
var assetPath = Application.dataPath + "/";
if (!path.StartsWith(assetPath, StringComparison.CurrentCultureIgnoreCase))
{
Debug.LogError(string.Format(
"Settings must be stored in Assets folder of the project (got: '{0}')", path));
return;
}

var extension = Path.GetExtension(path);
if (string.Compare(extension, ".asset", StringComparison.InvariantCultureIgnoreCase) != 0)
path += ".asset";

var relativePath = "Assets/" + path.Substring(assetPath.Length);
CreateNewSettingsAsset(relativePath);
}

private static void CreateNewSettingsAsset(string relativePath)
{
var settings = ScriptableObject.CreateInstance<MLAgentsSettings>();
AssetDatabase.CreateAsset(settings, relativePath);
EditorGUIUtility.PingObject(settings);
// Install the settings. This will lead to an MLAgentsManager.OnSettingsChange event
// which in turn will cause this Provider to reinitialize
MLAgentsManager.Settings = settings;
}

public override void OnGUI(string searchContext)
{
if (m_Settings == null)
{
InitializeWithCurrentSettings();
}

if (m_AvailableSettingsAssets.Length == 0)
{
EditorGUILayout.HelpBox(
"Click the button below to create a settings asset you can edit.",
MessageType.Info);
if (GUILayout.Button("Create settings asset", GUILayout.Height(30)))
CreateNewSettingsAsset();
GUILayout.Space(20);
}

using (new EditorGUI.DisabledScope(m_AvailableSettingsAssets.Length == 0))
{
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(m_SettingsObject.FindProperty("m_ConnectTrainer"), new GUIContent("Connect to Trainer"));
EditorGUILayout.PropertyField(m_SettingsObject.FindProperty("m_EditorPort"), new GUIContent("Editor Training Port"));
if (EditorGUI.EndChangeCheck())
m_SettingsObject.ApplyModifiedProperties();
}
}

internal void InitializeWithCurrentSettings()
{
m_AvailableSettingsAssets = FindSettingsInProject();

m_Settings = MLAgentsManager.Settings;
var currentSettingsPath = AssetDatabase.GetAssetPath(m_Settings);
if (string.IsNullOrEmpty(currentSettingsPath))
{
if (m_AvailableSettingsAssets.Length > 0)
{
m_CurrentSelectedSettingsAsset = 0;
m_Settings = AssetDatabase.LoadAssetAtPath<MLAgentsSettings>(m_AvailableSettingsAssets[0]);
MLAgentsManager.Settings = m_Settings;
}
}
else
{
var settingsList = m_AvailableSettingsAssets.ToList();
m_CurrentSelectedSettingsAsset = settingsList.IndexOf(currentSettingsPath);

EditorBuildSettings.AddConfigObject(MLAgentsManager.EditorBuildSettingsConfigKey, m_Settings, true);
}

m_SettingsObject = new SerializedObject(m_Settings);
}

private static string[] FindSettingsInProject()
{
var guids = AssetDatabase.FindAssets("t:MLAgentsSettings");
return guids.Select(guid => AssetDatabase.GUIDToAssetPath(guid)).ToArray();
}

private void Reinitialize()
{
if (m_Settings != null && MLAgentsManager.Settings != m_Settings)
{
InitializeWithCurrentSettings();
}
Repaint();
}
}
}
11 changes: 11 additions & 0 deletions com.unity.ml-agents/Editor/MLAgentsSettingsProvider.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion com.unity.ml-agents/Runtime/Academy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ static int ReadPortFromArgs()
// No arg passed, or malformed port number.
#if UNITY_EDITOR
// Try connecting on the default editor port
return k_EditorTrainingPort;
return MLAgentsManager.Settings.ConnectTrainer ? MLAgentsManager.Settings.EditorPort : -1;
#else
// This is an executable, so we don't try to connect.
return -1;
Expand Down
Loading