using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using GTFO.API;
using GameData;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using SNetwork;
using UnityEngine;
[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 = "")]
[assembly: AssemblyCompany("GlowierSticks")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("GlowierSticks")]
[assembly: AssemblyTitle("GlowierSticks")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
}
namespace GlowierSticks
{
public static class Configuration
{
public static class LocalConfig
{
private static readonly ConfigFile configFile;
public const double DEFAULT_GLOWSTICK_RANGE = 15.0;
private static readonly ConfigEntry<double> _glowstickRange;
public const bool DEFAULT_DO_LIGHTNESS_NORMALIZATION = true;
private static readonly ConfigEntry<bool> _doLightnessRangeNormalization;
public const float DEFAULT_GLOWSTICK_FADE_IN_TIME = 3f;
private static readonly ConfigEntry<float> _glowstickFadeInTime;
public const float DEFAULT_GLOWSTICK_DURATION = 237f;
private static readonly ConfigEntry<float> _glowstickDuration;
public const float DEFAULT_GLOWSTICK_FADE_OUT_TIME = 60f;
private static readonly ConfigEntry<float> _glowstickFadeOutTime;
public const int DEFAULT_GLOWSTICK_COUNT_MAX = 8;
private static readonly ConfigEntry<int> _glowstickCountMax;
public const int DEFAULT_GLOWSTICK_COUNT_MIN = 7;
private static readonly ConfigEntry<int> _glowstickCountMin;
private static readonly ConfigEntry<bool> _doDebug;
public static double GlowstickRange => _glowstickRange.Value;
public static bool DoLightnessRangeNormalization => _doLightnessRangeNormalization.Value;
public static float GlowstickFadeInTime => _glowstickFadeInTime.Value;
public static float GlowstickDuration => _glowstickDuration.Value;
public static float GlowstickFadeOutTime => _glowstickFadeOutTime.Value;
public static int GlowstickCountMax => _glowstickCountMax.Value;
public static int GlowstickCountMin => _glowstickCountMin.Value;
public static bool DoDebug => _doDebug.Value;
static LocalConfig()
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Expected O, but got Unknown
configFile = new ConfigFile(Path.Combine(Paths.ConfigPath, "GlowierSticks.cfg"), true);
_glowstickRange = configFile.Bind<double>("General Settings", "Target glowstick range", 15.0, "Total range of glowstick light, in meters (base game uses 5m); depending on color, brightly lit area reaches up to ~75% of this distance");
_doLightnessRangeNormalization = configFile.Bind<bool>("General Settings", "Light range normalization", true, "Whether to adjust glowstick light range so that every glowstick light color visually reaches about as far as a base-game yellow glowstick would");
_glowstickFadeInTime = configFile.Bind<float>("General Settings", "Glowstick fade-in time", 3f, "Time required for a glowstick to reach full brightness from the moment it's thrown, in seconds (base game uses 2)");
_glowstickDuration = configFile.Bind<float>("General Settings", "Glowstick duration", 237f, "Time glowstick light will shine for at full brightness, in seconds (base game uses 60)");
_glowstickFadeOutTime = configFile.Bind<float>("General Settings", "Glowstick fade-out time", 60f, "Time over which glowstick light will gradually fade out once its duration expires; (base game uses 3)");
_glowstickCountMax = configFile.Bind<int>("Generation Settings", "Glowstick maximum count", 8, "Maximum number of glowsticks in a randomly generated pack");
_glowstickCountMin = configFile.Bind<int>("Generation Settings", "Glowstick minimum count", 7, "Miminum number of glowsticks in a randomly generated pack");
_doDebug = configFile.Bind<bool>("Misc Settings", "Debug output", false, "Whether to output various debugging messages");
}
}
public static class RemoteConfig
{
internal struct ConfigPacket
{
public double GlowstickRange;
public bool DoLightnessRangeNormalization;
public float GlowstickFadeInTime;
public float GlowstickDuration;
public float GlowstickFadeOutTime;
public int GlowstickCountMax;
public int GlowstickCountMin;
public ConfigPacket()
{
GlowstickRange = LocalConfig.GlowstickRange;
DoLightnessRangeNormalization = LocalConfig.DoLightnessRangeNormalization;
GlowstickFadeInTime = LocalConfig.GlowstickFadeInTime;
GlowstickDuration = LocalConfig.GlowstickDuration;
GlowstickFadeOutTime = LocalConfig.GlowstickFadeOutTime;
GlowstickCountMax = LocalConfig.GlowstickCountMax;
GlowstickCountMin = LocalConfig.GlowstickCountMin;
}
}
private static bool _isReady = false;
private static double _glowstickRange = 15.0;
private static bool _doLightnessRangeNormalization = true;
private static float _glowstickFadeInTime = 3f;
private static float _glowstickDuration = 237f;
private static float _glowstickFadeOutTime = 60f;
private static int _glowstickCountMax = 8;
private static int _glowstickCountMin = 7;
public static bool IsReady => _isReady;
public static double GlowstickRange => _glowstickRange;
public static bool DoLightnessRangeNormalization => _doLightnessRangeNormalization;
public static float GlowstickFadeInTime => _glowstickFadeInTime;
public static float GlowstickDuration => _glowstickDuration;
public static float GlowstickFadeOutTime => _glowstickFadeOutTime;
public static int GlowstickCountMax => _glowstickCountMax;
public static int GlowstickCountMin => _glowstickCountMin;
internal static void LoadRemoteConfig(ConfigPacket packet)
{
if (_isReady)
{
Logging.Warning("New remote config received before the current was invalidated!");
return;
}
Logging.Debug("Loading remote settings:\n" + $"GlowstickRange = {packet.GlowstickRange}\n" + $"DoLightnessNormalization = {packet.DoLightnessRangeNormalization}\n" + $"GlowstickFadeInTime = {packet.GlowstickFadeInTime}\n" + $"GlowstickDuration = {packet.GlowstickDuration}\n" + $"GlowstickFadeOutTime = {packet.GlowstickFadeOutTime}\n" + $"GlowstickCountMax = {packet.GlowstickCountMax}\n" + $"GlowstickCountMin = {packet.GlowstickCountMin}");
_glowstickRange = packet.GlowstickRange;
_doLightnessRangeNormalization = packet.DoLightnessRangeNormalization;
_glowstickFadeInTime = packet.GlowstickFadeInTime;
_glowstickDuration = packet.GlowstickDuration;
_glowstickFadeOutTime = packet.GlowstickFadeOutTime;
_glowstickCountMax = packet.GlowstickCountMax;
_glowstickCountMin = packet.GlowstickCountMin;
_isReady = true;
}
internal static void InvalidateRemoteConfig()
{
Logging.Debug("Invalidating remote config");
_isReady = false;
}
}
private static readonly HashSet<uint> TRACKED_GLOWSTICK_PIDS = new HashSet<uint> { 114u, 130u, 167u, 174u };
public static double GlowstickRange => SNet.IsMaster ? LocalConfig.GlowstickRange : RemoteConfig.GlowstickRange;
public static bool DoLightnessRangeNormalization => SNet.IsMaster ? LocalConfig.DoLightnessRangeNormalization : RemoteConfig.DoLightnessRangeNormalization;
public static float GlowstickFadeInTime => SNet.IsMaster ? LocalConfig.GlowstickFadeInTime : RemoteConfig.GlowstickFadeInTime;
public static float GlowstickDuration => SNet.IsMaster ? LocalConfig.GlowstickDuration : RemoteConfig.GlowstickDuration;
public static float GlowstickFadeOutTime => SNet.IsMaster ? LocalConfig.GlowstickFadeOutTime : RemoteConfig.GlowstickFadeOutTime;
public static int GlowstickCountMax => SNet.IsMaster ? LocalConfig.GlowstickCountMax : RemoteConfig.GlowstickCountMax;
public static int GlowstickCountMin => SNet.IsMaster ? LocalConfig.GlowstickCountMin : RemoteConfig.GlowstickCountMin;
public static HashSet<uint> TrackedGlowstickPIDs => TRACKED_GLOWSTICK_PIDS;
public static bool IsEligibleGlowstick(ItemDataBlock itemDataBlock)
{
return TRACKED_GLOWSTICK_PIDS.Contains(((GameDataBlockBase<ItemDataBlock>)(object)itemDataBlock).persistentID);
}
}
[BepInPlugin("CinnamonSnowball.GlowierSticks", "GlowierSticks", "0.8.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
internal sealed class Plugin : BasePlugin
{
internal static class GlowstickTweaks
{
[HarmonyPatch]
internal static class GlowstickPatches
{
[HarmonyPatch(typeof(SNet_SyncManager), "OnFoundMaster")]
[HarmonyPostfix]
private static void PostFoundMaster()
{
if (SNet.IsMaster)
{
ModifyTemplates();
}
}
internal static void OnReceiveConfigPacket()
{
ModifyTemplates();
}
[HarmonyPatch(typeof(SNet_SessionHub), "LeaveHub")]
[HarmonyPostfix]
private static void PostLeaveHub()
{
ResetTemplates();
}
[HarmonyPatch(typeof(GlowstickInstance), "Setup")]
[HarmonyPostfix]
private static void PostGlowstickInstanceSetup(GlowstickInstance __instance)
{
if (!SNet.IsMaster && !Configuration.RemoteConfig.IsReady)
{
Logging.Debug("Aborting glowstick modification: in an unmodded lobby!");
return;
}
if (!Configuration.IsEligibleGlowstick(((Item)__instance).ItemDataBlock))
{
Logging.Debug("Aborting glowstick modification: persistent ID not in list of glowsticks to modify!");
return;
}
Logging.Debug("Setting up thrown glowstick...");
double num = 1.0;
if (Configuration.DoLightnessRangeNormalization)
{
num = CalculateLightnessRangeMultiplier(__instance);
Logging.Debug($"Lightness range multiplier: {Math.Round(num, 3)}");
}
double num2 = Configuration.GlowstickRange * num / 5.0;
Logging.Debug($"Light range: {Math.Round(__instance.s_lightRange, 3)} → {Math.Round((double)__instance.s_lightRange * num2, 3)}{(Configuration.DoLightnessRangeNormalization ? " (lightness-normalized)" : "")}");
__instance.s_lightRange *= (float)num2;
float num3 = Configuration.GlowstickDuration / 60f;
Logging.Debug($"Duration: {Math.Round(__instance.s_lightLifeTime, 3)} → {Math.Round(__instance.s_lightLifeTime * num3, 3)}");
__instance.s_lightLifeTime *= num3;
Logging.Debug("Setup done!");
}
[HarmonyPatch(typeof(GlowstickInstance), "Update")]
[HarmonyPrefix]
private static void PreGlowstickInstanceUpdate(GlowstickInstance __instance)
{
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Invalid comparison between Unknown and I4
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Invalid comparison between Unknown and I4
if ((SNet.IsMaster || Configuration.RemoteConfig.IsReady) && Configuration.IsEligibleGlowstick(((Item)__instance).ItemDataBlock))
{
if ((int)__instance.m_state == 1)
{
__instance.m_progressionSpeed = 1f / Configuration.GlowstickFadeInTime;
}
else if ((int)__instance.m_state == 3)
{
__instance.m_progressionSpeed = 1f / Configuration.GlowstickFadeOutTime;
}
}
}
}
private const double IDEAL_LIGHT_COLOR_OKLCH_LIGHTNESS = 0.9;
private const double VANILLA_GLOWSTICK_RANGE = 5.0;
private const float VANILLA_GLOWSTICK_DURATION = 60f;
private static readonly Dictionary<uint, List<int>> baseAmmoCounts = new Dictionary<uint, List<int>>();
private static double CalculateOKLCHLightness(Color lightColor)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
double num = lightColor.r;
double num2 = lightColor.g;
double num3 = lightColor.b;
double num4 = ((num <= 0.04045) ? (num / 12.92) : Math.Pow((num + 0.055) / 1.055, 2.4));
double num5 = ((num2 <= 0.04045) ? (num2 / 12.92) : Math.Pow((num2 + 0.055) / 1.055, 2.4));
double num6 = ((num3 <= 0.04045) ? (num3 / 12.92) : Math.Pow((num3 + 0.055) / 1.055, 2.4));
double num7 = Math.Cbrt(num4 * 0.4122214708 + num5 * 0.5363325363 + num6 * 0.0514459929);
double num8 = Math.Cbrt(num4 * 0.2119034982 + num5 * 0.6806995451 + num6 * 0.1073969566);
double num9 = Math.Cbrt(num4 * 0.0883024619 + num5 * 0.2817188376 + num6 * 0.6299787005);
return num7 * 0.2104542553 + num8 * 0.793617785 - num9 * 0.0040720468;
}
private static double CalculateLightnessRangeMultiplier(GlowstickInstance glowstick)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
double num = CalculateOKLCHLightness(glowstick.m_LightColorTarget);
Logging.Debug($"OKLCH lightness of glowstick light color: {Math.Round(num, 3)}");
return Math.Sqrt(0.9 / num);
}
internal static void ModifyTemplates()
{
Logging.Debug("Modifying glowstick templates...");
int glowstickCountMax = Configuration.GlowstickCountMax;
int glowstickCountMin = Configuration.GlowstickCountMin;
foreach (uint trackedGlowstickPID in Configuration.TrackedGlowstickPIDs)
{
ItemDataBlock block = GameDataBlockBase<ItemDataBlock>.GetBlock(trackedGlowstickPID);
if (!baseAmmoCounts.ContainsKey(trackedGlowstickPID))
{
baseAmmoCounts[trackedGlowstickPID] = new List<int> { block.ConsumableAmmoMax, block.ConsumableAmmoMin };
}
Logging.Debug($"{((GameDataBlockBase<ItemDataBlock>)(object)block).name}({trackedGlowstickPID}) ammo: max {block.ConsumableAmmoMax} → {glowstickCountMax}; min {block.ConsumableAmmoMin} → {glowstickCountMin}");
block.ConsumableAmmoMax = glowstickCountMax;
block.ConsumableAmmoMin = glowstickCountMin;
}
Logging.Debug("Template modification done!");
}
internal static void ResetTemplates()
{
Logging.Debug("Resetting glowstick templates...");
foreach (uint trackedGlowstickPID in Configuration.TrackedGlowstickPIDs)
{
ItemDataBlock block = GameDataBlockBase<ItemDataBlock>.GetBlock(trackedGlowstickPID);
List<int> list = baseAmmoCounts[trackedGlowstickPID];
Logging.Debug($"{((GameDataBlockBase<ItemDataBlock>)(object)block).name}({trackedGlowstickPID}): max {block.ConsumableAmmoMax} → {list[0]}; min {block.ConsumableAmmoMin} → {list[1]}");
block.ConsumableAmmoMax = list[0];
block.ConsumableAmmoMin = list[1];
}
Logging.Debug("Template reset done!");
}
}
public const string MOD_NAME = "GlowierSticks";
public const string MOD_AUTHOR = "CinnamonSnowball";
public const string MOD_GUID = "CinnamonSnowball.GlowierSticks";
public const string MOD_VERSION = "0.8.0";
public override void Load()
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Expected O, but got Unknown
Harmony val = new Harmony("CinnamonSnowball.GlowierSticks");
val.PatchAll();
AssetAPI.OnStartupAssetsLoaded += AssetAPI_OnStartupAssetsLoaded;
Logging.Info($"GlowierSticks loaded with {val.GetPatchedMethods().Count()} patches!");
}
private void AssetAPI_OnStartupAssetsLoaded()
{
RemoteConfigSync.Init();
}
}
internal static class Logging
{
private static readonly ManualLogSource logger = Logger.CreateLogSource("GlowierSticks");
public static void Log(string format, params object[] args)
{
Log(string.Format(format, args));
}
public static void Log(string str)
{
if (logger != null)
{
logger.Log((LogLevel)8, (object)str);
}
}
public static void Warning(string format, params object[] args)
{
Warning(string.Format(format, args));
}
public static void Warning(string str)
{
if (logger != null)
{
logger.Log((LogLevel)4, (object)str);
}
}
public static void Error(string format, params object[] args)
{
Error(string.Format(format, args));
}
public static void Error(string str)
{
if (logger != null)
{
logger.Log((LogLevel)2, (object)str);
}
}
public static void Info(string format, params object[] args)
{
Info(string.Format(format, args));
}
public static void Info(string str)
{
if (logger != null)
{
logger.Log((LogLevel)16, (object)str);
}
}
public static void Debug(string format, params object[] args)
{
Debug(string.Format(format, args));
}
public static void Debug(string str)
{
if (Configuration.LocalConfig.DoDebug && logger != null)
{
logger.Log((LogLevel)32, (object)str);
}
}
}
[HarmonyPatch]
internal static class RemoteConfigSync
{
[HarmonyPatch]
private static class RemoteConfigSyncPatches
{
[HarmonyPatch(typeof(SNet_SyncManager), "OnPlayerSpawnedAgent")]
[HarmonyPostfix]
private static void PostOnPlayerSpawnedAgent(SNet_Player player)
{
if (SNet.IsMaster && !player.IsLocal && !player.IsBot)
{
SendConfigPacket(player);
}
}
[HarmonyPatch(typeof(SNet_SessionHub), "LeaveHub")]
[HarmonyPostfix]
private static void PostLeaveHub()
{
Configuration.RemoteConfig.InvalidateRemoteConfig();
}
}
private static readonly string SYNC_EVENT_NAME = "GLOWIERSTICKS_CONFIG_SYNC";
internal static void Init()
{
NetworkAPI.RegisterEvent<Configuration.RemoteConfig.ConfigPacket>(SYNC_EVENT_NAME, (Action<ulong, Configuration.RemoteConfig.ConfigPacket>)ReceiveConfigPacket);
}
internal static void SendConfigPacket(SNet_Player target)
{
Logging.Debug($"Sending config packet to player #{target.PlayerSlotIndex() + 1}");
NetworkAPI.InvokeEvent<Configuration.RemoteConfig.ConfigPacket>(SYNC_EVENT_NAME, new Configuration.RemoteConfig.ConfigPacket(), target, (SNet_ChannelType)2);
}
internal static void ReceiveConfigPacket(ulong sender, Configuration.RemoteConfig.ConfigPacket packet)
{
SNet_Player val = default(SNet_Player);
if (!SNet.TryGetPlayer(sender, ref val))
{
Logging.Warning($"Received config packet from lookup ID {sender} but they're not a player in our session!");
}
else if ((Object)(object)val != (Object)(object)SNet.Master)
{
Logging.Warning($"Received config packet from player #{val.PlayerSlotIndex() + 1} but they're not the host!");
}
else
{
Logging.Debug($"Config packet received from host player #{val.PlayerSlotIndex() + 1}");
Configuration.RemoteConfig.LoadRemoteConfig(packet);
Plugin.GlowstickTweaks.GlowstickPatches.OnReceiveConfigPacket();
}
}
}
}