| using System.IO.Abstractions; |
| using System.Text.RegularExpressions; |
| using UnityEngine; |
| using System.IO; |
| using Unity.MLAgents.Policies; |
| using UnityEngine.Serialization; |
|
|
| namespace Unity.MLAgents.Demonstrations |
| { |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| [RequireComponent(typeof(Agent))] |
| [AddComponentMenu("ML Agents/Demonstration Recorder", (int)MenuGroup.Default)] |
| public class DemonstrationRecorder : MonoBehaviour |
| { |
| |
| |
| |
| [FormerlySerializedAs("record")] |
| [Tooltip("Whether or not to record demonstrations.")] |
| public bool Record; |
|
|
| |
| |
| |
| |
| [Tooltip("Number of steps to record. The editor will stop playing when it reaches this threshold. " + |
| "Set to zero to record indefinitely.")] |
| public int NumStepsToRecord; |
|
|
| |
| |
| |
| |
| [FormerlySerializedAs("demonstrationName")] |
| [Tooltip("Base demonstration file name. If multiple files are saved, the additional " + |
| "filenames will have a unique number appended.")] |
| public string DemonstrationName; |
|
|
| |
| |
| |
| |
| [FormerlySerializedAs("demonstrationDirectory")] |
| [Tooltip("Directory to save the demo files. Will default to " + |
| "{Application.dataPath}/Demonstrations if not specified.")] |
| public string DemonstrationDirectory; |
|
|
| DemonstrationWriter m_DemoWriter; |
| internal const int MaxNameLength = 16; |
|
|
| const string k_ExtensionType = ".demo"; |
| const string k_DefaultDirectoryName = "Demonstrations"; |
| IFileSystem m_FileSystem; |
|
|
| Agent m_Agent; |
|
|
| void OnEnable() |
| { |
| m_Agent = GetComponent<Agent>(); |
| } |
|
|
| void Update() |
| { |
| if (!Record) |
| { |
| return; |
| } |
|
|
| LazyInitialize(); |
|
|
| |
| if (NumStepsToRecord > 0 && m_DemoWriter.NumSteps >= NumStepsToRecord) |
| { |
| Application.Quit(0); |
| #if UNITY_EDITOR |
| UnityEditor.EditorApplication.isPlaying = false; |
| #endif |
| } |
| } |
|
|
| |
| |
| |
| |
| internal DemonstrationWriter LazyInitialize(IFileSystem fileSystem = null) |
| { |
| if (m_DemoWriter != null) |
| { |
| return m_DemoWriter; |
| } |
|
|
| if (m_Agent == null) |
| { |
| m_Agent = GetComponent<Agent>(); |
| } |
|
|
| m_FileSystem = fileSystem ?? new FileSystem(); |
| var behaviorParams = GetComponent<BehaviorParameters>(); |
| if (string.IsNullOrEmpty(DemonstrationName)) |
| { |
| DemonstrationName = behaviorParams.BehaviorName; |
| } |
| if (string.IsNullOrEmpty(DemonstrationDirectory)) |
| { |
| DemonstrationDirectory = Path.Combine(Application.dataPath, k_DefaultDirectoryName); |
| } |
|
|
| DemonstrationName = SanitizeName(DemonstrationName, MaxNameLength); |
| var filePath = MakeDemonstrationFilePath(m_FileSystem, DemonstrationDirectory, DemonstrationName); |
| var stream = m_FileSystem.File.Create(filePath); |
| m_DemoWriter = new DemonstrationWriter(stream); |
|
|
| AddDemonstrationWriterToAgent(m_DemoWriter); |
|
|
| return m_DemoWriter; |
| } |
|
|
| |
| |
| |
| |
| internal static string SanitizeName(string demoName, int maxNameLength) |
| { |
| var rgx = new Regex("[^a-zA-Z0-9 -]"); |
| demoName = rgx.Replace(demoName, ""); |
| |
| if (demoName.Length > maxNameLength) |
| { |
| demoName = demoName.Substring(0, maxNameLength); |
| } |
| return demoName; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| internal static string MakeDemonstrationFilePath( |
| IFileSystem fileSystem, string demonstrationDirectory, string demonstrationName |
| ) |
| { |
| |
| if (!fileSystem.Directory.Exists(demonstrationDirectory)) |
| { |
| fileSystem.Directory.CreateDirectory(demonstrationDirectory); |
| } |
|
|
| var literalName = demonstrationName; |
| var filePath = Path.Combine(demonstrationDirectory, literalName + k_ExtensionType); |
| var uniqueNameCounter = 0; |
| while (fileSystem.File.Exists(filePath)) |
| { |
| |
| |
| literalName = demonstrationName + "_" + uniqueNameCounter; |
| filePath = Path.Combine(demonstrationDirectory, literalName + k_ExtensionType); |
| uniqueNameCounter++; |
| } |
|
|
| return filePath; |
| } |
|
|
| |
| |
| |
| |
| public void Close() |
| { |
| if (m_DemoWriter != null) |
| { |
| RemoveDemonstrationWriterFromAgent(m_DemoWriter); |
|
|
| m_DemoWriter.Close(); |
| m_DemoWriter = null; |
| } |
| } |
|
|
| |
| |
| |
| void OnDestroy() |
| { |
| Close(); |
| } |
|
|
| |
| |
| |
| |
| |
| public void AddDemonstrationWriterToAgent(DemonstrationWriter demoWriter) |
| { |
| var behaviorParams = GetComponent<BehaviorParameters>(); |
| demoWriter.Initialize( |
| DemonstrationName, |
| behaviorParams.BrainParameters, |
| behaviorParams.FullyQualifiedBehaviorName |
| ); |
| m_Agent.DemonstrationWriters.Add(demoWriter); |
| } |
|
|
| |
| |
| |
| |
| |
| public void RemoveDemonstrationWriterFromAgent(DemonstrationWriter demoWriter) |
| { |
| m_Agent.DemonstrationWriters.Remove(demoWriter); |
| } |
| } |
| } |
|
|