|
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); |
|
} |
|
} |
|
} |
|
|