Advertisement
NeoGriever

Untitled

Dec 17th, 2020
52
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.39 KB | None | 0 0
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Text.RegularExpressions;
  5. using UnityEditor;
  6. using UnityEngine.Events;
  7. using System.Net.Sockets;
  8. using System.Threading;
  9. using System.IO;
  10. using System.Diagnostics;
  11.  
  12. [System.Serializable]
  13. public class TwitchChat : MonoBehaviour {
  14. public Twitch twitchBox = new Twitch();
  15. [SerializeField] public string un;
  16. [SerializeField] public string pw;
  17. [SerializeField] public string ch;
  18. public void Start() {
  19. twitchBox.nickname = un;
  20. twitchBox.oauth = pw;
  21. twitchBox.channel = ch;
  22. twitchBox.messageRecievedEvent.AddListener(Inbox);
  23. }
  24. public void Update() {
  25. twitchBox.Tick();
  26. }
  27. public void Inbox(Twitch.MSGInfo msg) {
  28. UnityEngine.Debug.Log(msg.name + ": " + msg.message);
  29. foreach(CommandEntry i in commands) {
  30. Regex r = new Regex("^" + i.commandTrigger);
  31. if(r.IsMatch(msg.message)) {
  32. UnityEngine.Debug.Log(msg.name + " used " + i.commandName);
  33. i.action.Invoke();
  34. }
  35. }
  36. }
  37. public CommandEntry[] commands;
  38. public void SendChatMsg(string msg) {
  39. twitchBox.SendMsg(msg);
  40. }
  41. public void OnDisable() {
  42. twitchBox.StopTwitchChat();
  43. }
  44. }
  45. [System.Serializable]
  46. public class CommandEntry {
  47. [SerializeField] public string commandName;
  48. [SerializeField] public string commandTrigger;
  49. [SerializeField] public UnityEvent action;
  50. public CommandEntry (string name) {
  51. commandName = name;
  52. }
  53. }
  54.  
  55. [CustomEditor(typeof(TwitchChat))]
  56. public class TwitchChatEditor : Editor {
  57. Twitch th;
  58. string msg;
  59. bool isActive;
  60. bool wasActive;
  61. public override void OnInspectorGUI() {
  62. th = (serializedObject.targetObject as TwitchChat).twitchBox;
  63. if (EditorApplication.isPlaying && Application.isPlaying) {
  64. GUI.enabled = false;
  65. }
  66. if(th != null) {
  67. isActive = EditorGUILayout.Foldout(isActive, "Configuration");
  68. if(isActive) {
  69. EditorGUILayout.PropertyField(serializedObject.FindProperty("un"), new GUIContent("Username:"));
  70. EditorGUILayout.PropertyField(serializedObject.FindProperty("pw"), new GUIContent("Password:"));
  71. if(GUILayout.Button("Open twitch.tv/tmi to get oauth/password")) {
  72. Application.OpenURL("https://twitch.tv/tmi");
  73. }
  74. EditorGUILayout.PropertyField(serializedObject.FindProperty("ch"), new GUIContent("Channel:"));
  75. GUILayout.Space(20);
  76. EditorGUILayout.PropertyField(serializedObject.FindProperty("commands"));
  77. GUILayout.Space(20);
  78. }
  79. GUI.enabled = true;
  80. if (!EditorApplication.isPlaying && !Application.isPlaying) {
  81. GUI.enabled = false;
  82. }
  83. if(th.isConnected) {
  84. if(GUILayout.Button("Disconnect from Twitch")) {
  85. th.StopTwitchChat();
  86. msg = "";
  87. }
  88. } else {
  89. if(GUILayout.Button("Connect to Twitch")) {
  90. th.StartTwitchChat();
  91. }
  92. }
  93. GUI.enabled = th.isConnected;
  94. GUILayout.BeginHorizontal();
  95. msg = GUILayout.TextField(msg);
  96. if (GUILayout.Button("Send", GUILayout.Width(60))) {
  97. th.SendMsg(msg);
  98. msg = "";
  99. }
  100. GUILayout.EndHorizontal();
  101. GUI.enabled = true;
  102. }
  103. if(serializedObject.hasModifiedProperties) {
  104. serializedObject.ApplyModifiedProperties();
  105. }
  106. }
  107. }
  108. public class Twitch {
  109. public string oauth;
  110. public string nickname;
  111. public string channel;
  112.  
  113. public class MsgEvent : UnityEvent<MSGInfo> { }
  114. public MsgEvent messageRecievedEvent = new MsgEvent();
  115.  
  116. [HideInInspector]
  117. public string server = "irc.twitch.tv";
  118.  
  119. [HideInInspector]
  120. public int port = 6667;
  121.  
  122. private string buffer = string.Empty;
  123. private bool stopThreads = false;
  124.  
  125. private Queue<string> commandQueue = new Queue<string>();
  126. private List<string> recievedMsgs = new List<string>();
  127.  
  128. private Thread inProc, outProc;
  129.  
  130. private Regex r = new Regex("^(.*?)PRIVMSG.*?:(.*)$");
  131. private Regex r2 = new Regex("^(.*?):");
  132.  
  133. [HideInInspector]
  134. public bool isConnected = false;
  135.  
  136. private void StartIRC() {
  137. // start connection
  138. TcpClient sock = new TcpClient();
  139. sock.Connect(server, port);
  140. if (!sock.Connected) {
  141. // connection failed
  142. UnityEngine.Debug.Log("Failed to connect!");
  143. return;
  144. }
  145. // get stream-handlers
  146. NetworkStream networkStream = sock.GetStream();
  147. TextReader input = (new StreamReader(networkStream)) as TextReader;
  148. StreamWriter output = new StreamWriter(networkStream);
  149.  
  150. // do the login
  151. output.WriteLine("PASS " + oauth);
  152. output.WriteLine("NICK " + nickname.ToLower());
  153. // add tags-request
  154. output.WriteLine("CAP REQ :twitch.tv/tags");
  155. output.Flush();
  156.  
  157. // start threats
  158. isConnected = true;
  159. outProc = new Thread(() => IRCOutputProcedure(output));
  160. outProc.Start();
  161. inProc = new Thread(() => IRCInputProcedure(input, networkStream));
  162. inProc.Start();
  163. }
  164. private void IRCInputProcedure(TextReader input, NetworkStream networkStream) {
  165. while (!stopThreads) {
  166. if (!networkStream.DataAvailable) {
  167. continue;
  168. }
  169. buffer = input.ReadLine();
  170. if (buffer.Contains("PRIVMSG #")) {
  171. lock (recievedMsgs) {
  172. recievedMsgs.Add(buffer);
  173. }
  174. }
  175. if (buffer.StartsWith("PING ")) {
  176. SendCommand(buffer.Replace("PING", "PONG"));
  177. }
  178. if (buffer.Split(' ')[1] == "001") {
  179. SendCommand("JOIN #" + channel);
  180. }
  181. }
  182. isConnected = false;
  183. }
  184. private void IRCOutputProcedure(TextWriter output) {
  185. Stopwatch stopWatch = new Stopwatch();
  186. stopWatch.Start();
  187. while (!stopThreads) {
  188. lock (commandQueue) {
  189. if (commandQueue.Count > 0) {
  190. if (stopWatch.ElapsedMilliseconds > 1750) {
  191. output.WriteLine(commandQueue.Peek());
  192. output.Flush();
  193. commandQueue.Dequeue();
  194. stopWatch.Reset();
  195. stopWatch.Start();
  196. }
  197. }
  198. }
  199. }
  200. isConnected = false;
  201. }
  202. public void SendCommand(string cmd) {
  203. lock (commandQueue) {
  204. commandQueue.Enqueue(cmd);
  205. }
  206. }
  207. public void SendMsg(string msg) {
  208. lock (commandQueue) {
  209. commandQueue.Enqueue("PRIVMSG #" + channel + " :" + msg);
  210. }
  211. MSGInfo mi = new MSGInfo(new string[] {"color=#ff0000", "display-name=" + nickname, "subscriber=0", "mod=0"}, msg);
  212. messageRecievedEvent.Invoke(mi);
  213. }
  214. public void StartTwitchChat() {
  215. stopThreads = false;
  216. StartIRC();
  217. }
  218. public void StopTwitchChat() {
  219. stopThreads = true;
  220. }
  221. void OnDisable() {
  222. StopTwitchChat();
  223. }
  224. void OnDestroy() {
  225. StopTwitchChat();
  226. }
  227. public void Tick() {
  228. lock (recievedMsgs) {
  229. if (recievedMsgs.Count > 0) {
  230. for (int i = 0; i < recievedMsgs.Count; i++) {
  231. handleMsg(recievedMsgs[i]);
  232. }
  233. recievedMsgs.Clear();
  234. }
  235. }
  236. }
  237. private void handleMsg(string msg) {
  238. Match match = r.Match(msg);
  239. string infoBlock = match.Groups[1].Value;
  240. Match match2 = r2.Match(infoBlock);
  241. MSGInfo mi = new MSGInfo(match2.Groups[1].Value.Split(';'), match.Groups[2].Value);
  242. messageRecievedEvent.Invoke(mi);
  243. }
  244. public class MSGInfo {
  245. public string name {get; private set;}
  246. public Color color {get; private set;}
  247. public bool isSubscriber {get; private set;}
  248. public bool isModerator {get; private set;}
  249. public string message {get; private set;}
  250. public MSGInfo(string[] data, string txt) {
  251. message = txt;
  252. string colorData = "";
  253. foreach(string j in data) {
  254. string[] v = j.Split('=');
  255. if(v[0] == "display-name") {
  256. name = v[1];
  257. } else if(v[0] == "color") {
  258. colorData = v[1];
  259. } else if(v[0] == "subscriber") {
  260. isSubscriber = (v[1] == "1");
  261. } else if(v[0] == "mod") {
  262. isModerator = (v[1] == "1");
  263. }
  264. }
  265. color = cfu(name);
  266. if(colorData != "") {
  267. Color genColor = color;
  268. if(ColorUtility.TryParseHtmlString(colorData, out genColor)) {
  269. color = genColor;
  270. }
  271. }
  272. }
  273. private Color cfu(string username) {
  274. Random.InitState(username.Length + (int)username[0] + (int)username[username.Length - 1]);
  275. return new Color(Random.Range(0.25f, 0.55f), Random.Range(0.20f, 0.55f), Random.Range(0.25f, 0.55f));
  276. }
  277. }
  278. }
  279.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement