using System;
using System.Collections;
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.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("JinxIt")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("JinxIt")]
[assembly: AssemblyTitle("JinxIt")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace JinxIt;
[BepInPlugin("tchernobill.jinxit", "JinxIt", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
public const string GUID = "tchernobill.jinxit";
public const string NAME = "JinxIt";
public const string VERSION = "1.0.0";
internal static ManualLogSource Log;
private void Awake()
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
Log = ((BaseUnityPlugin)this).Logger;
new Harmony("tchernobill.jinxit").PatchAll(typeof(JinxPatches));
TestHarness.StartIfRequested(((Component)this).gameObject);
}
}
[HarmonyPatch]
internal static class JinxPatches
{
[HarmonyPrefix]
[HarmonyPatch(typeof(AddStatusEffectRandom), "TryTriggerConditions")]
private static void BeforeDraw(AddStatusEffectRandom __instance, Character ___m_affectedCharacter, out int __state)
{
__state = __instance.ForceID;
if (__state < 0)
{
__instance.ForceID = PickMissing(__instance.Statuses, (___m_affectedCharacter != null) ? ___m_affectedCharacter.StatusEffectMngr : null);
}
}
[HarmonyFinalizer]
[HarmonyPatch(typeof(AddStatusEffectRandom), "TryTriggerConditions")]
private static void AfterDraw(AddStatusEffectRandom __instance, int __state)
{
__instance.ForceID = __state;
}
internal static int PickMissing(StatusEffect[] statuses, StatusEffectManager target)
{
if (statuses == null || (Object)(object)target == (Object)null)
{
return -1;
}
List<int> list = new List<int>(statuses.Length);
for (int i = 0; i < statuses.Length; i++)
{
if ((Object)(object)statuses[i] != (Object)null && (Object)(object)target.GetStatusEffectOfName(statuses[i].IdentifierName) == (Object)null)
{
list.Add(i);
}
}
if (list.Count == 0 || list.Count == statuses.Length)
{
return -1;
}
return list[Random.Range(0, list.Count)];
}
}
public class TestHarness : MonoBehaviour
{
private const int Draws = 400;
private static readonly MethodInfo s_tryTrigger = AccessTools.Method(typeof(AddStatusEffectRandom), "TryTriggerConditions", Type.EmptyTypes, (Type[])null);
private static readonly FieldRef<Effect, Character> s_affected = AccessTools.FieldRefAccess<Effect, Character>("m_affectedCharacter");
private static readonly FieldRef<AddStatusEffectRandom, int> s_id = AccessTools.FieldRefAccess<AddStatusEffectRandom, int>("m_id");
public static void StartIfRequested(GameObject host)
{
if (UnityEngineExtensions.Contains<string>(Environment.GetCommandLineArgs(), "--jinx-test"))
{
host.AddComponent<TestHarness>();
}
}
private void Start()
{
((MonoBehaviour)this).StartCoroutine(Run());
}
private static void Log(string message)
{
Plugin.Log.LogMessage((object)("jinx-test: " + message));
}
private static void Fail(string reason)
{
Plugin.Log.LogError((object)("jinx-test: FAILED " + reason));
}
private static IEnumerator WaitRealtime(float seconds)
{
float end = Time.realtimeSinceStartup + seconds;
while (Time.realtimeSinceStartup < end)
{
yield return null;
}
}
private static void SaveIcon(Sprite sprite)
{
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Expected O, but got Unknown
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)sprite == (Object)null)
{
Log("Jinx has no icon");
return;
}
Texture2D texture = sprite.texture;
RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
Graphics.Blit((Texture)(object)texture, temporary);
RenderTexture active = RenderTexture.active;
RenderTexture.active = temporary;
Rect textureRect = sprite.textureRect;
Texture2D val = new Texture2D((int)((Rect)(ref textureRect)).width, (int)((Rect)(ref textureRect)).height, (TextureFormat)5, false);
val.ReadPixels(textureRect, 0, 0);
val.Apply();
RenderTexture.active = active;
RenderTexture.ReleaseTemporary(temporary);
string text = Path.Combine(Paths.BepInExRootPath, "JinxItTest");
Directory.CreateDirectory(text);
string text2 = Path.Combine(text, "jinx_icon.png");
File.WriteAllBytes(text2, ImageConversion.EncodeToPNG(val));
Log($"icon {((Object)sprite).name} ({((Texture)texture).width}x{((Texture)texture).height}, rect {textureRect}) saved to {text2}");
}
private static string PathOf(Transform t)
{
if (!((Object)(object)t.parent == (Object)null))
{
return PathOf(t.parent) + "/" + ((Object)t).name;
}
return ((Object)t).name;
}
private IEnumerator Run()
{
Character character = null;
float deadline = Time.realtimeSinceStartup + 900f;
while ((Object)(object)character == (Object)null)
{
if (Time.realtimeSinceStartup > deadline)
{
Fail("no local character after 900 s");
yield break;
}
yield return null;
if (!((Object)(object)NetworkLevelLoader.Instance == (Object)null) && NetworkLevelLoader.Instance.IsOverallLoadingDone)
{
try
{
CharacterManager instance = CharacterManager.Instance;
character = ((instance != null) ? instance.GetFirstLocalCharacter() : null);
}
catch (NullReferenceException)
{
}
}
}
yield return WaitRealtime(3f);
Log("local character " + character.Name);
Item val = ((IEnumerable<Item>)((Dictionary<string, Item>)AccessTools.Field(typeof(ResourcesPrefabManager), "ITEM_PREFABS").GetValue(null)).Values).FirstOrDefault((Func<Item, bool>)((Item i) => (Object)(object)i != (Object)null && i.Name == "Jinx"));
if ((Object)(object)val == (Object)null)
{
Fail("no item named Jinx");
yield break;
}
Log($"Jinx = item {val.ItemID} ({((object)val).GetType().Name})");
SaveIcon(val.ItemIcon);
List<AddStatusEffectRandom> list = new List<AddStatusEffectRandom>();
ShootProjectile[] componentsInChildren = ((Component)val).GetComponentsInChildren<ShootProjectile>(true);
foreach (ShootProjectile val2 in componentsInChildren)
{
if ((Object)(object)val2.BaseProjectile != (Object)null)
{
list.AddRange(((Component)val2.BaseProjectile).GetComponentsInChildren<AddStatusEffectRandom>(true));
}
}
AddStatusEffectRandom[] array = Resources.FindObjectsOfTypeAll<AddStatusEffectRandom>();
foreach (AddStatusEffectRandom val3 in array)
{
object[] obj = new object[4]
{
PathOf(((Component)val3).transform),
null,
null,
null
};
Scene scene = ((Component)val3).gameObject.scene;
obj[1] = ((Scene)(ref scene)).name;
obj[2] = val3.ForceID;
obj[3] = ((AddStatusEffect)val3).BaseChancesToContract;
Log(string.Format("in memory: {0} (scene '{1}'), ForceID {2}, chances {3}, ", obj) + "statuses " + string.Join(", ", val3.Statuses.Select((StatusEffect s) => (!((Object)(object)s == (Object)null)) ? (s.IdentifierName + " [" + s.EffectFamily?.Name + "]") : "null")));
}
if (list.Count == 0)
{
Fail("no AddStatusEffectRandom on Jinx's projectile");
yield break;
}
AddStatusEffectRandom effect = list[0];
StatusEffect[] hexes = effect.Statuses;
StatusEffectManager statuses = character.StatusEffectMngr;
string problem = null;
StatusEffect[] array3;
for (int k = 0; k <= hexes.Length; k++)
{
if (problem != null)
{
break;
}
bool[] array2 = ((k == 0 || k == hexes.Length) ? new bool[1] : new bool[2] { false, true });
foreach (bool flag in array2)
{
HashSet<int> present = new HashSet<int>(Enumerable.Range(flag ? (hexes.Length - k) : 0, k));
array3 = hexes;
foreach (StatusEffect val4 in array3)
{
statuses.RemoveStatusWithIdentifierName(val4.IdentifierName);
}
foreach (int item in present)
{
statuses.AddStatusEffect(hexes[item], (Character)null);
}
yield return null;
int[] landed = new int[hexes.Length];
s_affected.Invoke((Effect)(object)effect) = character;
for (int num3 = 0; num3 < 400; num3++)
{
s_tryTrigger.Invoke(effect, null);
landed[s_id.Invoke(effect)]++;
}
string arg = string.Join(",", from h in hexes
where (Object)(object)statuses.GetStatusEffectOfName(h.IdentifierName) != (Object)null
select h.IdentifierName);
Log($"{k} on target [{arg}]: " + string.Join(", ", hexes.Select((StatusEffect h, int i) => $"{h.IdentifierName} {landed[i]}")) + $", ForceID back to {effect.ForceID}");
bool flag2 = k == 0 || k == hexes.Length;
for (int num4 = 0; num4 < hexes.Length; num4++)
{
if (problem != null)
{
break;
}
bool flag3 = flag2 || !present.Contains(num4);
if (flag3 && landed[num4] == 0)
{
problem = $"{hexes[num4].IdentifierName} never drawn with {k} hexes on the target";
}
else if (!flag3 && landed[num4] > 0)
{
problem = $"{hexes[num4].IdentifierName} drawn {landed[num4]} times while already on the target";
}
}
if (problem == null && present.Count((int i) => (Object)(object)statuses.GetStatusEffectOfName(hexes[i].IdentifierName) == (Object)null) > 0)
{
problem = $"could not put {k} hexes on the target";
}
if (problem == null && effect.ForceID != -1)
{
problem = $"ForceID left at {effect.ForceID}";
}
if (problem != null)
{
break;
}
}
}
array3 = hexes;
foreach (StatusEffect val5 in array3)
{
statuses.RemoveStatusWithIdentifierName(val5.IdentifierName);
}
if (problem != null)
{
Fail(problem);
}
else
{
Log("done");
}
}
}