public static SpeakingEvent Prepare(CharacterData character, char letter, float duration) { var e = new SpeakingEvent(); e.Letter = letter; e.Duration = duration; e.Character = character; return(e); }
private async Task ProcessMessageAsync(VoiceOpCode opCode, object payload) { _lastMessageTime = Environment.TickCount; try { switch (opCode) { case VoiceOpCode.Ready: { await _audioLogger.DebugAsync("Received Ready").ConfigureAwait(false); ReadyEvent data = (payload as JToken).ToObject <ReadyEvent>(_serializer); _ssrc = data.SSRC; if (!data.Modes.Contains(DiscordVoiceAPIClient.Mode)) { throw new InvalidOperationException($"Discord does not support {DiscordVoiceAPIClient.Mode}"); } ApiClient.SetUdpEndpoint(data.Ip, data.Port); await ApiClient.SendDiscoveryAsync(_ssrc).ConfigureAwait(false); _heartbeatTask = RunHeartbeatAsync(41250, _connection.CancelToken); } break; case VoiceOpCode.SessionDescription: { await _audioLogger.DebugAsync("Received SessionDescription").ConfigureAwait(false); SessionDescriptionEvent data = (payload as JToken).ToObject <SessionDescriptionEvent>(_serializer); if (data.Mode != DiscordVoiceAPIClient.Mode) { throw new InvalidOperationException($"Discord selected an unexpected mode: {data.Mode}"); } SecretKey = data.SecretKey; _isSpeaking = false; await ApiClient.SendSetSpeaking(false).ConfigureAwait(false); _keepaliveTask = RunKeepaliveAsync(5000, _connection.CancelToken); Task _ = _connection.CompleteAsync(); } break; case VoiceOpCode.HeartbeatAck: { await _audioLogger.DebugAsync("Received HeartbeatAck").ConfigureAwait(false); if (_heartbeatTimes.TryDequeue(out long time)) { int latency = (int)(Environment.TickCount - time); int before = Latency; Latency = latency; await _latencyUpdatedEvent.InvokeAsync(before, latency).ConfigureAwait(false); } } break; case VoiceOpCode.Speaking: { await _audioLogger.DebugAsync("Received Speaking").ConfigureAwait(false); SpeakingEvent data = (payload as JToken).ToObject <SpeakingEvent>(_serializer); _ssrcMap[data.Ssrc] = data.UserId; //TODO: Memory Leak: SSRCs are never cleaned up await _speakingUpdatedEvent.InvokeAsync(data.UserId, data.Speaking); } break; default: await _audioLogger.WarningAsync($"Unknown OpCode ({opCode})").ConfigureAwait(false); return; } } catch (Exception ex) { await _audioLogger.ErrorAsync($"Error handling {opCode}", ex).ConfigureAwait(false); return; } }
IEnumerator DisplayDialogue(DialogueNode d) { // emit dialogue started event EventDispatcher.Dispatch(DialogueEvent.Prepare(d, true)); // Find the speaking character speakingCharacter = DialogueManager.Instance.GetCharacter(d.Character); // Clear the text box DialogueText.text = ""; NameText.text = d.Character.Name; var index = 0; // Get the text from the dialogue var rawText = d.Text; // Wait a frame to avoid accidentally skipping to next dialogue yield return(null); // While there's letters left to show while (index < rawText.Length) { if (Input.GetMouseButtonUp(0)) { index = rawText.Length - 1; } // get a version of the text we can modify var currentText = rawText; if (rawText[index] == '<') { while (index < rawText.Length && rawText[index] != '>') { index++; } } // Insert the alpha tag to hide text after the index currentText = currentText.Insert(index + 1, "<alpha=#00>"); currentText += "<\\alpha>"; // Display the text DialogueText.text = currentText; // Wait for a while depending on what character we just showed if (Char.IsLetterOrDigit(rawText[index])) { EventDispatcher.Dispatch(SpeakingEvent.Prepare(d.Character, rawText[index], LetterDelay)); yield return(StartCoroutine(SkippableWaitForSeconds(LetterDelay))); } else if (rawText[index] == '.') { yield return(StartCoroutine(SkippableWaitForSeconds(SentanceDelay))); } else if (rawText[index] == ' ') { yield return(StartCoroutine(SkippableWaitForSeconds(SpaceDelay))); } else { yield return(StartCoroutine(SkippableWaitForSeconds(LetterDelay))); } // Go to the next character index++; } // Wait a frame to avoid accidentally skipping to next dialogue yield return(null); // If we're supposed to wait for input, wait for that here while (d.WaitForInput && !Input.GetMouseButtonUp(0)) { yield return(null); } // Emit an event saying the dialogue is over EventDispatcher.Dispatch(DialogueEvent.Prepare(d, false)); }