using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using Assets.Scripts.Actors.Enemies;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Il2CppInterop.Runtime.Injection;
using Il2CppSystem.Threading;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
namespace TwitchIntegration;
[BepInPlugin("TwitchIntegration", "MegaBonk Twitch Integration", "1.0.0")]
public class Plugin : BasePlugin
{
internal static ManualLogSource Log;
private static GameObject twitchIntegrationObject;
public override void Load()
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Expected O, but got Unknown
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Expected O, but got Unknown
Log = ((BasePlugin)this).Log;
PluginConfig.Initialize(((BasePlugin)this).Config);
ClassInjector.RegisterTypeInIl2Cpp<TwitchIntegrationBase>();
twitchIntegrationObject = new GameObject("TwitchIntegration");
twitchIntegrationObject.AddComponent<TwitchIntegrationBase>();
Object.DontDestroyOnLoad((Object)(object)twitchIntegrationObject);
ManualLogSource log = Log;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(18, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Plugin ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("TwitchIntegration");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" is loaded!");
}
log.LogInfo(val);
}
public override bool Unload()
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Expected O, but got Unknown
if ((Object)(object)twitchIntegrationObject != (Object)null)
{
Object.Destroy((Object)(object)twitchIntegrationObject);
twitchIntegrationObject = null;
}
ManualLogSource log = Log;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(17, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Plugin ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("TwitchIntegration");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" unloaded!");
}
log.LogInfo(val);
return true;
}
}
public class Bosses
{
private class BossData
{
public TargetOfInterestPrefab target;
public EnemyData enemyData;
public string name;
public GameObject dialogCanvas;
public TextMeshProUGUI messageText;
public DateTime lastMessageTime;
public float hideTimer;
public bool isFading;
}
private float lastBossFindTime;
private const float BOSS_FIND_DELAY = 0.5f;
private readonly Random random = new Random();
private readonly Dictionary<string, BossData> userToBoss = new Dictionary<string, BossData>();
private Dictionary<Enemy, string> enemyToUser = new Dictionary<Enemy, string>();
private readonly HashSet<string> chattersSet = new HashSet<string>();
private string[] chattersBuffer;
private int currentIndex;
private int totalChatters;
private readonly object bufferLock = new object();
private float DialogSize => PluginConfig.BossesDialogSize.Value;
private int MaxChatters => PluginConfig.BossesMaxChatters.Value;
public void Update()
{
if (totalChatters > 0)
{
FindBosses();
}
UpdateBossesData();
}
public void Reset()
{
foreach (KeyValuePair<string, BossData> item in userToBoss)
{
Object.Destroy((Object)(object)item.Value.dialogCanvas);
}
userToBoss.Clear();
enemyToUser.Clear();
lock (bufferLock)
{
chattersSet.Clear();
chattersBuffer = new string[MaxChatters];
currentIndex = 0;
totalChatters = 0;
}
}
public void ProcessNewChatMessage(string username, string message)
{
AddChatter(username);
ProcessMessage(username, message);
}
private void AddChatter(string username)
{
lock (bufferLock)
{
if (!chattersSet.Contains(username) && !userToBoss.ContainsKey(username))
{
if (totalChatters >= MaxChatters)
{
string item = chattersBuffer[currentIndex];
chattersSet.Remove(item);
}
chattersBuffer[currentIndex] = username;
chattersSet.Add(username);
currentIndex = (currentIndex + 1) % MaxChatters;
if (totalChatters < MaxChatters)
{
totalChatters++;
}
}
}
}
private void ProcessMessage(string username, string message)
{
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Expected O, but got Unknown
if (userToBoss.TryGetValue(username, out var value))
{
((TMP_Text)value.messageText).text = message;
value.lastMessageTime = DateTime.Now;
value.hideTimer = 15f;
value.isFading = false;
((TMP_Text)value.messageText).alpha = 1f;
ManualLogSource log = Plugin.Log;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(21, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Showing dialog for ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(username);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(message);
}
log.LogInfo(val);
}
}
private void FindBosses()
{
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Expected O, but got Unknown
if (Time.time - lastBossFindTime < 0.5f)
{
return;
}
IEnumerable<TargetOfInterestPrefab> enumerable = ((IEnumerable<TargetOfInterestPrefab>)Object.FindObjectsOfType<TargetOfInterestPrefab>()).Where(delegate(TargetOfInterestPrefab t)
{
Enemy enemy = t.enemy;
return enemy != null && enemy.IsBoss() && !enemyToUser.ContainsKey(t.enemy);
});
lastBossFindTime = Time.time;
bool flag = default(bool);
foreach (TargetOfInterestPrefab item in enumerable)
{
string text = PopRandomChatter();
if (text == null)
{
break;
}
enemyToUser[item.enemy] = text;
userToBoss[text] = CreateBossData(item, text);
ManualLogSource log = Plugin.Log;
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(17, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Boss renamed to: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
}
log.LogInfo(val);
}
}
private void UpdateBossesData()
{
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
//IL_0153: Expected O, but got Unknown
//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
//IL_01da: Unknown result type (might be due to invalid IL or missing references)
//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
//IL_0205: Unknown result type (might be due to invalid IL or missing references)
//IL_020a: Unknown result type (might be due to invalid IL or missing references)
//IL_0217: Unknown result type (might be due to invalid IL or missing references)
//IL_02df: Unknown result type (might be due to invalid IL or missing references)
//IL_02e6: Expected O, but got Unknown
bool flag = default(bool);
foreach (KeyValuePair<string, BossData> item in userToBoss.ToList())
{
string username = item.Key;
BossData value = item.Value;
if ((Object)(object)value.target.enemy == (Object)null || value.target.enemy.hp <= 0f || value.target.enemy.IsDeadOrDyingNextFrame() || !value.target.enemy.IsBoss() || (Object)(object)value.enemyData != (Object)(object)value.target.enemy.enemyData)
{
Object.Destroy((Object)(object)value.dialogCanvas);
userToBoss.Remove(username);
chattersSet.Remove(username);
enemyToUser = enemyToUser.Where((KeyValuePair<Enemy, string> e) => e.Value != username).ToDictionary((KeyValuePair<Enemy, string> e) => e.Key, (KeyValuePair<Enemy, string> e) => e.Value);
AddChatter(username);
ManualLogSource log = Plugin.Log;
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(28, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Boss ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(username);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" removed (dead or null)");
}
log.LogInfo(val);
continue;
}
if (((TMP_Text)value.target.t_name).text != value.name)
{
((TMP_Text)value.target.t_name).text = value.name;
}
Vector3 position = value.target.enemy.statusSymbols.boss.transform.position;
value.dialogCanvas.transform.position = position;
if ((Object)(object)Camera.main != (Object)null)
{
Vector3 position2 = ((Component)Camera.main).transform.position;
value.dialogCanvas.transform.LookAt(position2);
value.dialogCanvas.transform.Rotate(0f, 180f, 0f);
}
if (!(value.hideTimer > 0f))
{
continue;
}
value.hideTimer -= Time.deltaTime;
if (value.hideTimer <= 2f && !value.isFading)
{
value.isFading = true;
}
if (value.isFading)
{
float num = value.hideTimer / 2f;
float alpha = Mathf.Lerp(0f, 1f, num);
((TMP_Text)value.messageText).alpha = alpha;
}
if (value.hideTimer <= 0f)
{
value.isFading = false;
((TMP_Text)value.messageText).alpha = 0f;
ManualLogSource log2 = Plugin.Log;
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(32, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Hidden dialog for ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(username);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" after timeout");
}
log2.LogInfo(val);
}
}
}
private string PopRandomChatter()
{
lock (bufferLock)
{
if (totalChatters == 0)
{
return null;
}
int num = random.Next(totalChatters);
string result = chattersBuffer[num];
if (totalChatters > 1)
{
chattersBuffer[num] = chattersBuffer[totalChatters - 1];
}
else
{
chattersBuffer[num] = null;
}
totalChatters--;
totalChatters = Mathf.Clamp(totalChatters, 0, MaxChatters);
currentIndex = totalChatters % MaxChatters;
return result;
}
}
private BossData CreateBossData(TargetOfInterestPrefab target, string username)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Expected O, but got Unknown
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
//IL_0110: Unknown result type (might be due to invalid IL or missing references)
//IL_0135: Unknown result type (might be due to invalid IL or missing references)
//IL_0174: Unknown result type (might be due to invalid IL or missing references)
//IL_017e: Unknown result type (might be due to invalid IL or missing references)
//IL_019a: Unknown result type (might be due to invalid IL or missing references)
//IL_01af: Unknown result type (might be due to invalid IL or missing references)
//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject("BossDialog_" + username);
Canvas obj = val.AddComponent<Canvas>();
obj.renderMode = (RenderMode)2;
obj.worldCamera = Camera.main;
CanvasScaler obj2 = val.AddComponent<CanvasScaler>();
obj2.uiScaleMode = (ScaleMode)1;
obj2.referenceResolution = new Vector2(1920f, 1080f);
val.GetComponent<RectTransform>().sizeDelta = new Vector2(DialogSize, 0f);
GameObject val2 = new GameObject("NicknameText");
val2.transform.SetParent(val.transform, false);
TextMeshProUGUI obj3 = val2.AddComponent<TextMeshProUGUI>();
((TMP_Text)obj3).text = username;
((TMP_Text)obj3).fontSize = DialogSize / 15f;
((Graphic)obj3).color = new Color(0.7f, 0.2f, 0.2f, 1f);
((TMP_Text)obj3).alignment = (TextAlignmentOptions)514;
((TMP_Text)obj3).margin = new Vector4(0f, 0f, 0f, 0f - (1f + DialogSize / 15f));
GameObject val3 = new GameObject("MessageText");
val3.transform.SetParent(val.transform, false);
TextMeshProUGUI val4 = val3.AddComponent<TextMeshProUGUI>();
((TMP_Text)val4).text = "";
((TMP_Text)val4).fontSize = DialogSize / 20f;
((Graphic)val4).color = Color.white;
((TMP_Text)val4).horizontalAlignment = (HorizontalAlignmentOptions)2;
((TMP_Text)val4).verticalAlignment = (VerticalAlignmentOptions)1024;
((TMP_Text)val4).enableWordWrapping = true;
((TMP_Text)val4).margin = new Vector4(0f, 0f, 0f, DialogSize / 20f);
val3.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
RectTransform component = val3.GetComponent<RectTransform>();
component.anchorMin = new Vector2(0f, 0f);
component.anchorMax = new Vector2(1f, 0f);
component.pivot = new Vector2(0.5f, 0f);
component.anchoredPosition = Vector2.zero;
component.sizeDelta = new Vector2(0f, 0f);
BossData obj4 = new BossData
{
target = target
};
Enemy enemy = target.enemy;
obj4.enemyData = ((enemy != null) ? enemy.enemyData : null);
obj4.name = username;
obj4.dialogCanvas = val;
obj4.messageText = val4;
obj4.lastMessageTime = DateTime.MinValue;
obj4.hideTimer = 0f;
obj4.isFading = false;
return obj4;
}
}
public class Nicknames
{
private class EnemyData
{
public Enemy enemy;
public string name;
public TextMeshProUGUI usernameText;
public GameObject canvas;
}
private float lastEnemyFindTime;
private const float ENEMY_FIND_DELAY = 0.25f;
private readonly Random random = new Random();
private string[] chattersBuffer;
private int currentIndex;
private int totalChatters;
private readonly object bufferLock = new object();
private readonly HashSet<EnemyData> enemiesSet = new HashSet<EnemyData>();
private float NicknameSize => PluginConfig.NicknamesSize.Value;
private int MaxChatters => PluginConfig.NicknamesMaxChatters.Value;
public void Update()
{
if (totalChatters > 0)
{
FindEnemies();
}
ClearDeadEnemies();
UpdatePositions();
}
public void Reset()
{
lock (bufferLock)
{
chattersBuffer = new string[MaxChatters];
currentIndex = 0;
totalChatters = 0;
}
foreach (EnemyData item in enemiesSet)
{
Object.Destroy((Object)(object)item.canvas);
}
enemiesSet.Clear();
}
public void AddChatter(string username, string _)
{
lock (bufferLock)
{
chattersBuffer[currentIndex] = username;
currentIndex = (currentIndex + 1) % MaxChatters;
if (totalChatters < MaxChatters)
{
totalChatters++;
}
}
}
private void FindEnemies()
{
if (Time.time - lastEnemyFindTime < 0.25f)
{
return;
}
Enemy[] array = ((IEnumerable<Enemy>)Object.FindObjectsOfType<Enemy>()).Where((Enemy e) => e.hp > 0f && !e.IsBoss()).ToArray();
lastEnemyFindTime = Time.time;
Enemy[] array2 = array;
foreach (Enemy enemy in array2)
{
if (!IsEnemyAlreadyTracked(enemy))
{
int num = random.Next(totalChatters);
string username = chattersBuffer[num];
EnemyData item = CreateEnemyData(enemy, username);
enemiesSet.Add(item);
}
}
}
private void ClearDeadEnemies()
{
List<EnemyData> list = new List<EnemyData>();
foreach (EnemyData item in enemiesSet)
{
if ((Object)(object)item.enemy == (Object)null || item.enemy.hp <= 0f || item.enemy.IsDeadOrDyingNextFrame())
{
Object.Destroy((Object)(object)item.canvas);
list.Add(item);
}
}
foreach (EnemyData item2 in list)
{
enemiesSet.Remove(item2);
}
}
private void UpdatePositions()
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_0098: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
foreach (EnemyData item in enemiesSet)
{
float num = Mathf.Lerp(((Graphic)item.usernameText).color.a, 0.5f, Time.deltaTime * 2f);
((Graphic)item.usernameText).color = new Color(1f, 1f, 1f, num);
Vector3 headPosition = item.enemy.GetHeadPosition();
item.canvas.transform.position = headPosition;
if ((Object)(object)Camera.main != (Object)null)
{
Vector3 position = ((Component)Camera.main).transform.position;
item.canvas.transform.LookAt(position);
item.canvas.transform.Rotate(0f, 180f, 0f);
}
}
}
private bool IsEnemyAlreadyTracked(Enemy enemy)
{
foreach (EnemyData item in enemiesSet)
{
if ((Object)(object)item.enemy == (Object)(object)enemy)
{
return true;
}
}
return false;
}
private EnemyData CreateEnemyData(Enemy enemy, string username)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Expected O, but got Unknown
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject("TwitchUsername");
Canvas obj = val.AddComponent<Canvas>();
obj.renderMode = (RenderMode)2;
obj.worldCamera = Camera.main;
CanvasScaler obj2 = val.AddComponent<CanvasScaler>();
obj2.uiScaleMode = (ScaleMode)1;
obj2.referenceResolution = new Vector2(1920f, 1080f);
val.GetComponent<RectTransform>().sizeDelta = new Vector2(NicknameSize, 0f);
GameObject val2 = new GameObject("MessageText");
val2.transform.SetParent(val.transform, false);
TextMeshProUGUI val3 = val2.AddComponent<TextMeshProUGUI>();
((TMP_Text)val3).text = username;
((TMP_Text)val3).fontSize = NicknameSize / 20f;
((Graphic)val3).color = new Color(1f, 1f, 1f, 0f);
((TMP_Text)val3).alignment = (TextAlignmentOptions)514;
return new EnemyData
{
enemy = enemy,
name = username,
usernameText = val3,
canvas = val
};
}
}
public class TwitchIntegrationBase : MonoBehaviour
{
private readonly Chat chat = new Chat();
private readonly Bosses bosses = new Bosses();
private readonly Nicknames nicknames = new Nicknames();
private string lastTwitchChannel = string.Empty;
public void Awake()
{
((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
Plugin.Log.LogInfo((object)"Awake called");
}
public void Start()
{
Plugin.Log.LogInfo((object)"Start called");
chat.RegisterMessageCallback(bosses.ProcessNewChatMessage);
chat.RegisterMessageCallback(nicknames.AddChatter);
}
public void Update()
{
if (lastTwitchChannel != PluginConfig.TwitchChannel.Value)
{
lastTwitchChannel = PluginConfig.TwitchChannel.Value;
chat.Reset();
bosses.Reset();
nicknames.Reset();
}
chat.Update();
if (PluginConfig.EnableBosses.Value)
{
bosses.Update();
}
if (PluginConfig.EnableNicknames.Value)
{
nicknames.Update();
}
}
public void OnDestroy()
{
chat?.DisconnectFromTwitch();
bosses?.Reset();
nicknames?.Reset();
}
}
public class Chat
{
private const string TWITCH_IRC_SERVER = "irc.chat.twitch.tv";
private const int TWITCH_IRC_PORT = 6667;
private Action<string, string>[] messageCallback = Array.Empty<Action<string, string>>();
private readonly Random random = new Random();
private TcpClient tcpClient;
private StreamReader inputStream;
private StreamWriter outputStream;
private Thread ircThread;
private volatile bool isConnected;
private DateTime lastConnectionAttempt = DateTime.MinValue;
private const int RECONNECT_DELAY_MS = 5000;
private string TwitchChannel => PluginConfig.TwitchChannel.Value;
public void Update()
{
if (!isConnected && (DateTime.Now - lastConnectionAttempt).TotalMilliseconds > 5000.0)
{
StartTwitchConnection();
}
}
public void Reset()
{
DisconnectFromTwitch();
}
public void RegisterMessageCallback(Action<string, string> callback)
{
List<Action<string, string>> list = messageCallback.ToList();
if (!list.Contains(callback))
{
list.Add(callback);
messageCallback = list.ToArray();
}
}
private void StartTwitchConnection()
{
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Expected O, but got Unknown
if (!string.IsNullOrEmpty(TwitchChannel))
{
lastConnectionAttempt = DateTime.Now;
if (ircThread == null || !ircThread.IsAlive)
{
ircThread = new Thread(ThreadStart.op_Implicit((Action)ConnectAndReadMessages));
ircThread.Start();
}
}
}
private void ConnectAndReadMessages()
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Expected O, but got Unknown
//IL_0135: Unknown result type (might be due to invalid IL or missing references)
//IL_013c: Expected O, but got Unknown
//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
//IL_00fe: Expected O, but got Unknown
//IL_0179: Unknown result type (might be due to invalid IL or missing references)
//IL_017f: Expected O, but got Unknown
bool flag = default(bool);
try
{
ManualLogSource log = Plugin.Log;
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(27, 0, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Connecting to Twitch IRC...");
}
log.LogInfo(val);
tcpClient = new TcpClient();
tcpClient.Connect("irc.chat.twitch.tv", 6667);
inputStream = new StreamReader(tcpClient.GetStream());
outputStream = new StreamWriter(tcpClient.GetStream());
string text = $"justinfan{random.Next(10000, 99999)}";
outputStream.WriteLine("NICK " + text);
outputStream.WriteLine("JOIN #" + TwitchChannel);
outputStream.Flush();
isConnected = true;
ManualLogSource log2 = Plugin.Log;
val = new BepInExInfoLogInterpolatedStringHandler(14, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Connected to #");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(TwitchChannel);
}
log2.LogInfo(val);
ReadIrcMessages();
}
catch (Exception ex)
{
ManualLogSource log3 = Plugin.Log;
BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(19, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Connection failed: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
}
log3.LogError(val2);
isConnected = false;
DisconnectFromTwitch();
ManualLogSource log4 = Plugin.Log;
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(23, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Retrying in ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(5);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" seconds...");
}
log4.LogInfo(val);
Thread.Sleep(5000);
}
}
private void ReadIrcMessages()
{
//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
//IL_0103: Expected O, but got Unknown
//IL_016b: Unknown result type (might be due to invalid IL or missing references)
//IL_0172: Expected O, but got Unknown
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Expected O, but got Unknown
bool flag = default(bool);
try
{
string text;
while (isConnected && tcpClient.Connected && (text = inputStream.ReadLine()) != null)
{
if (text.StartsWith("PING"))
{
string value = text.Replace("PING", "PONG");
outputStream.WriteLine(value);
outputStream.Flush();
}
else
{
if (!text.Contains("PRIVMSG"))
{
continue;
}
try
{
int num = text.IndexOf(':') + 1;
int num2 = text.IndexOf('!');
string text2 = text.Substring(num, num2 - num);
int startIndex = text.IndexOf("twitch.tv PRIVMSG");
int startIndex2 = text.IndexOf(':', startIndex) + 1;
string arg = text.Substring(startIndex2);
ManualLogSource log = Plugin.Log;
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(15, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Chatter found: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text2);
}
log.LogInfo(val);
Action<string, string>[] array = messageCallback;
for (int i = 0; i < array.Length; i++)
{
array[i](text2, arg);
}
}
catch (Exception ex)
{
ManualLogSource log2 = Plugin.Log;
BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(23, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Error parsing message: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
}
log2.LogError(val2);
}
}
}
}
catch (Exception ex2)
{
if (isConnected)
{
ManualLogSource log3 = Plugin.Log;
BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(28, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Error reading IRC messages: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex2.Message);
}
log3.LogError(val2);
}
}
finally
{
DisconnectFromTwitch();
}
}
public void DisconnectFromTwitch()
{
isConnected = false;
try
{
inputStream?.Dispose();
outputStream?.Dispose();
tcpClient?.Close();
}
catch (Exception)
{
}
finally
{
inputStream = null;
outputStream = null;
tcpClient = null;
}
}
}
public static class PluginConfig
{
public static ConfigEntry<string> TwitchChannel { get; private set; }
public static ConfigEntry<bool> EnableBosses { get; private set; }
public static ConfigEntry<float> BossesDialogSize { get; private set; }
public static ConfigEntry<int> BossesMaxChatters { get; private set; }
public static ConfigEntry<bool> EnableNicknames { get; private set; }
public static ConfigEntry<float> NicknamesSize { get; private set; }
public static ConfigEntry<int> NicknamesMaxChatters { get; private set; }
public static ConfigFile ConfigFile { get; private set; }
public static void Initialize(ConfigFile config)
{
TwitchChannel = config.Bind<string>("Base", "TwitchChannel", "flowseal", "The Twitch channel to connect to");
EnableBosses = config.Bind<bool>("Bosses", "EnableBosses", true, "Enable assigning random chatter to the boss");
BossesDialogSize = config.Bind<float>("Bosses", "TextSize", 28f, "Size of the boss text");
BossesMaxChatters = config.Bind<int>("Bosses", "MaxChatters", 1000, "Maximum number of last chatters buffer (overwrites oldest users when full)");
EnableNicknames = config.Bind<bool>("Nicknames", "EnableNicknames", true, "Enable showing random chatter nicknames above creeps");
NicknamesSize = config.Bind<float>("Nicknames", "NicknameSize", 12f, "Size of the nickname text for creeps");
NicknamesMaxChatters = config.Bind<int>("Nicknames", "MaxChatters", 1000, "Maximum number of last chatters buffer (overwrites oldest users when full)");
ConfigFile = config;
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "TwitchIntegration";
public const string PLUGIN_NAME = "MegaBonk Twitch Integration";
public const string PLUGIN_VERSION = "1.0.0";
}