using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using Mirror;
using Rewired;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Rendering;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("BigWalkSprays")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("TF2-style sprays for Big Walk")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("BigWalkSprays")]
[assembly: AssemblyTitle("BigWalkSprays")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[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 BigWalkSprays
{
internal static class ImageDecoders
{
public static bool IsPng(byte[] d)
{
return d != null && d.Length > 8 && d[0] == 137 && d[1] == 80 && d[2] == 78 && d[3] == 71;
}
public static bool IsJpeg(byte[] d)
{
return d != null && d.Length > 3 && d[0] == byte.MaxValue && d[1] == 216 && d[2] == byte.MaxValue;
}
private static bool IsGif(byte[] d)
{
return d != null && d.Length > 13 && d[0] == 71 && d[1] == 73 && d[2] == 70 && d[3] == 56;
}
private static bool IsBmp(byte[] d)
{
return d != null && d.Length > 54 && d[0] == 66 && d[1] == 77;
}
public static bool TryDecode(byte[] d, int maxDim, out int w, out int h, out Color32[] px, out string err)
{
w = (h = 0);
px = null;
err = null;
try
{
if (IsPng(d))
{
return PngCodec.TryDecode(d, maxDim, out w, out h, out px, out err);
}
if (IsGif(d))
{
return DecodeGif(d, maxDim, out w, out h, out px, out err);
}
if (IsBmp(d))
{
return DecodeBmp(d, maxDim, out w, out h, out px, out err);
}
err = "unsupported format (supported: png, jpg, gif, bmp)";
return false;
}
catch (Exception ex)
{
err = ex.Message;
px = null;
return false;
}
}
private static bool DecodeGif(byte[] d, int maxDim, out int width, out int height, out Color32[] pixels, out string err)
{
//IL_03f4: Unknown result type (might be due to invalid IL or missing references)
//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
width = (height = 0);
pixels = null;
err = null;
int num = d[6] | (d[7] << 8);
int num2 = d[8] | (d[9] << 8);
if (num < 1 || num2 < 1 || num > maxDim || num2 > maxDim)
{
err = "bad GIF dimensions";
return false;
}
int num3 = d[10];
int i = 13;
byte[] array = null;
if ((num3 & 0x80) != 0)
{
int num4 = 3 << (num3 & 7) + 1;
if (i + num4 > d.Length)
{
err = "truncated GIF";
return false;
}
array = new byte[num4];
Buffer.BlockCopy(d, i, array, 0, num4);
i += num4;
}
int num5 = -1;
Color32[] array2 = (Color32[])(object)new Color32[num * num2];
while (i < d.Length)
{
switch (d[i++])
{
case 33:
{
if (i >= d.Length)
{
break;
}
int num18 = d[i++];
if (num18 == 249 && i + 5 < d.Length)
{
num5 = (((d[i + 1] & 1) != 0) ? d[i + 4] : (-1));
}
int num19;
for (; i < d.Length; i += num19)
{
num19 = d[i++];
if (num19 == 0)
{
break;
}
}
continue;
}
case 44:
{
if (i + 9 > d.Length)
{
break;
}
int num6 = d[i] | (d[i + 1] << 8);
int num7 = d[i + 2] | (d[i + 3] << 8);
int num8 = d[i + 4] | (d[i + 5] << 8);
int num9 = d[i + 6] | (d[i + 7] << 8);
int num10 = d[i + 8];
i += 9;
if (num8 < 1 || num9 < 1 || (long)num8 * (long)num9 > 16777216)
{
err = "bad GIF frame size";
return false;
}
byte[] array3 = array;
if ((num10 & 0x80) != 0)
{
int num11 = 3 << (num10 & 7) + 1;
if (i + num11 > d.Length)
{
err = "truncated GIF";
return false;
}
array3 = new byte[num11];
Buffer.BlockCopy(d, i, array3, 0, num11);
i += num11;
}
if (array3 == null)
{
err = "GIF has no color table";
return false;
}
bool flag = (num10 & 0x40) != 0;
if (i >= d.Length)
{
err = "truncated GIF";
return false;
}
int num12 = d[i++];
if (num12 < 2 || num12 > 8)
{
err = "bad GIF LZW size";
return false;
}
MemoryStream memoryStream = new MemoryStream();
int num13;
for (; i < d.Length; i += num13)
{
num13 = d[i++];
if (num13 == 0)
{
break;
}
if (i + num13 > d.Length)
{
num13 = d.Length - i;
}
memoryStream.Write(d, i, num13);
}
byte[] array4 = LzwDecode(memoryStream.ToArray(), num12, num8 * num9);
for (int j = 0; j < num9; j++)
{
int num14 = (flag ? InterlacedRow(j, num9) : j);
int num15 = num7 + num14;
if (num15 >= num2)
{
continue;
}
for (int k = 0; k < num8; k++)
{
int num16 = num6 + k;
if (num16 < num)
{
int num17 = array4[j * num8 + k];
if (num17 != num5 && num17 * 3 + 2 < array3.Length)
{
array2[(num2 - 1 - num15) * num + num16] = new Color32(array3[num17 * 3], array3[num17 * 3 + 1], array3[num17 * 3 + 2], byte.MaxValue);
}
}
}
}
width = num;
height = num2;
pixels = array2;
return true;
}
}
break;
}
err = "GIF contains no image";
return false;
}
private static int InterlacedRow(int r, int h)
{
int num = (h + 7) / 8;
int num2 = (h + 3) / 8;
int num3 = (h + 1) / 4;
if (r < num)
{
return r * 8;
}
r -= num;
if (r < num2)
{
return 4 + r * 8;
}
r -= num2;
if (r < num3)
{
return 2 + r * 4;
}
r -= num3;
return 1 + r * 2;
}
private static byte[] LzwDecode(byte[] data, int minCode, int pixelCount)
{
int num = 1 << minCode;
int num2 = num + 1;
int num3 = num2 + 1;
int num4 = minCode + 1;
int num5 = (1 << num4) - 1;
short[] array = new short[4096];
byte[] array2 = new byte[4096];
byte[] array3 = new byte[4097];
for (int i = 0; i < num; i++)
{
array2[i] = (byte)i;
}
byte[] array4 = new byte[pixelCount];
int num6 = 0;
int num7 = 0;
int j = 0;
int num8 = 0;
int num9 = -1;
byte b = 0;
while (num6 < pixelCount)
{
for (; j < num4; j += 8)
{
if (num8 >= data.Length)
{
return array4;
}
num7 |= data[num8++] << j;
}
int num10 = num7 & num5;
num7 >>= num4;
j -= num4;
if (num10 == num)
{
num4 = minCode + 1;
num5 = (1 << num4) - 1;
num3 = num2 + 1;
num9 = -1;
continue;
}
if (num10 == num2)
{
break;
}
if (num9 == -1)
{
if (num10 >= num)
{
break;
}
array4[num6++] = array2[num10];
num9 = num10;
b = array2[num10];
continue;
}
int num11 = num10;
int num12 = 0;
if (num10 >= num3)
{
if (num10 > num3)
{
break;
}
array3[num12++] = b;
num10 = num9;
}
while (num10 >= num)
{
if (num12 >= 4096)
{
return array4;
}
array3[num12++] = array2[num10];
num10 = array[num10];
}
b = array2[num10];
array3[num12++] = b;
while (num12 > 0 && num6 < pixelCount)
{
array4[num6++] = array3[--num12];
}
if (num3 < 4096)
{
array[num3] = (short)num9;
array2[num3] = b;
num3++;
if ((num3 & num5) == 0 && num4 < 12)
{
num4++;
num5 = (1 << num4) - 1;
}
}
num9 = num11;
}
return array4;
}
private static int I32(byte[] d, int p)
{
return d[p] | (d[p + 1] << 8) | (d[p + 2] << 16) | (d[p + 3] << 24);
}
private static bool DecodeBmp(byte[] d, int maxDim, out int width, out int height, out Color32[] pixels, out string err)
{
//IL_0329: Unknown result type (might be due to invalid IL or missing references)
//IL_032e: Unknown result type (might be due to invalid IL or missing references)
//IL_0334: Unknown result type (might be due to invalid IL or missing references)
//IL_033b: Unknown result type (might be due to invalid IL or missing references)
//IL_0342: Unknown result type (might be due to invalid IL or missing references)
//IL_034e: Unknown result type (might be due to invalid IL or missing references)
//IL_0353: Unknown result type (might be due to invalid IL or missing references)
//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
//IL_02db: Unknown result type (might be due to invalid IL or missing references)
width = (height = 0);
pixels = null;
err = null;
int num = I32(d, 10);
int num2 = I32(d, 14);
if (num2 < 40)
{
err = "unsupported BMP header";
return false;
}
int num3 = I32(d, 18);
int num4 = I32(d, 22);
int num5 = d[28] | (d[29] << 8);
int num6 = I32(d, 30);
int num7 = I32(d, 46);
bool flag = num4 < 0;
int num8 = Math.Abs(num4);
if (num3 < 1 || num8 < 1 || num3 > maxDim || num8 > maxDim)
{
err = "bad BMP dimensions";
return false;
}
if (num6 != 0 && (num6 != 3 || num5 != 32))
{
err = "compressed BMP unsupported";
return false;
}
if (num5 != 8 && num5 != 24 && num5 != 32)
{
err = "BMP bit depth " + num5 + " unsupported (use 8/24/32)";
return false;
}
byte[] array = null;
if (num5 == 8)
{
int num9 = ((num7 > 0) ? num7 : 256);
int num10 = 14 + num2;
if (num10 + num9 * 4 > d.Length)
{
err = "truncated BMP palette";
return false;
}
array = new byte[num9 * 4];
Buffer.BlockCopy(d, num10, array, 0, num9 * 4);
}
long num11 = ((long)num3 * (long)num5 + 31) / 32 * 4;
if (num < 0 || num + num11 * num8 > d.Length)
{
err = "truncated BMP data";
return false;
}
Color32[] array2 = (Color32[])(object)new Color32[num3 * num8];
bool flag2 = false;
for (int i = 0; i < num8; i++)
{
int num12 = (int)(num + num11 * i);
int num13 = (flag ? (num8 - 1 - i) : i) * num3;
for (int j = 0; j < num3; j++)
{
byte b = byte.MaxValue;
byte b4;
byte b3;
byte b2;
switch (num5)
{
case 8:
{
int num15 = d[num12 + j];
if (num15 * 4 + 3 >= array.Length)
{
b4 = (b3 = (b2 = 0));
break;
}
b2 = array[num15 * 4];
b3 = array[num15 * 4 + 1];
b4 = array[num15 * 4 + 2];
break;
}
case 24:
{
int num16 = num12 + j * 3;
b2 = d[num16];
b3 = d[num16 + 1];
b4 = d[num16 + 2];
break;
}
default:
{
int num14 = num12 + j * 4;
b2 = d[num14];
b3 = d[num14 + 1];
b4 = d[num14 + 2];
b = d[num14 + 3];
if (b != 0)
{
flag2 = true;
}
break;
}
}
array2[num13 + j] = new Color32(b4, b3, b2, b);
}
}
if (num5 == 32 && !flag2)
{
for (int k = 0; k < array2.Length; k++)
{
Color32 val = array2[k];
array2[k] = new Color32(val.r, val.g, val.b, byte.MaxValue);
}
}
width = num3;
height = num8;
pixels = array2;
return true;
}
}
internal static class RewiredLock
{
private static bool locked;
private static bool broken;
public static void Set(bool lockInput)
{
if (broken || locked == lockInput)
{
return;
}
try
{
int playerCount = ReInput.players.playerCount;
for (int i = 0; i < playerCount; i++)
{
Player player = ReInput.players.GetPlayer(i);
if (player != null)
{
player.controllers.maps.SetAllMapsEnabled(!lockInput);
}
}
locked = lockInput;
}
catch (Exception ex)
{
broken = true;
((BasePlugin)Plugin.Instance).Log.LogWarning((object)("Rewired input lock failed (menu will not freeze movement): " + ex.Message));
}
}
}
[HarmonyPatch]
internal static class InputBlock
{
internal static bool Bypass;
private static bool Blocking => SprayManager.MenuOpen && !Bypass;
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
[HarmonyPrefix]
private static bool LockState(CursorLockMode value)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Invalid comparison between Unknown and I4
return !Blocking || (int)value == 0;
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
[HarmonyPrefix]
private static bool Visible(bool value)
{
return !Blocking || value;
}
}
public class MirrorNet : ISprayNet
{
private const ushort MsgId = 45466;
private const int MaxPacket = 65536;
public event Action<byte[]> OnReceive;
public void Tick()
{
if (NetworkClient.active && !NetworkClient.handlers.ContainsKey((ushort)45466))
{
NetworkClient.handlers[(ushort)45466] = DelegateSupport.ConvertDelegate<NetworkMessageDelegate>((Delegate)new Action<NetworkConnection, NetworkReader, int>(OnClientMessage));
}
if (NetworkServer.active && !NetworkServer.handlers.ContainsKey((ushort)45466))
{
NetworkServer.handlers[(ushort)45466] = DelegateSupport.ConvertDelegate<NetworkMessageDelegate>((Delegate)new Action<NetworkConnection, NetworkReader, int>(OnServerMessage));
}
}
public void Broadcast(byte[] payload)
{
if (payload != null && payload.Length <= 65536)
{
if (NetworkServer.active)
{
SendToAll(payload, 0);
}
else if (NetworkClient.active && NetworkClient.connection != null)
{
NetworkWriter val = Frame(payload);
NetworkClient.connection.Send(val.ToArraySegment(), Channels.Reliable);
}
}
}
private static byte[] ReadPayload(NetworkReader r)
{
int num = NetworkReaderExtensions.ReadInt(r);
if (num <= 0 || num > 65536 || num > r.Remaining)
{
return null;
}
Il2CppStructArray<byte> val = new Il2CppStructArray<byte>((long)num);
r.ReadBytes(val, num);
return Il2CppArrayBase<byte>.op_Implicit((Il2CppArrayBase<byte>)(object)val);
}
private void OnClientMessage(NetworkConnection conn, NetworkReader reader, int channelId)
{
byte[] array = ReadPayload(reader);
if (array != null)
{
this.OnReceive?.Invoke(array);
}
}
private void OnServerMessage(NetworkConnection conn, NetworkReader reader, int channelId)
{
byte[] array = ReadPayload(reader);
if (array != null)
{
SendToAll(array, conn.connectionId);
}
}
private static NetworkWriter Frame(byte[] payload)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Expected O, but got Unknown
NetworkWriter val = new NetworkWriter();
NetworkWriterExtensions.WriteUShort(val, (ushort)45466);
NetworkWriterExtensions.WriteInt(val, payload.Length);
val.WriteBytes(Il2CppStructArray<byte>.op_Implicit(payload), 0, payload.Length);
return val;
}
private static void SendToAll(byte[] payload, int exceptConnId)
{
NetworkWriter val = Frame(payload);
ArraySegment<byte> val2 = val.ToArraySegment();
Enumerator<int, NetworkConnectionToClient> enumerator = NetworkServer.connections.GetEnumerator();
while (enumerator.MoveNext())
{
KeyValuePair<int, NetworkConnectionToClient> current = enumerator.Current;
NetworkConnectionToClient value = current.Value;
if (value != null && ((NetworkConnection)value).connectionId != exceptConnId)
{
((NetworkConnection)value).Send(val2, Channels.Reliable);
}
}
}
}
internal static class PngCodec
{
private static readonly byte[] Sig = new byte[8] { 137, 80, 78, 71, 13, 10, 26, 10 };
private static uint[] crcTable;
public static bool TryDecode(byte[] data, int maxDim, out int width, out int height, out Color32[] pixels, out string error)
{
width = (height = 0);
pixels = null;
error = null;
try
{
return DecodeInner(data, maxDim, out width, out height, out pixels, out error);
}
catch (Exception ex)
{
error = ex.Message;
pixels = null;
return false;
}
}
private static bool Fail(out string error, string msg)
{
error = msg;
return false;
}
private static bool DecodeInner(byte[] data, int maxDim, out int width, out int height, out Color32[] pixels, out string error)
{
//IL_07df: Unknown result type (might be due to invalid IL or missing references)
//IL_07e4: Unknown result type (might be due to invalid IL or missing references)
width = (height = 0);
pixels = null;
error = null;
if (data == null || data.Length < 33)
{
return Fail(out error, "too short");
}
for (int i = 0; i < 8; i++)
{
if (data[i] != Sig[i])
{
return Fail(out error, "not a PNG");
}
}
int num = 0;
int num2 = 0;
int num3 = 0;
int num4 = 0;
int num5 = 0;
bool flag = false;
bool flag2 = false;
byte[] array = null;
byte[] array2 = null;
MemoryStream memoryStream = new MemoryStream();
int num6 = 8;
while (!flag2 && num6 + 12 <= data.Length)
{
int num7 = ReadInt(data, num6);
string text = Encoding.ASCII.GetString(data, num6 + 4, 4);
int num8 = num6 + 8;
if (num7 < 0 || (long)num8 + (long)num7 + 4 > data.Length)
{
return Fail(out error, "truncated chunk");
}
switch (text)
{
case "IHDR":
if (num7 < 13)
{
return Fail(out error, "bad IHDR");
}
num = ReadInt(data, num8);
num2 = ReadInt(data, num8 + 4);
num3 = data[num8 + 8];
num4 = data[num8 + 9];
num5 = data[num8 + 12];
flag = true;
break;
case "PLTE":
array = new byte[num7];
Buffer.BlockCopy(data, num8, array, 0, num7);
break;
case "tRNS":
array2 = new byte[num7];
Buffer.BlockCopy(data, num8, array2, 0, num7);
break;
case "IDAT":
memoryStream.Write(data, num8, num7);
break;
case "IEND":
flag2 = true;
break;
}
num6 = num8 + num7 + 4;
}
if (!flag)
{
return Fail(out error, "no IHDR");
}
if (num < 1 || num2 < 1 || num > maxDim || num2 > maxDim)
{
return Fail(out error, "bad or too large dimensions " + num + "x" + num2);
}
if (num5 != 0)
{
return Fail(out error, "interlaced PNGs unsupported (re-save without interlacing)");
}
int num9;
switch (num4)
{
case 0:
num9 = 1;
if (num3 != 1 && num3 != 2 && num3 != 4 && num3 != 8 && num3 != 16)
{
return Fail(out error, "bad depth");
}
break;
case 2:
num9 = 3;
if (num3 != 8 && num3 != 16)
{
return Fail(out error, "bad depth");
}
break;
case 3:
num9 = 1;
if (num3 != 1 && num3 != 2 && num3 != 4 && num3 != 8)
{
return Fail(out error, "bad depth");
}
if (array == null)
{
return Fail(out error, "missing palette");
}
break;
case 4:
num9 = 2;
if (num3 != 8 && num3 != 16)
{
return Fail(out error, "bad depth");
}
break;
case 6:
num9 = 4;
if (num3 != 8 && num3 != 16)
{
return Fail(out error, "bad depth");
}
break;
default:
return Fail(out error, "bad color type");
}
int num10 = num9 * num3;
int num11 = Math.Max(1, num10 / 8);
int num12 = (int)(((long)num * (long)num10 + 7) / 8);
long num13 = (long)(num12 + 1) * (long)num2;
if (num13 > 67108864)
{
return Fail(out error, "image too large");
}
byte[] array3 = new byte[num13];
memoryStream.Position = 0L;
using (ZLibStream zLibStream = new ZLibStream(memoryStream, CompressionMode.Decompress))
{
long num14;
int num15;
for (num14 = 0L; num14 < num13; num14 += num15)
{
num15 = zLibStream.Read(array3, (int)num14, (int)(num13 - num14));
if (num15 <= 0)
{
break;
}
}
if (num14 < num13)
{
return Fail(out error, "truncated image data");
}
}
int num16 = num12 + 1;
for (int j = 0; j < num2; j++)
{
int num17 = j * num16;
int num18 = array3[num17];
int num19 = num17 + 1;
int num20 = ((j > 0) ? (num19 - num16) : (-1));
for (int k = 0; k < num12; k++)
{
int num21 = ((k >= num11) ? array3[num19 + k - num11] : 0);
int num22 = ((num20 >= 0) ? array3[num20 + k] : 0);
int c = ((k >= num11 && num20 >= 0) ? array3[num20 + k - num11] : 0);
int num23 = array3[num19 + k];
switch (num18)
{
case 1:
num23 += num21;
break;
case 2:
num23 += num22;
break;
case 3:
num23 += num21 + num22 >> 1;
break;
case 4:
num23 += Paeth(num21, num22, c);
break;
default:
return Fail(out error, "bad filter type");
case 0:
break;
}
array3[num19 + k] = (byte)num23;
}
}
Color32[] array4 = (Color32[])(object)new Color32[num * num2];
int step = ((num3 >= 8) ? (num3 / 8) : 0);
int num24 = (1 << Math.Min(num3, 8)) - 1;
for (int l = 0; l < num2; l++)
{
int rowStart = l * num16 + 1;
int num25 = (num2 - 1 - l) * num;
for (int m = 0; m < num; m++)
{
byte b = byte.MaxValue;
byte b2;
byte b3;
byte b4;
switch (num4)
{
case 0:
{
int num27 = Sample(array3, rowStart, m, 0, 1, num3, step);
if (num3 < 8)
{
num27 = num27 * 255 / num24;
}
b2 = (b3 = (b4 = (byte)num27));
break;
}
case 2:
b2 = (byte)Sample(array3, rowStart, m, 0, 3, num3, step);
b3 = (byte)Sample(array3, rowStart, m, 1, 3, num3, step);
b4 = (byte)Sample(array3, rowStart, m, 2, 3, num3, step);
break;
case 3:
{
int num26 = Sample(array3, rowStart, m, 0, 1, num3, step);
if (num26 * 3 + 2 >= array.Length)
{
b2 = (b3 = (b4 = 0));
}
else
{
b2 = array[num26 * 3];
b3 = array[num26 * 3 + 1];
b4 = array[num26 * 3 + 2];
}
if (array2 != null && num26 < array2.Length)
{
b = array2[num26];
}
break;
}
case 4:
b2 = (b3 = (b4 = (byte)Sample(array3, rowStart, m, 0, 2, num3, step)));
b = (byte)Sample(array3, rowStart, m, 1, 2, num3, step);
break;
default:
b2 = (byte)Sample(array3, rowStart, m, 0, 4, num3, step);
b3 = (byte)Sample(array3, rowStart, m, 1, 4, num3, step);
b4 = (byte)Sample(array3, rowStart, m, 2, 4, num3, step);
b = (byte)Sample(array3, rowStart, m, 3, 4, num3, step);
break;
}
array4[num25 + m] = new Color32(b2, b3, b4, b);
}
}
width = num;
height = num2;
pixels = array4;
return true;
}
private static int Sample(byte[] raw, int rowStart, int x, int k, int channels, int depth, int step)
{
if (depth < 8)
{
int num = x * depth;
int num2 = 8 - depth - (num & 7);
return (raw[rowStart + (num >> 3)] >> num2) & ((1 << depth) - 1);
}
return raw[rowStart + (x * channels + k) * step];
}
private static int Paeth(int a, int b, int c)
{
int num = a + b - c;
int num2 = Math.Abs(num - a);
int num3 = Math.Abs(num - b);
int num4 = Math.Abs(num - c);
if (num2 <= num3 && num2 <= num4)
{
return a;
}
return (num3 <= num4) ? b : c;
}
private static int ReadInt(byte[] d, int p)
{
return (d[p] << 24) | (d[p + 1] << 16) | (d[p + 2] << 8) | d[p + 3];
}
public static Color32[] Resize(Color32[] src, int sw, int sh, int dw, int dh)
{
//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
if (sw == dw && sh == dh)
{
return src;
}
Color32[] array = (Color32[])(object)new Color32[dw * dh];
for (int i = 0; i < dh; i++)
{
int num = (int)((long)i * (long)sh / dh);
int num2 = Math.Max(num + 1, (int)((long)(i + 1) * (long)sh / dh));
for (int j = 0; j < dw; j++)
{
int num3 = (int)((long)j * (long)sw / dw);
int num4 = Math.Max(num3 + 1, (int)((long)(j + 1) * (long)sw / dw));
double num5 = 0.0;
double num6 = 0.0;
double num7 = 0.0;
double num8 = 0.0;
int num9 = 0;
for (int k = num; k < num2 && k < sh; k++)
{
for (int l = num3; l < num4 && l < sw; l++)
{
Color32 val = src[k * sw + l];
double num10 = (int)val.a;
num5 += (double)(int)val.r * num10;
num6 += (double)(int)val.g * num10;
num7 += (double)(int)val.b * num10;
num8 += num10;
num9++;
}
}
if (num8 > 0.0 && num9 > 0)
{
array[i * dw + j] = new Color32((byte)(num5 / num8 + 0.5), (byte)(num6 / num8 + 0.5), (byte)(num7 / num8 + 0.5), (byte)(num8 / (double)num9 + 0.5));
}
else
{
array[i * dw + j] = new Color32((byte)0, (byte)0, (byte)0, (byte)0);
}
}
}
return array;
}
public static byte[] Encode(int w, int h, Color32[] px)
{
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
int num = w * 4;
byte[] array = new byte[(num + 1) * h];
for (int i = 0; i < h; i++)
{
int num2 = (h - 1 - i) * w;
int num3 = i * (num + 1);
array[num3] = 1;
for (int j = 0; j < w; j++)
{
Color32 val = px[num2 + j];
int num4 = num3 + 1 + j * 4;
array[num4] = val.r;
array[num4 + 1] = val.g;
array[num4 + 2] = val.b;
array[num4 + 3] = val.a;
}
for (int num5 = num - 1; num5 >= 4; num5--)
{
array[num3 + 1 + num5] = (byte)(array[num3 + 1 + num5] - array[num3 + 1 + num5 - 4]);
}
}
byte[] data;
using (MemoryStream memoryStream = new MemoryStream())
{
using (ZLibStream zLibStream = new ZLibStream(memoryStream, CompressionLevel.Optimal, leaveOpen: true))
{
zLibStream.Write(array, 0, array.Length);
}
data = memoryStream.ToArray();
}
using MemoryStream memoryStream2 = new MemoryStream();
memoryStream2.Write(Sig, 0, 8);
byte[] array2 = new byte[13];
WriteInt(array2, 0, w);
WriteInt(array2, 4, h);
array2[8] = 8;
array2[9] = 6;
array2[10] = 0;
array2[11] = 0;
array2[12] = 0;
WriteChunk(memoryStream2, "IHDR", array2);
WriteChunk(memoryStream2, "IDAT", data);
WriteChunk(memoryStream2, "IEND", new byte[0]);
return memoryStream2.ToArray();
}
private static void WriteInt(byte[] d, int p, int v)
{
d[p] = (byte)(v >> 24);
d[p + 1] = (byte)(v >> 16);
d[p + 2] = (byte)(v >> 8);
d[p + 3] = (byte)v;
}
private static void WriteChunk(Stream s, string type, byte[] data)
{
byte[] array = new byte[4];
WriteInt(array, 0, data.Length);
s.Write(array, 0, 4);
byte[] bytes = Encoding.ASCII.GetBytes(type);
s.Write(bytes, 0, 4);
s.Write(data, 0, data.Length);
uint v = Crc(Crc(uint.MaxValue, bytes), data) ^ 0xFFFFFFFFu;
byte[] array2 = new byte[4];
WriteInt(array2, 0, (int)v);
s.Write(array2, 0, 4);
}
private static uint Crc(uint c, byte[] buf)
{
if (crcTable == null)
{
uint[] array = new uint[256];
for (uint num = 0u; num < 256; num++)
{
uint num2 = num;
for (int i = 0; i < 8; i++)
{
num2 = (((num2 & 1) != 0) ? (0xEDB88320u ^ (num2 >> 1)) : (num2 >> 1));
}
array[num] = num2;
}
crcTable = array;
}
foreach (byte b in buf)
{
c = crcTable[(c ^ b) & 0xFF] ^ (c >> 8);
}
return c;
}
}
[BepInPlugin("com.gogogadgetjustice.bigwalk.sprays", "Big Walk Sprays", "0.2.0")]
public class Plugin : BasePlugin
{
internal static Plugin Instance;
internal static ConfigEntry<float> Lifetime;
internal static ConfigEntry<float> SprayWorldSize;
internal static ConfigEntry<float> MaxRange;
internal static ConfigEntry<float> Cooldown;
internal static ConfigEntry<float> Volume;
internal static ConfigEntry<KeyCode> MenuKey;
internal static ConfigEntry<KeyCode> SprayKey;
internal static ConfigEntry<KeyCode> DeleteLastKey;
internal static ConfigEntry<KeyCode> DeleteAllKey;
internal static ConfigEntry<int> MaxPerPlayer;
internal static ConfigEntry<string> SelectedSound;
internal static string SprayDir;
internal static string SoundDir;
public override void Load()
{
//IL_0201: Unknown result type (might be due to invalid IL or missing references)
Instance = this;
Lifetime = ((BasePlugin)this).Config.Bind<float>("Sprays", "SprayLifetimeSeconds", 0f, "How long sprays stay up on YOUR screen, in seconds. 0 = never expire.");
MaxPerPlayer = ((BasePlugin)this).Config.Bind<int>("Sprays", "MaxSpraysPerPlayer", 10, "Max sprays shown per player (oldest is removed first). 0 = unlimited.");
SprayWorldSize = ((BasePlugin)this).Config.Bind<float>("Sprays", "WorldSize", 1f, "Spray width/height in metres.");
MaxRange = ((BasePlugin)this).Config.Bind<float>("Sprays", "MaxRange", 4f, "Max distance to a wall you can spray.");
Cooldown = ((BasePlugin)this).Config.Bind<float>("Sprays", "CooldownSeconds", 3f, "Min time between your sprays.");
Volume = ((BasePlugin)this).Config.Bind<float>("Sounds", "Volume", 1f, "Spray sound volume (0-1).");
MenuKey = ((BasePlugin)this).Config.Bind<KeyCode>("Input", "MenuKey", (KeyCode)284, "Opens the spray/sound picker.");
SprayKey = ((BasePlugin)this).Config.Bind<KeyCode>("Input", "SprayKey", (KeyCode)102, "Sprays the selected image.");
DeleteLastKey = ((BasePlugin)this).Config.Bind<KeyCode>("Input", "DeleteLastKey", (KeyCode)99, "Removes your most recent spray (for everyone); repeat to go further back.");
DeleteAllKey = ((BasePlugin)this).Config.Bind<KeyCode>("Input", "DeleteAllKey", (KeyCode)118, "Clears every spray from your own screen (local only).");
string text = null;
try
{
text = Path.GetDirectoryName(typeof(Plugin).Assembly.Location);
}
catch
{
}
if (string.IsNullOrEmpty(text))
{
text = Path.Combine(Paths.PluginPath, "BigWalkSprays");
}
SprayDir = Path.Combine(text, "sprays");
SoundDir = Path.Combine(text, "spraysounds");
Directory.CreateDirectory(SprayDir);
Directory.CreateDirectory(SoundDir);
SelectedSound = ((BasePlugin)this).Config.Bind<string>("Sounds", "SelectedSound", "", "File name in spraysounds (blank = default spray.ogg).");
new Harmony("com.you.bigwalk.sprays").PatchAll(typeof(InputBlock));
ClassInjector.RegisterTypeInIl2Cpp<SprayManager>();
((BasePlugin)this).AddComponent<SprayManager>();
((BasePlugin)this).Log.LogInfo((object)("Sprays loaded. Images: " + SprayDir + " | Sounds: " + SoundDir));
}
}
public interface ISprayNet
{
event Action<byte[]> OnReceive;
void Broadcast(byte[] payload);
void Tick();
}
public class NullNet : ISprayNet
{
public event Action<byte[]> OnReceive;
public void Tick()
{
}
public void Broadcast(byte[] payload)
{
this.OnReceive?.Invoke(payload);
}
}
internal class ActiveSpray
{
public GameObject Go;
public float Expires;
public int Owner;
public int Seq;
}
internal class PendingSpray
{
public Vector3 Pos;
public Vector3 Normal;
public Vector3 Up;
public float Size;
public int Owner;
public int Seq;
public string Sound = "";
}
internal class Prepared
{
public string Path;
public DateTime Stamp;
public string Hash;
public byte[] Png;
public bool Ready;
public bool Failed;
}
public class SprayManager : MonoBehaviour
{
private const byte MsgSpray = 1;
private const byte MsgImage = 2;
private const byte MsgRequest = 3;
private const byte MsgDelete = 4;
private const int MaxImageBytes = 49152;
private const int MaxDim = 384;
private ISprayNet net;
private static bool menuOpen;
private readonly int myId = Guid.NewGuid().GetHashCode();
private int mySeq;
private float lastSpray;
private Vector2 scroll;
private int tab;
private string[] files = new string[0];
private string[] soundFiles = new string[0];
private string selectedSound = "";
private Prepared armed;
private readonly Dictionary<string, Prepared> prepared = new Dictionary<string, Prepared>();
private readonly Dictionary<string, Texture2D> textures = new Dictionary<string, Texture2D>();
private readonly Dictionary<string, byte[]> pngBytes = new Dictionary<string, byte[]>();
private readonly Dictionary<string, List<PendingSpray>> pending = new Dictionary<string, List<PendingSpray>>();
private readonly HashSet<string> sentHashes = new HashSet<string>();
private readonly List<ActiveSpray> active = new List<ActiveSpray>();
private Material baseMat;
private UnityWebRequest jpgReq;
private Prepared jpgTarget;
private GameObject soundHost;
private readonly Dictionary<string, AudioSource> holders = new Dictionary<string, AudioSource>();
private readonly Dictionary<string, UnityWebRequest> clipReqs = new Dictionary<string, UnityWebRequest>();
private string hudMsg;
private float hudUntil;
private static readonly string[] ImageExts = new string[5] { ".png", ".jpg", ".jpeg", ".gif", ".bmp" };
internal static bool MenuOpen => menuOpen;
public SprayManager(IntPtr ptr)
: base(ptr)
{
}
private void Start()
{
net = new MirrorNet();
net.OnReceive += HandlePacket;
string fullPath = Path.GetFullPath(Path.Combine(Plugin.SprayDir, ".."));
string[] array = new string[3] { "spray.ogg", "spray.wav", "spray.mp3" };
foreach (string path in array)
{
string path2 = Path.Combine(fullPath, path);
if (File.Exists(path2))
{
LoadClip("", path2);
break;
}
}
soundFiles = ScanSounds();
string[] array2 = soundFiles;
foreach (string path3 in array2)
{
LoadClip(Path.GetFileName(path3), path3);
}
selectedSound = Plugin.SelectedSound.Value ?? "";
}
private void Update()
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
PollClips();
PollJpg();
net.Tick();
InputBlock.Bypass = true;
bool keyDown = Input.GetKeyDown(Plugin.MenuKey.Value);
bool flag = !menuOpen && Input.GetKeyDown(Plugin.SprayKey.Value);
bool flag2 = !menuOpen && Input.GetKeyDown(Plugin.DeleteLastKey.Value);
bool flag3 = !menuOpen && Input.GetKeyDown(Plugin.DeleteAllKey.Value);
InputBlock.Bypass = false;
if (keyDown)
{
SetMenu(!menuOpen);
}
else if (flag)
{
TrySpray();
}
else if (flag2)
{
DeleteLast();
}
else if (flag3)
{
DeleteAll();
}
if (armed != null && !armed.Ready && !armed.Failed && Time.time > hudUntil - 0.5f)
{
hudUntil = Time.time + 1f;
}
for (int num = active.Count - 1; num >= 0; num--)
{
if ((Object)(object)active[num].Go == (Object)null || Time.time >= active[num].Expires)
{
if ((Object)(object)active[num].Go != (Object)null)
{
Object.Destroy((Object)(object)active[num].Go);
}
active.RemoveAt(num);
}
}
}
private void OnDestroy()
{
RewiredLock.Set(lockInput: false);
}
private void SetMenu(bool open)
{
menuOpen = open;
RewiredLock.Set(open);
InputBlock.Bypass = true;
if (open)
{
files = ScanFiles();
soundFiles = ScanSounds();
string[] array = soundFiles;
foreach (string path in array)
{
LoadClip(Path.GetFileName(path), path);
}
Cursor.lockState = (CursorLockMode)0;
Cursor.visible = true;
}
else
{
Cursor.lockState = (CursorLockMode)1;
Cursor.visible = false;
}
InputBlock.Bypass = false;
}
private string[] ScanFiles()
{
try
{
List<string> list = new List<string>();
string[] array = Directory.GetFiles(Plugin.SprayDir, "*", SearchOption.AllDirectories);
foreach (string text in array)
{
if (Array.IndexOf(ImageExts, Path.GetExtension(text).ToLowerInvariant()) >= 0)
{
list.Add(text);
}
}
list.Sort();
return list.ToArray();
}
catch
{
return new string[0];
}
}
private void OnGUI()
{
//IL_0140: Unknown result type (might be due to invalid IL or missing references)
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
if (menuOpen)
{
DrawMenu();
}
else
{
if (Time.time >= hudUntil)
{
return;
}
string text = hudMsg;
if (text == null)
{
if (armed == null)
{
return;
}
string fileName = Path.GetFileName(armed.Path);
text = (armed.Failed ? ("Couldn't load " + fileName + " (see log)") : (armed.Ready ? (fileName + " - press " + ((object)Plugin.SprayKey.Value/*cast due to .constrained prefix*/).ToString() + " to spray (" + ((object)Plugin.MenuKey.Value/*cast due to .constrained prefix*/).ToString() + " to change)") : ("Loading " + fileName + "...")));
}
GUI.Box(new Rect((float)Screen.width / 2f - 240f, (float)(Screen.height - 80), 480f, 28f), text);
}
}
private void DrawMenu()
{
//IL_002e: 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_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
//IL_0150: Unknown result type (might be due to invalid IL or missing references)
//IL_015d: Unknown result type (might be due to invalid IL or missing references)
//IL_0163: Unknown result type (might be due to invalid IL or missing references)
//IL_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: Unknown result type (might be due to invalid IL or missing references)
Rect val = default(Rect);
((Rect)(ref val))..ctor((float)(Screen.width / 2 - 200), (float)(Screen.height / 2 - 250), 400f, 500f);
GUI.Box(val, "Spray menu - pick one, then press " + ((object)Plugin.SprayKey.Value/*cast due to .constrained prefix*/).ToString());
float num = (((Rect)(ref val)).width - 20f) / 2f;
if (GUI.Button(new Rect(((Rect)(ref val)).x + 10f, ((Rect)(ref val)).y + 28f, num, 28f), (tab == 0) ? "[ Sprays ]" : "Sprays"))
{
tab = 0;
scroll = Vector2.zero;
}
if (GUI.Button(new Rect(((Rect)(ref val)).x + 10f + num, ((Rect)(ref val)).y + 28f, num, 28f), (tab == 1) ? "[ Sounds ]" : "Sounds"))
{
tab = 1;
scroll = Vector2.zero;
}
GUILayout.BeginArea(new Rect(((Rect)(ref val)).x + 10f, ((Rect)(ref val)).y + 62f, ((Rect)(ref val)).width - 20f, ((Rect)(ref val)).height - 72f));
scroll = GUILayout.BeginScrollView(scroll, (Il2CppReferenceArray<GUILayoutOption>)null);
if (tab == 0)
{
DrawSprays();
}
else
{
DrawSounds();
}
GUILayout.EndScrollView();
if (GUILayout.Button("Close", (Il2CppReferenceArray<GUILayoutOption>)null))
{
SetMenu(open: false);
}
GUILayout.EndArea();
}
private void DrawSprays()
{
string text = ((armed != null) ? armed.Path : "");
if (files.Length == 0)
{
GUILayout.Label("No images in:\n" + Plugin.SprayDir + "\n(png, jpg, gif, bmp)", (Il2CppReferenceArray<GUILayoutOption>)null);
}
string[] array = files;
foreach (string text2 in array)
{
string text3 = ((text2 == text) ? "* " : "") + Path.GetFileName(text2);
if (GUILayout.Button(text3, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) }))
{
Arm(text2);
SetMenu(open: false);
}
}
}
private void DrawSounds()
{
string text = selectedSound;
if (GUILayout.Button(((text == "") ? "* " : "") + "Default (spray sound)", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) }))
{
SelectSound("");
}
string[] array = soundFiles;
foreach (string path in array)
{
string fileName = Path.GetFileName(path);
if (GUILayout.Button(((fileName == text) ? "* " : "") + fileName, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) }))
{
SelectSound(fileName);
}
}
if (soundFiles.Length == 0)
{
GUILayout.Label("Put .ogg / .wav / .mp3 files in:\n" + Plugin.SoundDir, (Il2CppReferenceArray<GUILayoutOption>)null);
}
}
private void SelectSound(string name)
{
selectedSound = name;
Plugin.SelectedSound.Value = name;
AudioSource holder = GetHolder(name);
if ((Object)(object)holder != (Object)null && (Object)(object)holder.clip != (Object)null)
{
holder.Play();
}
else
{
((BasePlugin)Plugin.Instance).Log.LogWarning((object)("Sound '" + name + "' isn't loaded (yet)."));
}
}
private void Hud(string msg)
{
hudMsg = msg;
hudUntil = Time.time + 2f;
}
private void Arm(string path)
{
DateTime lastWriteTimeUtc;
try
{
lastWriteTimeUtc = File.GetLastWriteTimeUtc(path);
}
catch
{
return;
}
if (this.prepared.TryGetValue(path, out var value) && value.Stamp == lastWriteTimeUtc && value.Ready)
{
armed = value;
hudMsg = null;
hudUntil = Time.time + 6f;
return;
}
Prepared prepared = new Prepared
{
Path = path,
Stamp = lastWriteTimeUtc
};
this.prepared[path] = prepared;
armed = prepared;
hudMsg = null;
hudUntil = Time.time + 6f;
byte[] array;
try
{
array = File.ReadAllBytes(path);
}
catch (Exception ex)
{
((BasePlugin)Plugin.Instance).Log.LogWarning((object)("Can't read " + path + ": " + ex.Message));
prepared.Failed = true;
return;
}
int w;
int h;
Color32[] px;
string err;
if (ImageDecoders.IsJpeg(array))
{
StartJpg(prepared);
}
else if (!ImageDecoders.TryDecode(array, 4096, out w, out h, out px, out err))
{
((BasePlugin)Plugin.Instance).Log.LogWarning((object)("Can't decode " + Path.GetFileName(path) + ": " + err));
prepared.Failed = true;
}
else
{
Finish(prepared, w, h, px, ImageDecoders.IsPng(array) ? array : null);
}
}
private void StartJpg(Prepared p)
{
try
{
if (jpgReq != null)
{
try
{
jpgReq.Abort();
jpgReq.Dispose();
}
catch
{
}
jpgReq = null;
}
jpgReq = UnityWebRequestTexture.GetTexture(new Uri(Path.GetFullPath(p.Path)).AbsoluteUri);
jpgReq.SendWebRequest();
jpgTarget = p;
}
catch (Exception ex)
{
((BasePlugin)Plugin.Instance).Log.LogWarning((object)("JPEG load failed to start: " + ex.Message));
p.Failed = true;
}
}
private void PollJpg()
{
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Invalid comparison between Unknown and I4
if (jpgReq == null || !jpgReq.isDone)
{
return;
}
UnityWebRequest val = jpgReq;
Prepared prepared = jpgTarget;
jpgReq = null;
jpgTarget = null;
try
{
if ((int)val.result != 1)
{
((BasePlugin)Plugin.Instance).Log.LogWarning((object)("JPEG load failed: " + val.error));
prepared.Failed = true;
return;
}
Texture2D content = DownloadHandlerTexture.GetContent(val);
int width = ((Texture)content).width;
int height = ((Texture)content).height;
if (width < 1 || height < 1 || width > 4096 || height > 4096)
{
Object.Destroy((Object)(object)content);
prepared.Failed = true;
((BasePlugin)Plugin.Instance).Log.LogWarning((object)("JPEG too large: " + width + "x" + height));
}
else
{
Color32[] opx = Il2CppArrayBase<Color32>.op_Implicit((Il2CppArrayBase<Color32>)(object)content.GetPixels32());
Object.Destroy((Object)(object)content);
Finish(prepared, width, height, opx, null);
}
}
catch (Exception ex)
{
((BasePlugin)Plugin.Instance).Log.LogWarning((object)("JPEG decode failed: " + ex.Message));
prepared.Failed = true;
}
finally
{
val.Dispose();
}
}
private void Finish(Prepared p, int ow, int oh, Color32[] opx, byte[] rawPng)
{
byte[] array = null;
int w = ow;
int h = oh;
Color32[] px = opx;
if (rawPng != null && Math.Max(ow, oh) <= 384 && rawPng.Length <= 49152)
{
array = rawPng;
}
else
{
int num = 384;
int num2 = 0;
while (num2 < 8 && num >= 16)
{
float num3 = Math.Min(1f, (float)num / (float)Math.Max(ow, oh));
int num4 = Math.Max(1, (int)((float)ow * num3));
int num5 = Math.Max(1, (int)((float)oh * num3));
Color32[] array2 = PngCodec.Resize(opx, ow, oh, num4, num5);
byte[] array3 = PngCodec.Encode(num4, num5, array2);
if (array3.Length <= 49152)
{
array = array3;
w = num4;
h = num5;
px = array2;
break;
}
num2++;
num = (int)((float)num * 0.75f);
}
}
if (array == null)
{
((BasePlugin)Plugin.Instance).Log.LogWarning((object)("Couldn't shrink " + Path.GetFileName(p.Path) + " small enough to send."));
p.Failed = true;
return;
}
p.Png = array;
p.Hash = Hash(array);
if (!textures.ContainsKey(p.Hash))
{
textures[p.Hash] = MakeTexture(w, h, px);
}
pngBytes[p.Hash] = array;
p.Ready = true;
}
private void TrySpray()
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
//IL_00da: Unknown result type (might be due to invalid IL or missing references)
//IL_011a: Unknown result type (might be due to invalid IL or missing references)
//IL_013d: Unknown result type (might be due to invalid IL or missing references)
//IL_0130: Unknown result type (might be due to invalid IL or missing references)
//IL_0142: Unknown result type (might be due to invalid IL or missing references)
//IL_014b: Unknown result type (might be due to invalid IL or missing references)
//IL_0150: Unknown result type (might be due to invalid IL or missing references)
//IL_0158: Unknown result type (might be due to invalid IL or missing references)
//IL_015d: Unknown result type (might be due to invalid IL or missing references)
//IL_0163: Unknown result type (might be due to invalid IL or missing references)
//IL_0164: Unknown result type (might be due to invalid IL or missing references)
if (armed == null)
{
Hud("Press " + ((object)Plugin.MenuKey.Value/*cast due to .constrained prefix*/).ToString() + " and pick a spray first");
}
else if (armed.Failed)
{
Hud("That image couldn't be loaded (see log)");
}
else if (!armed.Ready)
{
Hud("Still loading...");
}
else
{
if (Time.time - lastSpray < Plugin.Cooldown.Value)
{
return;
}
Camera main = Camera.main;
if ((Object)(object)main == (Object)null)
{
return;
}
RaycastHit val = default(RaycastHit);
if (!Physics.Raycast(((Component)main).transform.position, ((Component)main).transform.forward, ref val, Plugin.MaxRange.Value, -1, (QueryTriggerInteraction)1))
{
Hud("No surface in range");
return;
}
lastSpray = Time.time;
Vector3 up = ((Mathf.Abs(((RaycastHit)(ref val)).normal.y) > 0.95f) ? ((Component)main).transform.up : Vector3.up);
PendingSpray s = new PendingSpray
{
Pos = ((RaycastHit)(ref val)).point,
Normal = ((RaycastHit)(ref val)).normal,
Up = up,
Size = Plugin.SprayWorldSize.Value,
Owner = myId,
Seq = ++mySeq,
Sound = selectedSound
};
if (sentHashes.Add(armed.Hash))
{
net.Broadcast(WriteImage(armed.Hash, armed.Png));
}
net.Broadcast(WriteSpray(armed.Hash, s));
if (!(net is NullNet))
{
PlaceSpray(armed.Hash, s);
}
}
}
private void PlaceSpray(string hash, PendingSpray s)
{
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
//IL_00e5: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
//IL_0119: Unknown result type (might be due to invalid IL or missing references)
if (!textures.TryGetValue(hash, out var value))
{
if (!pending.TryGetValue(hash, out var value2))
{
value2 = (pending[hash] = new List<PendingSpray>());
}
if (value2.Count == 0)
{
net.Broadcast(WriteRequest(hash));
}
value2.Add(s);
return;
}
PlayAt(s.Sound, s.Pos);
GameObject val = GameObject.CreatePrimitive((PrimitiveType)5);
Object.Destroy((Object)(object)val.GetComponent<Collider>());
((Object)val).name = "Spray";
float num = (float)((Texture)value).width / (float)((Texture)value).height;
val.transform.position = s.Pos + s.Normal * 0.01f;
val.transform.rotation = Quaternion.LookRotation(-s.Normal, s.Up);
val.transform.localScale = new Vector3(s.Size * num, s.Size, 1f);
MeshRenderer component = val.GetComponent<MeshRenderer>();
((Renderer)component).material = MakeMaterial(value);
((Renderer)component).shadowCastingMode = (ShadowCastingMode)0;
((Renderer)component).receiveShadows = false;
float value3 = Plugin.Lifetime.Value;
active.Add(new ActiveSpray
{
Go = val,
Owner = s.Owner,
Seq = s.Seq,
Expires = ((value3 > 0f) ? (Time.time + value3) : float.PositiveInfinity)
});
EnforceCap(s.Owner);
}
private Material MakeMaterial(Texture2D tex)
{
//IL_0186: Unknown result type (might be due to invalid IL or missing references)
//IL_018c: Expected O, but got Unknown
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Expected O, but got Unknown
if ((Object)(object)baseMat == (Object)null)
{
string[] array = new string[3] { "Universal Render Pipeline/Unlit", "Sprites/Default", "Unlit/Transparent" };
Shader val = null;
string[] array2 = array;
foreach (string text in array2)
{
val = Shader.Find(text);
if ((Object)(object)val != (Object)null)
{
break;
}
}
if ((Object)(object)val == (Object)null)
{
((BasePlugin)Plugin.Instance).Log.LogError((object)"No usable shader found (stripped from build?)");
val = Shader.Find("Hidden/InternalErrorShader");
}
baseMat = new Material(val);
if (((Object)val).name.StartsWith("Universal"))
{
baseMat.SetFloat("_Surface", 1f);
baseMat.SetFloat("_Blend", 0f);
baseMat.SetFloat("_SrcBlend", 5f);
baseMat.SetFloat("_DstBlend", 10f);
baseMat.SetFloat("_ZWrite", 0f);
baseMat.SetFloat("_Cull", 0f);
baseMat.EnableKeyword("_SURFACE_TYPE_TRANSPARENT");
baseMat.SetOverrideTag("RenderType", "Transparent");
}
baseMat.renderQueue = 3000;
}
Material val2 = new Material(baseMat);
val2.mainTexture = (Texture)(object)tex;
if (val2.HasProperty("_BaseMap"))
{
val2.SetTexture("_BaseMap", (Texture)(object)tex);
}
return val2;
}
private void HandlePacket(byte[] data)
{
//IL_0148: Unknown result type (might be due to invalid IL or missing references)
//IL_014d: Unknown result type (might be due to invalid IL or missing references)
//IL_0165: Unknown result type (might be due to invalid IL or missing references)
//IL_016a: Unknown result type (might be due to invalid IL or missing references)
//IL_0182: Unknown result type (might be due to invalid IL or missing references)
//IL_0187: Unknown result type (might be due to invalid IL or missing references)
try
{
using BinaryReader binaryReader = new BinaryReader(new MemoryStream(data));
byte b = binaryReader.ReadByte();
string text = binaryReader.ReadString();
switch (b)
{
case 2:
{
int num = binaryReader.ReadInt32();
if (num <= 0 || num > 49152 || textures.ContainsKey(text))
{
break;
}
byte[] array = binaryReader.ReadBytes(num);
if (Hash(array) != text)
{
break;
}
Texture2D val = Decode(array);
if ((Object)(object)val == (Object)null)
{
break;
}
textures[text] = val;
pngBytes[text] = array;
if (!pending.TryGetValue(text, out var value2))
{
break;
}
foreach (PendingSpray item in value2)
{
PlaceSpray(text, item);
}
pending.Remove(text);
break;
}
case 1:
{
PendingSpray s = new PendingSpray
{
Pos = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle()),
Normal = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle()),
Up = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle()),
Size = Mathf.Clamp(binaryReader.ReadSingle(), 0.1f, 3f),
Owner = binaryReader.ReadInt32(),
Seq = binaryReader.ReadInt32(),
Sound = SafeSoundName(binaryReader.ReadString())
};
PlaceSpray(text, s);
break;
}
case 4:
{
int owner = binaryReader.ReadInt32();
int seq = binaryReader.ReadInt32();
RemoveSpray(owner, seq);
break;
}
case 3:
{
if (pngBytes.TryGetValue(text, out var value))
{
net.Broadcast(WriteImage(text, value));
}
break;
}
}
}
catch (Exception ex)
{
((BasePlugin)Plugin.Instance).Log.LogWarning((object)("Bad spray packet: " + ex.Message));
}
}
private static byte[] WriteImage(string hash, byte[] png)
{
using MemoryStream memoryStream = new MemoryStream();
using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
binaryWriter.Write((byte)2);
binaryWriter.Write(hash);
binaryWriter.Write(png.Length);
binaryWriter.Write(png);
return memoryStream.ToArray();
}
private static byte[] WriteRequest(string hash)
{
using MemoryStream memoryStream = new MemoryStream();
using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
binaryWriter.Write((byte)3);
binaryWriter.Write(hash);
return memoryStream.ToArray();
}
private static byte[] WriteDelete(int owner, int seq)
{
using MemoryStream memoryStream = new MemoryStream();
using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
binaryWriter.Write((byte)4);
binaryWriter.Write("");
binaryWriter.Write(owner);
binaryWriter.Write(seq);
return memoryStream.ToArray();
}
private static byte[] WriteSpray(string hash, PendingSpray s)
{
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: 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_0078: Unknown result type (might be due to invalid IL or missing references)
using MemoryStream memoryStream = new MemoryStream();
using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
binaryWriter.Write((byte)1);
binaryWriter.Write(hash);
Vector3[] array = (Vector3[])(object)new Vector3[3] { s.Pos, s.Normal, s.Up };
foreach (Vector3 val in array)
{
binaryWriter.Write(val.x);
binaryWriter.Write(val.y);
binaryWriter.Write(val.z);
}
binaryWriter.Write(s.Size);
binaryWriter.Write(s.Owner);
binaryWriter.Write(s.Seq);
binaryWriter.Write(s.Sound ?? "");
return memoryStream.ToArray();
}
private void DeleteLast()
{
for (int num = active.Count - 1; num >= 0; num--)
{
if (active[num].Owner == myId)
{
int seq = active[num].Seq;
if ((Object)(object)active[num].Go != (Object)null)
{
Object.Destroy((Object)(object)active[num].Go);
}
active.RemoveAt(num);
net.Broadcast(WriteDelete(myId, seq));
Hud("Removed your latest spray");
return;
}
}
Hud("You have no sprays to remove");
}
private void DeleteAll()
{
int count = active.Count;
foreach (ActiveSpray item in active)
{
if ((Object)(object)item.Go != (Object)null)
{
Object.Destroy((Object)(object)item.Go);
}
}
active.Clear();
pending.Clear();
Hud((count == 0) ? "No sprays to clear" : ("Cleared " + count + " spray(s) from your screen"));
}
private void RemoveSpray(int owner, int seq)
{
for (int i = 0; i < active.Count; i++)
{
if (active[i].Owner == owner && active[i].Seq == seq)
{
if ((Object)(object)active[i].Go != (Object)null)
{
Object.Destroy((Object)(object)active[i].Go);
}
active.RemoveAt(i);
break;
}
}
}
private void EnforceCap(int owner)
{
int value = Plugin.MaxPerPlayer.Value;
if (value <= 0)
{
return;
}
int num = 0;
foreach (ActiveSpray item in active)
{
if (item.Owner == owner)
{
num++;
}
}
int num2 = 0;
while (num2 < active.Count && num > value)
{
if (active[num2].Owner == owner)
{
if ((Object)(object)active[num2].Go != (Object)null)
{
Object.Destroy((Object)(object)active[num2].Go);
}
active.RemoveAt(num2);
num--;
}
else
{
num2++;
}
}
}
private static string[] ScanSounds()
{
try
{
List<string> list = new List<string>();
string[] array = Directory.GetFiles(Plugin.SoundDir, "*", SearchOption.AllDirectories);
foreach (string text in array)
{
string text2 = Path.GetExtension(text).ToLowerInvariant();
if (text2 == ".ogg" || text2 == ".wav" || text2 == ".mp3")
{
list.Add(text);
}
}
list.Sort();
return list.ToArray();
}
catch
{
return new string[0];
}
}
private static AudioType TypeFor(string path)
{
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
string text = Path.GetExtension(path).ToLowerInvariant();
string text2 = text;
if (!(text2 == ".wav"))
{
if (text2 == ".mp3")
{
return (AudioType)13;
}
return (AudioType)14;
}
return (AudioType)20;
}
private void LoadClip(string key, string path)
{
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
if (holders.ContainsKey(key) || clipReqs.ContainsKey(key))
{
return;
}
try
{
UnityWebRequest audioClip = UnityWebRequestMultimedia.GetAudioClip(new Uri(Path.GetFullPath(path)).AbsoluteUri, TypeFor(path));
audioClip.SendWebRequest();
clipReqs[key] = audioClip;
}
catch (Exception ex)
{
((BasePlugin)Plugin.Instance).Log.LogWarning((object)("Could not start loading sound " + path + ": " + ex.Message));
}
}
private void PollClips()
{
//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
//IL_00c3: Invalid comparison between Unknown and I4
if (clipReqs.Count == 0)
{
return;
}
List<string> list = null;
foreach (KeyValuePair<string, UnityWebRequest> clipReq in clipReqs)
{
if (clipReq.Value.isDone)
{
(list ?? (list = new List<string>())).Add(clipReq.Key);
}
}
if (list == null)
{
return;
}
foreach (string item in list)
{
UnityWebRequest val = clipReqs[item];
clipReqs.Remove(item);
try
{
if ((int)val.result == 1)
{
AudioClip content = DownloadHandlerAudioClip.GetContent(val);
if ((Object)(object)content != (Object)null)
{
((Object)content).name = ((item == "") ? "default" : Path.GetFileNameWithoutExtension(item));
holders[item] = MakeHolder(content);
((BasePlugin)Plugin.Instance).Log.LogInfo((object)("Loaded sound '" + ((item == "") ? "(default)" : item) + "'"));
}
else
{
((BasePlugin)Plugin.Instance).Log.LogWarning((object)("Sound '" + item + "' decoded to a null clip."));
}
}
else
{
((BasePlugin)Plugin.Instance).Log.LogWarning((object)("Sound '" + item + "' failed: " + val.error));
}
}
catch (Exception ex)
{
((BasePlugin)Plugin.Instance).Log.LogWarning((object)("Sound '" + item + "' exception: " + ex.Message));
}
finally
{
val.Dispose();
}
}
}
private AudioSource MakeHolder(AudioClip clip)
{
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Expected O, but got Unknown
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Expected O, but got Unknown
if ((Object)(object)soundHost == (Object)null)
{
soundHost = new GameObject("SpraySoundHost")
{
hideFlags = (HideFlags)61
};
Object.DontDestroyOnLoad((Object)(object)soundHost);
}
GameObject val = new GameObject("SprayClip_" + ((Object)clip).name);
val.transform.SetParent(soundHost.transform, false);
AudioSource val2 = ((Il2CppObjectBase)val.AddComponent(Il2CppType.Of<AudioSource>())).Cast<AudioSource>();
val2.clip = clip;
val2.playOnAwake = false;
val2.spatialBlend = 0f;
return val2;
}
private AudioSource GetHolder(string name)
{
if (!string.IsNullOrEmpty(name) && holders.TryGetValue(name, out var value) && (Object)(object)value != (Object)null && (Object)(object)value.clip != (Object)null)
{
return value;
}
AudioSource value2;
return (holders.TryGetValue("", out value2) && (Object)(object)value2 != (Object)null && (Object)(object)value2.clip != (Object)null) ? value2 : null;
}
private void PlayAt(string soundName, Vector3 pos)
{
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Expected O, but got Unknown
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
try
{
AudioSource holder = GetHolder(soundName);
if ((Object)(object)holder == (Object)null)
{
((BasePlugin)Plugin.Instance).Log.LogInfo((object)"No spray sound loaded (put spray.ogg next to the sprays folder, or pick one in the Sounds tab).");
return;
}
GameObject val = new GameObject("SprayPlay");
val.transform.position = pos;
AudioSource val2 = ((Il2CppObjectBase)val.AddComponent(Il2CppType.Of<AudioSource>())).Cast<AudioSource>();
val2.clip = holder.clip;
val2.playOnAwake = false;
val2.spatialBlend = 1f;
val2.rolloffMode = (AudioRolloffMode)1;
val2.minDistance = 1f;
val2.maxDistance = 30f;
val2.volume = Mathf.Clamp01(Plugin.Volume.Value);
val2.Play();
Object.Destroy((Object)(object)val, holder.clip.length + 0.5f);
}
catch (Exception ex)
{
((BasePlugin)Plugin.Instance).Log.LogWarning((object)("Spray sound failed: " + ex.Message));
}
}
private static string SafeSoundName(string n)
{
return (string.IsNullOrEmpty(n) || n.Length > 100) ? "" : n;
}
private static string Hash(byte[] b)
{
using SHA1 sHA = SHA1.Create();
return BitConverter.ToString(sHA.ComputeHash(b)).Replace("-", "").Substring(0, 16);
}
private static Texture2D Decode(byte[] png)
{
if (!PngCodec.TryDecode(png, 1024, out var width, out var height, out var pixels, out var error))
{
((BasePlugin)Plugin.Instance).Log.LogWarning((object)("PNG decode failed: " + error));
return null;
}
return MakeTexture(width, height, pixels);
}
private static Texture2D MakeTexture(int w, int h, Color32[] px)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Expected O, but got Unknown
Texture2D val = new Texture2D(w, h, (TextureFormat)4, true);
val.SetPixels32(Il2CppStructArray<Color32>.op_Implicit(px));
val.Apply(true, false);
((Texture)val).wrapMode = (TextureWrapMode)1;
return val;
}
}
}