UnityInputProto Exchange(UnityOutputProto unityOutput) { #if UNITY_EDITOR || UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_STANDALONE_LINUX if (!m_IsOpen) { return(null); } try { var message = m_Client.Exchange(WrapMessage(unityOutput, 200)); if (message.Header.Status == 200) { return(message.UnityInput); } m_IsOpen = false; // Not sure if the quit command is actually sent when a // non 200 message is received. Notify that we are indeed // quitting. QuitCommandReceived?.Invoke(); return(message.UnityInput); } catch { m_IsOpen = false; QuitCommandReceived?.Invoke(); return(null); } #else throw new UnityAgentsException( "You cannot perform training on this platform."); #endif }
UnityInputProto Initialize(UnityOutputProto unityOutput, out UnityInputProto unityInput) { #if UNITY_EDITOR || UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_STANDALONE_LINUX m_IsOpen = true; var channel = new Channel( "localhost:" + m_CommunicatorInitParameters.port, ChannelCredentials.Insecure); m_Client = new UnityToExternalProto.UnityToExternalProtoClient(channel); var result = m_Client.Exchange(WrapMessage(unityOutput, 200)); var inputMessage = m_Client.Exchange(WrapMessage(null, 200)); unityInput = inputMessage.UnityInput; #if UNITY_EDITOR EditorApplication.playModeStateChanged += HandleOnPlayModeChanged; #endif if (result.Header.Status != 200 || inputMessage.Header.Status != 200) { m_IsOpen = false; QuitCommandReceived?.Invoke(); } return(result.UnityInput); #else throw new UnityAgentsException( "You cannot perform training on this platform."); #endif }
/// <summary> /// Send a UnityOutput and receives a UnityInput. /// </summary> /// <returns>The next UnityInput.</returns> /// <param name="unityOutput">The UnityOutput to be sent.</param> UnityInputProto Exchange(UnityOutputProto unityOutput) { if (!m_IsOpen) { return(null); } try { var message = m_Client.Exchange(WrapMessage(unityOutput, 200)); if (message.Header.Status == 200) { return(message.UnityInput); } m_IsOpen = false; // Not sure if the quit command is actually sent when a // non 200 message is received. Notify that we are indeed // quitting. NotifyQuitAndShutDownChannel(); return(message.UnityInput); } catch (Exception ex) { if (ex is RpcException rpcException) { // Log more verbose errors if they're something the user can possibly do something about. switch (rpcException.Status.StatusCode) { case StatusCode.Unavailable: // This can happen when python disconnects. Ignore it to avoid noisy logs. break; case StatusCode.ResourceExhausted: // This happens is the message body is too large. There's no way to // gracefully handle this, but at least we can show the message and the // user can try to reduce the number of agents or observation sizes. Debug.LogError($"GRPC Exception: {rpcException.Message}. Disconnecting from trainer."); break; default: // Other unknown errors. Log at INFO level. Debug.Log($"GRPC Exception: {rpcException.Message}. Disconnecting from trainer."); break; } } else { // Fall-through for other error types Debug.LogError($"Communication Exception: {ex.Message}. Disconnecting from trainer."); } m_IsOpen = false; NotifyQuitAndShutDownChannel(); return(null); } }
/// <summary> /// Wraps the UnityOutput into a message with the appropriate status. /// </summary> /// <returns>The UnityMessage corresponding.</returns> /// <param name="content">The UnityOutput to be wrapped.</param> /// <param name="status">The status of the message.</param> static UnityMessageProto WrapMessage(UnityOutputProto content, int status) { return(new UnityMessageProto { Header = new HeaderProto { Status = status }, UnityOutput = content }); }
UnityInputProto Initialize(int port, UnityOutputProto unityOutput, out UnityInputProto unityInput) { m_IsOpen = true; m_Channel = new Channel($"localhost:{port}", ChannelCredentials.Insecure); m_Client = new UnityToExternalProto.UnityToExternalProtoClient(m_Channel); var result = m_Client.Exchange(WrapMessage(unityOutput, 200)); var inputMessage = m_Client.Exchange(WrapMessage(null, 200)); unityInput = inputMessage.UnityInput; #if UNITY_EDITOR EditorApplication.playModeStateChanged += HandleOnPlayModeChanged; #endif if (result.Header.Status != 200 || inputMessage.Header.Status != 200) { m_IsOpen = false; NotifyQuitAndShutDownChannel(); } return(result.UnityInput); }
/// <summary> /// Helper method that sends the current UnityRLOutput, receives the next UnityInput and /// Applies the appropriate AgentAction to the agents. /// </summary> void SendBatchedMessageHelper() { var message = new UnityOutputProto { RlOutput = m_CurrentUnityRlOutput, }; var tempUnityRlInitializationOutput = GetTempUnityRlInitializationOutput(); if (tempUnityRlInitializationOutput != null) { message.RlInitializationOutput = tempUnityRlInitializationOutput; } byte[] messageAggregated = SideChannelManager.GetSideChannelMessage(); message.RlOutput.SideChannel = ByteString.CopyFrom(messageAggregated); var input = Exchange(message); UpdateSentActionSpec(tempUnityRlInitializationOutput); foreach (var k in m_CurrentUnityRlOutput.AgentInfos.Keys) { m_CurrentUnityRlOutput.AgentInfos[k].Value.Clear(); } var rlInput = input?.RlInput; if (rlInput?.AgentActions == null) { return; } UpdateEnvironmentWithInput(rlInput); foreach (var brainName in rlInput.AgentActions.Keys) { if (!m_OrderedAgentsRequestingDecisions[brainName].Any()) { continue; } if (!rlInput.AgentActions[brainName].Value.Any()) { continue; } var agentActions = rlInput.AgentActions[brainName].ToAgentActionList(); var numAgents = m_OrderedAgentsRequestingDecisions[brainName].Count; for (var i = 0; i < numAgents; i++) { var agentAction = agentActions[i]; var agentId = m_OrderedAgentsRequestingDecisions[brainName][i]; if (m_LastActionsReceived[brainName].ContainsKey(agentId)) { m_LastActionsReceived[brainName][agentId] = agentAction; } } } foreach (var brainName in m_OrderedAgentsRequestingDecisions.Keys) { m_OrderedAgentsRequestingDecisions[brainName].Clear(); } }