예제 #1
0
    public void _u_WebSocketOpened(/* int connectionID */)
    {
        debug._u_Log("[TwitchChatBehavior] _u_WebSocketOpened");

        webManager._u_WebSocketSendStringUnicode(connectionID, "CAP REQ :twitch.tv/tags twitch.tv/commands", true);
        state = TwitchChatState.CapReqSent; // First message sent
    }
예제 #2
0
    void _u_TryStartChat()
    {
        debug._u_Log("[TwitchChatBehavior] _u_TryStartChat");

        if (!_u_PlayerIsOnlineAndAvailable(Networking.GetOwner(gameObject)))
        {
            debug._u_Log("[TwitchChatBehavior] No player is web connected!");

            output.text         = "No player is web connected!";
            currentMessageCount = 0;
            return;
        }

        // The current behavior is to only allow the chat owner to connect through the web handler.
        // Since messages are going to be broadcast to everyone anyway, it would be best for all
        // other web conncted clients to save their Udon processing power and connection counts.
        // Could make chat brokering opt-out and brokering disable options in the future.
        if (!webManager.online || !Networking.IsOwner(gameObject) || !urlIsTwitchChannel)
        {
            return;
        }

        string url = syncedURL.Get();
        string channelToConnectTo = url.Remove(0, 22);

        if (connectionID != -1 && state == TwitchChatState.ChannelJoined && channelToConnectTo != connectedChannelName)
        {
            // Preserve existing websocket connection, simply change irc channel
            webManager._u_WebSocketSendStringUnicode(connectionID, "PART #" + connectedChannelName, true);
            output.text         = "";
            currentMessageCount = 0;
            webManager._u_ClearConnection(connectionID);
            webManager._u_WebSocketSendStringUnicode(connectionID, "JOIN #" + channelToConnectTo, true);
        }
        else
        {
            // Fresh connect!
            // Perform a full reset in case something goes wrong with the websocket connection.
            // Twitch doesn't like to follow full websocket protocol so the helper program runs into issues
            _u_Reset();
            connectionID = webManager._u_WebSocketOpen("wss://irc-ws.chat.twitch.tv/", this, true, true);
            if (connectionID == -1)
            {
                output.text = "Too many active connections!  Finding new broker.\n";
                _u_Resync();
                return;
            }
            else
            {
                state = TwitchChatState.WebSocketOpening;
            }
        }
        connectedChannelName = channelToConnectTo;
    }
예제 #3
0
    void _u_Reset()
    {
        debug._u_Log("[TwitchChatBehavior] _u_Reset");

        // Close if open
        state = TwitchChatState.Off;
        if (connectionID != -1)
        {
            webManager._u_WebSocketClose(connectionID);
            state = TwitchChatState.Closing; // Complete reset
        }
        connectedChannelName = "";
        output.text          = "";
        currentMessageCount  = 0;
    }
예제 #4
0
    public void _u_WebSocketClosed(/* int connectionID */)
    {
        debug._u_Log("[TwitchChatBehavior] _u_WebSocketClosed");

        connectionID        = -1;
        output.text         = "";
        currentMessageCount = 0;
        // This close could have been achieved gracefully as the result of
        // _u_Reset() or ungracefully from twitch aborting the connection
        // because the justinfan nickname was already in use.  If a close wasn't
        // expected, resync.
        connectedChannelName = "";
        if (state != TwitchChatState.Closing)
        {
            _u_TryStartChat();
        }
        else
        {
            state = TwitchChatState.Off;
        }
    }
예제 #5
0
    public void _u_WebSocketReceive(/* int connectionID, byte[] connectionData, string connectionString, bool messageIsText */)
    {
        if (connectionString == "PING :tmi.twitch.tv\r\n")
        {
            debug._u_Log("[TwitchChatBehavior] PING received");
            webManager._u_WebSocketSendStringUnicode(connectionID, "PONG", true);
            return;
        }
        else if (state == TwitchChatState.CapReqSent)
        {
            webManager._u_WebSocketSendStringUnicode(connectionID, "PASS SCHMOOPIIE", true);
            username = "******" + (int)(1000 + Random.value * 80000);
            webManager._u_WebSocketSendStringUnicode(connectionID, "NICK " + username, true);
            state = TwitchChatState.NicknameSent; // Second message sent
        }
        else if (state == TwitchChatState.NicknameSent && connectionString.Contains("Welcome, GLHF!"))
        {
            webManager._u_WebSocketSendStringUnicode(connectionID, "USER " + username + " 8 * :" + username, true);
            webManager._u_WebSocketSendStringUnicode(connectionID, "JOIN #" + connectedChannelName, true);
            state = TwitchChatState.ChannelJoined; // Third message set sent
        }
        else if (state == TwitchChatState.ChannelJoined)
        {
            // Ready to receive chat messages
            string[] split = connectionString.Split(' ');
            if (split.Length < 5 || split[2] != "PRIVMSG")
            {
                // Remove this for release, as this is a security flaw that could allow injecting log lines via twitch chat messages
                // Debug option exclusively for non-chat-message websocket messages.
                // Debug.Log("[TwitchChatBehavior] WebSocketReceive: " + connectionString);
                return;
            }

            string   color   = "white";
            string[] kvPairs = split[0].Split(';');
            foreach (string kv in kvPairs)
            {
                string[] kvSplit = kv.Split('=');
                if (kvSplit.Length > 1 && kvSplit[0] == "color")
                {
                    color = kvSplit[1];
                    break;
                }
            }
            int nicknameSplitIndex = split[1].IndexOf('!');
            if (nicknameSplitIndex < 1 || split[1].Length < 2)
            {
                return;
            }
            string name = split[1].Substring(1, nicknameSplitIndex - 1);
            if (split[4].Length < 1)
            {
                return;
            }
            string messageIndexIdentifier = " PRIVMSG #" + connectedChannelName + " :";
            // Ignore messages from other channels that may be left over after flushing the websocket connection
            int messageStart = connectionString.IndexOf(messageIndexIdentifier);
            if (messageStart != -1)
            {
                string message = connectionString.Substring(messageStart + messageIndexIdentifier.Length);
                // Replace < and > to prevent escapeing Unity UI's rich text markup
                // ≺ ≻
                string completeMessage = "<b><color=" + color + ">" + name + "</color></b>: " + message.Replace('<', '〈').Replace('>', '〉').Replace("\r\n", "");
                if (brokeredMessage != "")
                {
                    brokeredMessage += "\n";
                }
                brokeredMessage += completeMessage;
                brokeredMessageSerializations++;
                RequestSerialization();
                _u_AppendChatMessage();
                // Special case where OnPostSerialization is never reached
                if (VRCPlayerApi.GetPlayerCount() == 1)
                {
                    brokeredMessage = "";
                }
            }
        }
    }