using System.Collections.Generic; using System; using UnityEngine; namespace Unity.MLAgents.SideChannels { /// /// Lists the different data types supported. /// internal enum EnvironmentDataTypes { Float = 0, Sampler = 1 } /// /// The types of distributions from which to sample reset parameters. /// internal enum SamplerType { /// /// Samples a reset parameter from a uniform distribution. /// Uniform = 0, /// /// Samples a reset parameter from a Gaussian distribution. /// Gaussian = 1, /// /// Samples a reset parameter from a MultiRangeUniform distribution. /// MultiRangeUniform = 2 } /// /// A side channel that manages the environment parameter values from Python. Currently /// limited to parameters of type float. /// internal class EnvironmentParametersChannel : SideChannel { Dictionary> m_Parameters = new Dictionary>(); Dictionary> m_RegisteredActions = new Dictionary>(); const string k_EnvParamsId = "534c891e-810f-11ea-a9d0-822485860400"; /// /// Initializes the side channel. The constructor is internal because only one instance is /// supported at a time, and is created by the Academy. /// internal EnvironmentParametersChannel() { ChannelId = new Guid(k_EnvParamsId); } /// protected override void OnMessageReceived(IncomingMessage msg) { var key = msg.ReadString(); var type = msg.ReadInt32(); if ((int)EnvironmentDataTypes.Float == type) { var value = msg.ReadFloat32(); m_Parameters[key] = () => value; Action action; m_RegisteredActions.TryGetValue(key, out action); action?.Invoke(value); } else if ((int)EnvironmentDataTypes.Sampler == type) { int seed = msg.ReadInt32(); int samplerType = msg.ReadInt32(); Func sampler = () => 0.0f; if ((int)SamplerType.Uniform == samplerType) { float min = msg.ReadFloat32(); float max = msg.ReadFloat32(); sampler = SamplerFactory.CreateUniformSampler(min, max, seed); } else if ((int)SamplerType.Gaussian == samplerType) { float mean = msg.ReadFloat32(); float stddev = msg.ReadFloat32(); sampler = SamplerFactory.CreateGaussianSampler(mean, stddev, seed); } else if ((int)SamplerType.MultiRangeUniform == samplerType) { IList intervals = msg.ReadFloatList(); sampler = SamplerFactory.CreateMultiRangeUniformSampler(intervals, seed); } else { Debug.LogWarning("EnvironmentParametersChannel received an unknown data type."); } m_Parameters[key] = sampler; } else { Debug.LogWarning("EnvironmentParametersChannel received an unknown data type."); } } /// /// Returns the parameter value associated with the provided key. Returns the default /// value if one doesn't exist. /// /// Parameter key. /// Default value to return. /// public float GetWithDefault(string key, float defaultValue) { Func valueOut; bool hasKey = m_Parameters.TryGetValue(key, out valueOut); return hasKey ? valueOut.Invoke() : defaultValue; } /// /// Registers a callback for the associated parameter key. Will overwrite any existing /// actions for this parameter key. /// /// The parameter key. /// The callback. public void RegisterCallback(string key, Action action) { m_RegisteredActions[key] = action; } /// /// Returns all parameter keys that have a registered value. /// /// public IList ListParameters() { return new List(m_Parameters.Keys); } } }