Skip to content

Commit

Permalink
Added Capabilities, Improved error handling, Fix chat line length
Browse files Browse the repository at this point in the history
The correct name color is now used when available; might add
badges/emoji in the future.
  • Loading branch information
Hotrian committed Jun 26, 2016
1 parent 9b521b3 commit d567da3
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 86 deletions.
62 changes: 14 additions & 48 deletions Assets/HOTK/Twitch/TwitchChatTester.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ public TwitchIRC IRC
}
private TwitchIRC _irc;

private readonly Dictionary<string, string> _userColors = new Dictionary<string, string>();

private readonly List<TwitchChat> _userChat = new List<TwitchChat>();

private bool _connected;
Expand Down Expand Up @@ -132,38 +130,27 @@ private void OnChatMsg(string msg)
switch (channel)
{
case "System-Green":
AddMsg(nickname, ColorToHex(new Color(0f, 1f, 0f)), chat);
AddMsg(nickname, TwitchIRC.ColorToHex(new Color(0f, 1f, 0f)), chat);
break;
case "System-Red":
AddMsg(nickname, ColorToHex(new Color(1f, 0f, 0f)), chat);
AddMsg(nickname, TwitchIRC.ColorToHex(new Color(1f, 0f, 0f)), chat);
break;
case "System-Blue":
AddMsg(nickname, ColorToHex(new Color(0f, 0.4f, 1f)), chat);
AddMsg(nickname, TwitchIRC.ColorToHex(new Color(0f, 0.4f, 1f)), chat);
break;
case "System-Yellow":
AddMsg(nickname, ColorToHex(new Color(1f, 1f, 0f)), chat);
AddMsg(nickname, TwitchIRC.ColorToHex(new Color(1f, 1f, 0f)), chat);
break;
case "System-Purple":
AddMsg(nickname, ColorToHex(new Color(1f, 0f, 1f)), chat);
AddMsg(nickname, TwitchIRC.ColorToHex(new Color(1f, 0f, 1f)), chat);
break;
default:
AddMsg(nickname, ColorToHex(new Color(1f, 1f, 1f)), chat);
AddMsg(nickname, TwitchIRC.ColorToHex(new Color(1f, 1f, 1f)), chat);
break;
}
break;
case "PRIVMSG":
nickname = FirstLetterToUpper(nickname);
if (!_userColors.ContainsKey(nickname))
{
var r = Mathf.Max(0.25f, Random.value);
var g = Mathf.Max(0.25f, Random.value);
var b = Mathf.Max(0.25f, Random.value);
_userColors.Add(nickname, ColorToHex(new Color(r, g, b)));
}

string hex;
if (_userColors.TryGetValue(nickname, out hex))
AddMsg(nickname, hex, chat);
AddMsg(FirstLetterToUpper(nickname), TwitchIRC.GetUserColor(nickname), chat);
break;
}
}
Expand All @@ -188,50 +175,29 @@ private void WordWrapText(List<TwitchChat> messages)
var lines = new List<string>();
TextMesh.text = "";
var ren = TextMesh.GetComponent<Renderer>();
var rowLimit = 0.9f; //find the sweet spot
var rowLimit = 0.975f; //find the sweet spot
foreach (var m in messages)
{
TextMesh.text = string.Format("{0}: ", m.Name);
var builder = string.Format("<color=#{0}FF>{1}</color>: ", m.Color, m.Name);
TextMesh.text = string.Format("<color=#{0}FF>{1}</color>: ", m.Color, m.Name);
string builder = "";
var parts = m.Message.Split(' ');
foreach (var t in parts)
{
builder = TextMesh.text;
TextMesh.text += t + " ";
if (ren.bounds.extents.x > rowLimit)
{
lines.Add(builder.TrimEnd() + System.Environment.NewLine);
TextMesh.text = "";
builder = "";
TextMesh.text = t + " ";
}
builder += t + " ";
builder = TextMesh.text;
}

if (builder != "")
lines.Add(builder.TrimEnd() + System.Environment.NewLine);
lines.Add(builder.TrimEnd() + System.Environment.NewLine);
}

TextMesh.text = lines.Aggregate("", (current, t) => current + t);
}

public static string ColorToHex(Color32 color)
{
return color.r.ToString("X2") + color.g.ToString("X2") + color.b.ToString("X2");
}

public static Color HexToColor(string hex)
{
hex = hex.Replace("0x", "");//in case the string is formatted 0xFFFFFF
hex = hex.Replace("#", "");//in case the string is formatted #FFFFFF
byte a = 255;//assume fully visible unless specified in hex
var r = byte.Parse(hex.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
var g = byte.Parse(hex.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);
var b = byte.Parse(hex.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);
//Only use alpha if the string has enough characters
if (hex.Length == 8)
a = byte.Parse(hex.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);
return new Color32(r, g, b, a);
}

public static string FirstLetterToUpper(string str)
{
if (str == null)
Expand Down
170 changes: 132 additions & 38 deletions Assets/HOTK/Twitch/TwitchIRC.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

public class TwitchIRC : MonoBehaviour
{
public const string DefaultChatNameColor = "#FFFFFFFF";
public string Oauth;
public string NickName;
public string ChannelName;
Expand All @@ -21,7 +22,10 @@ public class MsgEvent : UnityEngine.Events.UnityEvent<string> { }
private readonly Queue<string> _commandQueue = new Queue<string>();
private readonly List<string> _recievedMsgs = new List<string>();
private System.Threading.Thread _inProc, _outProc;


private static readonly Dictionary<string, string> UserColors = new Dictionary<string, string>();
private static System.Random Random = new System.Random();

private bool _connected;
private bool _loggedin;

Expand All @@ -32,7 +36,7 @@ public void StartIRC()
sock.Connect(Server, Port);
if (!sock.Connected)
{
Debug.Log("Failed to connect!");
ToNotice("System", "Failed to connect!", NoticeColor.Red);
return;
}
var networkStream = sock.GetStream();
Expand All @@ -54,7 +58,7 @@ public void StartIRC()
_inProc.Start();

CancelInvoke("CheckConnection");
Invoke("CheckConnection", 5f);
Invoke("CheckConnection", 10f);
}

private void CheckConnection()
Expand All @@ -77,48 +81,109 @@ private void IRCInputProcedure(System.IO.TextReader input, System.Net.Sockets.Ne
{
while (!_stopThreads)
{
if (!networkStream.DataAvailable)
try
{
Thread.Sleep(20);
continue;
}
if (!networkStream.DataAvailable)
{
Thread.Sleep(20);
continue;
}

_buffer = input.ReadLine();
if (_buffer == null) continue;
var tokens = _buffer.Split(' ');
switch (tokens[1])
{
case "PRIVMSG":
case "NOTICE":
lock (_recievedMsgs)
{
_recievedMsgs.Add(_buffer);
}
break;
case "001":
lock (_recievedMsgs)
{
_recievedMsgs.Add(ToTwitchNotice("Logged in! Connecting to chat.."));
_loggedin = true;
}
SendCommand("JOIN #" + ChannelName);
break;
case "JOIN":
lock (_recievedMsgs)
{
_recievedMsgs.Add(ToTwitchNotice(string.Format("Connected to {0}!", tokens[2])));
_connected = true;
}
break;
default:
if (_buffer.StartsWith("PING "))
_buffer = input.ReadLine();
if (_buffer == null) continue;
//Debug.Log(_buffer);

string[] tokens;
string message;
if (_buffer.StartsWith("@"))
{
var split = _buffer.IndexOf(' ');
var userstate = _buffer.Substring(0, split);
message = _buffer.Substring(split + 1);
tokens = message.Split(' ');

var username = tokens[0].Split('!')[0].Substring(1);
var keys = userstate.Split(';');

foreach (var k in keys)
{
SendCommand(_buffer.Replace("PING", "PONG"));
if (k.StartsWith("color="))
{
if (GetUserColor(username) != DefaultChatNameColor) continue;
var color = (k != "color=") ? k.Substring(7) : null;
if (string.IsNullOrEmpty(color))
{
var r = Mathf.Max(0.25f, Random.Next(0, 100)/100f);
var g = Mathf.Max(0.25f, Random.Next(0, 100)/100f);
var b = Mathf.Max(0.25f, Random.Next(0, 100)/100f);
color = ColorToHex(new Color(r, g, b));
}
lock (UserColors)
{
UserColors.Add(username, color);
}
}
}
break;
}
else
{
message = _buffer;
tokens = _buffer.Split(' ');
}

switch (tokens[1])
{
case "PRIVMSG":
case "NOTICE":
lock (_recievedMsgs)
{
_recievedMsgs.Add(message);
}
break;
case "JOIN":
lock (_recievedMsgs)
{
_recievedMsgs.Add(ToTwitchNotice(string.Format("Connected to {0}!", tokens[2])));
_connected = true;
}
break;
case "001":
lock (_recievedMsgs)
{
_recievedMsgs.Add(ToTwitchNotice("Logged in! Connecting to chat.."));
_loggedin = true;
}
SendCommand("CAP REQ :twitch.tv/tags");
SendCommand("CAP REQ :twitch.tv/commands");
SendCommand("JOIN #" + ChannelName);
break;
case "CAP":
lock (_recievedMsgs)
{
_recievedMsgs.Add(ToTwitchNotice("Acknowledging Client Capabilities!"));
_connected = true;
}
break;
case "USERSTATE":
break;
default:
if (_buffer.StartsWith("PING "))
{
SendCommand(_buffer.Replace("PING", "PONG"));
}
break;
}
}
catch (Exception e)
{
lock (_recievedMsgs)
{
_recievedMsgs.Add(ToNotice("EXCEPTION", e.ToString(), NoticeColor.Red));
}
}
}
}

private void IRCOutputProcedure(System.IO.TextWriter output)
{
System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch();
Expand Down Expand Up @@ -202,6 +267,35 @@ public static string ToNotice(string nickname, string msgIn, NoticeColor colorEn
return string.Format(":{0} NOTICE {1} :{2}", nickname, NoticeColorToString(colorEnum), msgIn);
}

public static string GetUserColor(string username)
{
lock (UserColors)
{
string hex;
return UserColors.TryGetValue(username, out hex) ? hex : DefaultChatNameColor;
}
}

public static string ColorToHex(Color32 color)
{
return color.r.ToString("X2") + color.g.ToString("X2") + color.b.ToString("X2");
}

public static Color HexToColor(string hex)
{
hex = hex.Replace("0x", "");//in case the string is formatted 0xFFFFFF
hex = hex.Replace("#", "");//in case the string is formatted #FFFFFF
byte a = 255;//assume fully visible unless specified in hex
var r = byte.Parse(hex.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
var g = byte.Parse(hex.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);
var b = byte.Parse(hex.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);
//Only use alpha if the string has enough characters
if (hex.Length == 8)
a = byte.Parse(hex.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);
return new Color32(r, g, b, a);
}


public static string NoticeColorToString(NoticeColor colorEnum)
{
switch (colorEnum)
Expand Down

0 comments on commit d567da3

Please sign in to comment.