using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net.WebSockets;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Bonelab;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.Warehouse;
using Il2CppSLZ.Utilities;
using Il2CppSystem;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using StreamlabsIntegration;
using UnityEngine;
using UnityEngine.Events;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(Core), "StreamlabsIntegration", "1.0.0", "notnotnotswipez", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("StreamlabsIntegration")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("StreamlabsIntegration")]
[assembly: AssemblyTitle("StreamlabsIntegration")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace StreamlabsIntegration
{
public class EmbeddedResourceHelper
{
public static byte[] GetResourceBytes(string filename)
{
Assembly executingAssembly = Assembly.GetExecutingAssembly();
string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
foreach (string text in manifestResourceNames)
{
if (!text.Contains(filename))
{
continue;
}
using Stream stream = executingAssembly.GetManifestResourceStream(text);
if (stream == null)
{
return null;
}
byte[] array = new byte[stream.Length];
stream.Read(array, 0, array.Length);
return array;
}
return null;
}
}
public static class AssetBundleExtension
{
public static T LoadPersistentAsset<T>(this AssetBundle bundle, string name) where T : Object
{
Object val = bundle.LoadAsset(name);
if (val != (Object)null)
{
val.hideFlags = (HideFlags)32;
return ((Il2CppObjectBase)val).TryCast<T>();
}
return default(T);
}
}
public class ClipboardEffectAssets
{
public static Material goldMaterial;
public static void LoadAssets(AssetBundle bundle)
{
goldMaterial = bundle.LoadPersistentAsset<Material>("assets/gold.mat");
}
}
public class ClipboardNotifier
{
public string donator;
public string monetaryDisplay;
public string message;
public float value;
private const string CLIPBOARD_BARCODE = "SLZ.BONELAB.Content.Spawnable.ClipboardLore";
private const string AURA_GLOW = "SLZ.BONELAB.Content.VFX.AuraGlow";
private const float clipBoardDistanceToHead = 1f;
public ClipboardNotifier(string donator, string monetaryDisplay, string message, float value)
{
this.donator = donator;
this.monetaryDisplay = monetaryDisplay;
this.message = message;
this.value = value;
}
public void SpawnClipboard()
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Expected O, but got Unknown
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Expected O, but got Unknown
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Expected O, but got Unknown
GameObjectCrate val = ((Il2CppObjectBase)AssetWarehouse.Instance._crateRegistry[new Barcode("SLZ.BONELAB.Content.Spawnable.ClipboardLore")]).TryCast<GameObjectCrate>();
GameObjectCrate auraGlowCrate = ((Il2CppObjectBase)AssetWarehouse.Instance._crateRegistry[new Barcode("SLZ.BONELAB.Content.VFX.AuraGlow")]).TryCast<GameObjectCrate>();
GameObject disabledParent = new GameObject("DISABLED_CONTAINER");
disabledParent.SetActive(false);
Action<GameObject> action = delegate(GameObject go)
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
Transform head = ((Rig)PlayerRefs.Instance.PlayerPhysicsRig).m_head;
Vector3 determinedPosition = head.position + head.forward * 1f;
Vector3 forward = head.position - determinedPosition;
GameObject spawnedClip = Object.Instantiate<GameObject>(go, determinedPosition, Quaternion.identity, disabledParent.transform);
Object.DestroyImmediate((Object)(object)spawnedClip.GetComponent<LoreClipboard>());
spawnedClip.transform.parent = null;
Object.DestroyImmediate((Object)(object)disabledParent);
Rigidbody component = spawnedClip.GetComponent<Rigidbody>();
component.isKinematic = true;
spawnedClip.transform.forward = forward;
spawnedClip.transform.Rotate(new Vector3(90f, 0f, 0f), (Space)1);
component.isKinematic = false;
FixedJoint val2 = spawnedClip.AddComponent<FixedJoint>();
((Joint)val2).breakForce = 900f;
((Joint)val2).breakTorque = 900f;
Action<GameObject> action2 = delegate(GameObject go)
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Expected O, but got Unknown
GameObject spawnedVFX = Object.Instantiate<GameObject>(go, determinedPosition, Quaternion.identity);
GenericOnJointBreak val3 = spawnedClip.AddComponent<GenericOnJointBreak>();
val3.JointBreakEvent = new UnityEvent();
val3.JointBreakEvent.AddListener(UnityAction.op_Implicit((Action)delegate
{
Object.Destroy((Object)(object)spawnedVFX);
}));
};
((CrateT<GameObject>)(object)auraGlowCrate).LoadAsset(Action<GameObject>.op_Implicit(action2));
TMP_Text component2 = ((Component)spawnedClip.transform.Find("Text/textTitle")).GetComponent<TMP_Text>();
TMP_Text component3 = ((Component)spawnedClip.transform.Find("Text/textBody")).GetComponent<TMP_Text>();
component2.text = donator + " (" + monetaryDisplay + ")";
component3.text = message;
OnClipboardAfterEffect(spawnedClip, component);
};
((CrateT<GameObject>)(object)val).LoadAsset(Action<GameObject>.op_Implicit(action));
}
public void OnClipboardAfterEffect(GameObject clipBoard, Rigidbody body)
{
if (!((double)value > 24.9))
{
return;
}
Transform val = clipBoard.transform.Find("Art");
foreach (MeshRenderer componentsInChild in ((Component)val).GetComponentsInChildren<MeshRenderer>())
{
((Renderer)componentsInChild).materials = Il2CppReferenceArray<Material>.op_Implicit((Material[])(object)new Material[2]
{
ClipboardEffectAssets.goldMaterial,
ClipboardEffectAssets.goldMaterial
});
}
body.mass = 30f;
}
}
public class Core : MelonMod
{
[HarmonyPatch(typeof(UIRig), "Awake")]
public class UIRigAwakePatch
{
public static void Postfix()
{
canDisplayClipboards = true;
}
}
[HarmonyPatch(typeof(LoadingScene), "Start")]
public class LoadingSceneStartPatch
{
public static void Postfix()
{
canDisplayClipboards = false;
}
}
private static string latestMessage = "";
private static ClientWebSocket cSocket;
public static Action<float, string, string> OnDonationEvent;
private static Dictionary<string, float> toUSDConversion = new Dictionary<string, float>
{
{ "USD", 1f },
{ "AUD", 0.63f },
{ "BRL", 0.174f },
{ "CAD", 0.7f },
{ "CZK", 0.043f },
{ "DKK", 0.14f },
{ "EUR", 1.07f },
{ "HKD", 0.13f },
{ "ILS", 0.27f },
{ "MYR", 0.22f },
{ "MXN", 0.049f },
{ "NOK", 0.095f },
{ "NZD", 0.57f },
{ "PHP", 0.017f },
{ "PLN", 0.26f },
{ "GBP", 1.29f },
{ "RUB", 0.012f },
{ "SGD", 0.75f },
{ "SEK", 0.099f },
{ "CHF", 1.13f },
{ "THB", 0.029f },
{ "TRY", 0.026f }
};
public static bool canDisplayClipboards = false;
private Queue<ClipboardNotifier> queuedClipboards = new Queue<ClipboardNotifier>();
private MelonPreferences_Entry<float> minimumClipboardDonation;
public override void OnInitializeMelon()
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Invalid comparison between Unknown and I4
if ((int)MelonUtils.CurrentPlatform == 3)
{
MelonLogger.Error("StreamlabsIntegration not supported on Quest!");
return;
}
MelonPreferences_Category val = MelonPreferences.CreateCategory("StreamlabsIntegration");
MelonPreferences_Entry<string> val2 = val.CreateEntry<string>("socketToken", "none", (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
minimumClipboardDonation = val.CreateEntry<float>("minimumClipboardDonation", 4.8f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
string value = val2.Value;
val.SaveToFile(false);
if (!(value == "none"))
{
ClipboardEffectAssets.LoadAssets(AssetBundle.LoadFromMemory(Il2CppStructArray<byte>.op_Implicit(EmbeddedResourceHelper.GetResourceBytes("streamlabs.assets"))));
string uriString = "wss://sockets.streamlabs.com/socket.io/?token=" + value + "&EIO=3&transport=websocket";
((MelonBase)this).LoggerInstance.Msg("CONNECTING TO STREAMLABS SOCKET...");
cSocket = new ClientWebSocket();
Task task = cSocket.ConnectAsync(new Uri(uriString), CancellationToken.None);
while (!task.GetAwaiter().IsCompleted)
{
}
if (cSocket.State == WebSocketState.Open)
{
((MelonBase)this).LoggerInstance.Msg("Connected to StreamLabs.");
RunSocketThread();
}
else
{
((MelonBase)this).LoggerInstance.Msg("Failed to connect to StreamLabs.");
}
}
}
public override void OnUpdate()
{
if (canDisplayClipboards && queuedClipboards.Count > 0)
{
ClipboardNotifier clipboardNotifier = queuedClipboards.Dequeue();
clipboardNotifier.SpawnClipboard();
}
if (latestMessage.Length <= 0)
{
return;
}
try
{
if (latestMessage.Contains("streamlabels.underlying"))
{
latestMessage = "";
return;
}
dynamic val = JsonConvert.DeserializeObject<object>(latestMessage);
dynamic val2 = val[1];
string text = val2["type"];
string text2 = "";
float num = 0f;
string text3 = "";
string monetaryDisplay = "";
string text4 = "";
bool flag = true;
switch (text)
{
case "superchat":
{
dynamic val3 = val2["message"][0];
text2 = val3["amount"];
num = float.Parse(text2) / 1000000f;
text3 = val3["name"];
monetaryDisplay = val3["displayString"];
text4 = val3["comment"];
string key = val3["currency"];
if (toUSDConversion.ContainsKey(key))
{
num *= toUSDConversion[key];
}
else
{
flag = false;
}
break;
}
case "bits":
{
dynamic val3 = val2["message"][0];
text2 = val3["amount"];
num = float.Parse(text2) / 100f;
text3 = val3["name"];
monetaryDisplay = text2 + " Bits";
text4 = val3["message"];
break;
}
case "subscription":
{
dynamic val3 = val2["message"][0];
string text5 = val2["for"];
text2 = val3["months"];
num = 5f;
text3 = val3["name"];
monetaryDisplay = text2 + " Month Sub!";
if (text5 == "twitch_account")
{
text4 = val3["message"];
}
else if (text5 == "youtube_account")
{
text4 = "From YouTube!";
monetaryDisplay = text2 + " Month Member!";
}
break;
}
default:
flag = false;
break;
}
if (flag && (double)num > 0.5 && text != "subscription")
{
OnDonationEvent?.Invoke(num, text3, text4);
}
if (flag && num > minimumClipboardDonation.Value)
{
queuedClipboards.Enqueue(new ClipboardNotifier(text3, monetaryDisplay, text4, num));
}
}
catch (Exception ex)
{
((MelonBase)this).LoggerInstance.Msg(latestMessage);
MelonLogger.Error("Error when parsing streamlabs event: " + ex);
}
latestMessage = "";
}
public void RunSocketThread()
{
Thread thread = new Thread((ThreadStart)delegate
{
byte[] array = new byte[4096];
while (cSocket.State == WebSocketState.Open)
{
Task<WebSocketReceiveResult> task = cSocket.ReceiveAsync(new ArraySegment<byte>(array), CancellationToken.None);
while (!task.GetAwaiter().IsCompleted)
{
}
string @string = Encoding.UTF8.GetString(array, 0, task.Result.Count);
if (@string.StartsWith("42"))
{
latestMessage = @string.Substring(2);
}
}
});
Thread thread2 = new Thread((ThreadStart)delegate
{
while (cSocket.State == WebSocketState.Open)
{
cSocket.SendAsync(Encoding.UTF8.GetBytes("2"), WebSocketMessageType.Text, endOfMessage: true, CancellationToken.None);
Thread.Sleep(3000);
}
});
thread.Start();
thread2.Start();
}
}
}