using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using BepInEx;
using Microsoft.CodeAnalysis;
using MoreCustomizations;
using MoreCustomizations.Data;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("JojoHats")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.5.2.0")]
[assembly: AssemblyInformationalVersion("0.5.2+25b3a737a1724d093b59586ae47f5c8abceca380")]
[assembly: AssemblyProduct("JojoHats")]
[assembly: AssemblyTitle("JojoHats")]
[assembly: AssemblyVersion("0.5.2.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[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]
[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;
}
}
[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 JojoHats
{
internal static class CatalogMerge
{
internal static IReadOnlyDictionary<TKey, IReadOnlyList<TValue>> Append<TKey, TValue>(IReadOnlyDictionary<TKey, IReadOnlyList<TValue>> existing, TKey hatType, IReadOnlyList<TValue> additions, Func<TValue, string> identity) where TKey : notnull
{
if (existing == null)
{
throw new ArgumentNullException("existing");
}
if (hatType == null)
{
throw new ArgumentNullException("hatType");
}
if (additions == null)
{
throw new ArgumentNullException("additions");
}
if (identity == null)
{
throw new ArgumentNullException("identity");
}
List<KeyValuePair<string, TValue>> list = new List<KeyValuePair<string, TValue>>(additions.Count);
HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
for (int i = 0; i < additions.Count; i++)
{
TValue val = additions[i];
if (val == null)
{
throw new ArgumentException("An added cosmetic cannot be null.", "additions");
}
string text = identity(val);
if (string.IsNullOrWhiteSpace(text))
{
throw new ArgumentException("Every added cosmetic needs a non-empty identity.", "additions");
}
if (!hashSet.Add(text))
{
throw new ArgumentException("Duplicate added cosmetic identity: " + text, "additions");
}
list.Add(new KeyValuePair<string, TValue>(text, val));
}
IReadOnlyList<TValue> value;
bool num = existing.TryGetValue(hatType, out value);
if (num && value == null)
{
throw new ArgumentException("The existing hat category cannot be null.", "existing");
}
HashSet<string> hashSet2 = new HashSet<string>(StringComparer.Ordinal);
List<TValue> list2 = new List<TValue>(num ? (value.Count + list.Count) : list.Count);
if (num)
{
foreach (TValue item in value)
{
if (item == null)
{
throw new ArgumentException("An existing hat cannot be null.", "existing");
}
string text2 = identity(item);
if (!string.IsNullOrWhiteSpace(text2))
{
hashSet2.Add(text2);
}
list2.Add(item);
}
}
int count = list2.Count;
foreach (KeyValuePair<string, TValue> item2 in list)
{
if (hashSet2.Add(item2.Key))
{
list2.Add(item2.Value);
}
}
if (list2.Count == count)
{
return existing;
}
Dictionary<TKey, IReadOnlyList<TValue>> dictionary = new Dictionary<TKey, IReadOnlyList<TValue>>();
foreach (KeyValuePair<TKey, IReadOnlyList<TValue>> item3 in existing)
{
dictionary.Add(item3.Key, item3.Value);
}
dictionary[hatType] = list2.AsReadOnly();
return new ReadOnlyDictionary<TKey, IReadOnlyList<TValue>>(dictionary);
}
}
internal static class NetworkIndexSmoke
{
private static readonly string[] HatNames = new string[6] { "jojo_mvp_01_jotaro_cap", "jojo_mvp_02_josuke_pompadour", "jojo_mvp_03_giorno_rolls", "jojo_mvp_04_jonathan_hair", "jojo_mvp_05_jolyne_buns", "jojo_mvp_06_joseph_hair" };
private static readonly string[] FieldNames = new string[8] { "currentSkin", "currentAccessory", "currentEyes", "currentMouth", "currentOutfit", "currentHat", "currentSash", "currentMedal" };
internal static void Verify(List<string> results, int firstJojoRuntimeIndex)
{
if (results == null)
{
throw new ArgumentNullException("results");
}
FieldInfo? obj = typeof(Customization).BaseType?.GetField("_instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingFieldException("Customization singleton _instance");
FieldInfo fieldInfo = typeof(Customization).BaseType?.GetField("m_shuttingDown", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingFieldException("Customization singleton m_shuttingDown");
object? value = obj.GetValue(null);
Customization val = (Customization)((value is Customization) ? value : null);
if (val != null)
{
Object val2 = (Object)(object)((val is Object) ? val : null);
if (val2 != null && Object.op_Implicit(val2) && !(bool)fieldInfo.GetValue(null))
{
int baseHatCount = MoreCustomizationsPlugin.BaseHatCount;
int overrideHatCount = MoreCustomizationsPlugin.OverrideHatCount;
if (baseHatCount <= 0 || overrideHatCount < 0 || firstJojoRuntimeIndex < baseHatCount + overrideHatCount)
{
throw new InvalidOperationException("Local serialization test has invalid vanilla/override hat bounds.");
}
int num = firstJojoRuntimeIndex - overrideHatCount;
if (val.hats == null || num < 0 || num > val.hats.Length - HatNames.Length)
{
throw new InvalidOperationException("JOJO runtime indices do not fit the real passport catalog.");
}
for (int i = 0; i < HatNames.Length; i++)
{
if (!Object.op_Implicit((Object)(object)val.hats[num + i]) || ((Object)val.hats[num + i]).name != HatNames[i])
{
throw new InvalidOperationException("JOJO menu/runtime index mapping differs at ordinal " + i);
}
}
string[] array = new string[7] { "skins", "accessories", "eyes", "mouths", "fits", "sashes", "medals" };
foreach (string text in array)
{
if (!(typeof(Customization).GetField(text)?.GetValue(val) is CustomizationOption[] array2) || array2.Length == 0)
{
throw new InvalidOperationException("Real customization category unavailable: " + text);
}
}
Type typeFromHandle = typeof(CharacterCustomizationData);
MethodInfo methodInfo = typeFromHandle.GetMethod("Serialize", BindingFlags.Instance | BindingFlags.Public) ?? throw new MissingMethodException(typeFromHandle.FullName, "Serialize");
MethodInfo methodInfo2 = typeFromHandle.GetMethod("Deserialize", BindingFlags.Instance | BindingFlags.Public) ?? throw new MissingMethodException(typeFromHandle.FullName, "Deserialize");
Type parameterType = methodInfo.GetParameters()[0].ParameterType;
Type parameterType2 = methodInfo2.GetParameters()[0].ParameterType;
ConstructorInfo constructorInfo = parameterType2.GetConstructor(new Type[1] { parameterType }) ?? throw new MissingMethodException(parameterType2.FullName, ".ctor(BinarySerializer)");
PropertyInfo propertyInfo = parameterType.GetProperty("Position") ?? throw new MissingMemberException(parameterType.FullName, "Position");
FieldInfo[] array3 = new FieldInfo[FieldNames.Length];
for (int k = 0; k < array3.Length; k++)
{
array3[k] = typeFromHandle.GetField(FieldNames[k], BindingFlags.Instance | BindingFlags.Public) ?? throw new MissingFieldException(typeFromHandle.FullName, FieldNames[k]);
if (array3[k].FieldType != typeof(int))
{
throw new InvalidOperationException("Game cosmetic format changed: " + FieldNames[k]);
}
}
for (int l = 0; l < HatNames.Length; l++)
{
int num2 = checked(firstJojoRuntimeIndex + l);
object obj2 = Activator.CreateInstance(typeFromHandle);
object obj3 = Activator.CreateInstance(typeFromHandle);
array3[5].SetValue(obj2, num2);
object obj4 = Activator.CreateInstance(parameterType);
try
{
methodInfo.Invoke(obj2, new object[1] { obj4 });
if ((int)propertyInfo.GetValue(obj4) != FieldNames.Length * 4)
{
throw new InvalidOperationException("Game cosmetic serialization byte count changed.");
}
object obj5 = constructorInfo.Invoke(new object[1] { obj4 });
methodInfo2.Invoke(obj3, new object[1] { obj5 });
for (int m = 0; m < array3.Length; m++)
{
int num3 = ((m == 5) ? num2 : 0);
if ((int)array3[m].GetValue(obj2) != num3 || (int)array3[m].GetValue(obj3) != num3)
{
throw new InvalidOperationException("Local cosmetic round-trip changed " + FieldNames[m] + " for " + HatNames[l]);
}
}
}
finally
{
((IDisposable)obj4).Dispose();
}
}
results.Add("localGameSerializationRoundTrip=6/6; actual Serialize/Deserialize+CorrectValues; runtimeIndices=" + firstJojoRuntimeIndex + ".." + (firstJojoRuntimeIndex + HatNames.Length - 1) + "; saves=untouched; packetsSent=0; twoClientMultiplayer=NOT_TESTED");
return;
}
}
throw new InvalidOperationException("Local serialization test needs the real Customization singleton.");
}
}
[BepInPlugin("midor.peak.jojohats", "JOJO Scout Hats", "0.5.2")]
[BepInDependency("MoreCustomizations", "1.1.10")]
public sealed class Plugin : BaseUnityPlugin
{
internal const string Version = "0.5.2";
private const string Prefix = "jojo_mvp_";
private static readonly string[] Ids = new string[6] { "01_jotaro_cap", "02_josuke_pompadour", "03_giorno_rolls", "04_jonathan_hair", "05_jolyne_buns", "06_joseph_hair" };
private readonly List<Object> ownedAssets = new List<Object>();
private readonly List<CustomHat_V1> hats = new List<CustomHat_V1>();
private GameObject? templates;
private IReadOnlyDictionary<Type, IReadOnlyList<CustomizationData>>? originalCatalog;
private string contentFingerprint = "";
private bool catalogPublished;
private void Awake()
{
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Expected O, but got Unknown
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0104: Expected O, but got Unknown
//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
//IL_01be: Unknown result type (might be due to invalid IL or missing references)
try
{
string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "assets");
IReadOnlyDictionary<Type, IReadOnlyList<CustomizationData>> readOnlyDictionary = (originalCatalog = MoreCustomizationsPlugin.AllCustomizationsData ?? throw new InvalidOperationException("More Customizations did not initialize. Reinstall the official More Customizations dependency in your mod-manager profile and keep its built-in.pcab. Do not run the old JOJO-only patch script. No other cosmetics or files were changed."));
Texture2D val = LoadTexture(Path.Combine(text, "palette.png"));
((Texture)val).filterMode = (FilterMode)0;
templates = new GameObject("JOJO Hat Templates");
templates.SetActive(false);
Object.DontDestroyOnLoad((Object)(object)templates);
string[] ids = Ids;
foreach (string text2 in ids)
{
string path = Path.Combine(text, text2);
MeshData meshData = JsonUtility.FromJson<MeshData>(File.ReadAllText(Path.Combine(path, "mesh.json")));
Validate(meshData, text2);
Mesh val2 = MakeMesh(meshData);
Texture2D val3 = val;
if (!string.IsNullOrEmpty(meshData.texture))
{
val3 = LoadTexture(Path.Combine(path, meshData.texture));
((Texture)val3).filterMode = (FilterMode)1;
}
GameObject val4 = new GameObject("jojo_mvp_" + text2);
val4.transform.SetParent(templates.transform, false);
val4.AddComponent<MeshFilter>().sharedMesh = val2;
val4.AddComponent<MeshRenderer>();
CustomHat_V1 val5 = ScriptableObject.CreateInstance<CustomHat_V1>();
ownedAssets.Add((Object)(object)val5);
((Object)val5).name = "jojo_mvp_" + text2;
Set(val5, "Icon", LoadTexture(Path.Combine(path, "icon.png")));
Set(val5, "Prefab", val4);
Set(val5, "MainTexture", val3);
Set(val5, "SubTexture", val3);
Set(val5, "PositionOffset", Vector3.zero);
Set(val5, "EulerAngleOffset", Vector3.zero);
if (!((CustomizationData)val5).IsValid)
{
throw new InvalidDataException("Hat validation failed: " + text2);
}
hats.Add(val5);
((BaseUnityPlugin)this).Logger.LogInfo((object)$"Prepared {text2}: {val2.vertexCount} vertices, {meshData.triangles.Length / 3} triangles");
}
IReadOnlyDictionary<Type, IReadOnlyList<CustomizationData>> readOnlyDictionary2 = CatalogMerge.Append(readOnlyDictionary, (Type)50, hats.Cast<CustomizationData>().ToArray(), (CustomizationData item) => ((Object)item).name);
contentFingerprint = Fingerprint(text);
SetStatic(typeof(MoreCustomizationsPlugin), "AllCustomizationsData", readOnlyDictionary2);
catalogPublished = true;
IReadOnlyList<CustomizationData> value;
int num = (readOnlyDictionary.TryGetValue((Type)50, out value) ? value.Count : 0);
((BaseUnityPlugin)this).Logger.LogInfo((object)$"JOJO_REGISTERED=6; mode=append; existingHats={num}; totalHats={readOnlyDictionary2[(Type)50].Count}; contentSHA256={contentFingerprint}");
((BaseUnityPlugin)this).Logger.LogInfo((object)"Other cosmetics preserved. For multiplayer, every player needs the same complete cosmetic profile and versions; mesh files are not sent over the network.");
if (Environment.GetCommandLineArgs().Contains("--jojo-smoke-test"))
{
File.WriteAllLines(Path.Combine(Paths.BepInExRootPath, "jojo-smoke.txt"), new string[2] { "version=0.5.2", "result=PENDING" });
((MonoBehaviour)this).StartCoroutine(SmokeTest());
}
}
catch (Exception ex)
{
((BaseUnityPlugin)this).Logger.LogError((object)((catalogPublished ? "JOJO post-registration diagnostic failed: " : "JOJO initialization aborted; other cosmetics left unchanged: ") + ex));
if (!catalogPublished)
{
if (Object.op_Implicit((Object)(object)templates))
{
Object.Destroy((Object)(object)templates);
}
foreach (Object ownedAsset in ownedAssets)
{
if (Object.op_Implicit(ownedAsset))
{
Object.Destroy(ownedAsset);
}
}
((Behaviour)this).enabled = false;
}
if (Environment.GetCommandLineArgs().Contains("--jojo-smoke-test"))
{
File.WriteAllLines(Path.Combine(Paths.BepInExRootPath, "jojo-smoke.txt"), new string[2]
{
"version=0.5.2",
"result=FAIL: " + ex
});
if (Environment.GetCommandLineArgs().Contains("--jojo-test-quit"))
{
Application.Quit();
}
}
}
}
private static string Fingerprint(string root)
{
using SHA256 sHA = SHA256.Create();
List<string> list = new List<string>();
foreach (string item in new string[1] { "palette.png" }.Concat(Ids.SelectMany((string id) => new string[2]
{
id + "/mesh.json",
id + "/icon.png"
})))
{
list.Add(item + ":" + BitConverter.ToString(sHA.ComputeHash(File.ReadAllBytes(Path.Combine(root, item)))).Replace("-", ""));
}
return BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(string.Join("\n", list)))).Replace("-", "").ToLowerInvariant();
}
private Texture2D LoadTexture(string path)
{
//IL_0004: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: Expected O, but got Unknown
Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
ownedAssets.Add((Object)(object)val);
if (!ImageConversion.LoadImage(val, File.ReadAllBytes(path)))
{
throw new InvalidDataException("Cannot decode " + path);
}
((Object)val).name = Path.GetFileName(path);
((Texture)val).wrapMode = (TextureWrapMode)1;
return val;
}
private Mesh MakeMesh(MeshData data)
{
//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_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_00b1: Expected O, but got Unknown
//IL_0144: Unknown result type (might be due to invalid IL or missing references)
//IL_0149: Unknown result type (might be due to invalid IL or missing references)
int num = data.positions.Length / 3;
Vector3[] array = (Vector3[])(object)new Vector3[num];
Vector2[] array2 = (Vector2[])(object)new Vector2[num];
Color[] array3 = (Color[])(object)new Color[num];
for (int i = 0; i < num; i++)
{
array[i] = new Vector3(data.positions[i * 3], data.positions[i * 3 + 1], data.positions[i * 3 + 2]);
array2[i] = new Vector2(data.uv[i * 2], data.uv[i * 2 + 1]);
array3[i] = Color.white;
}
Mesh val = new Mesh
{
name = "jojo_mvp_" + data.name
};
ownedAssets.Add((Object)(object)val);
val.vertices = array;
val.uv = array2;
val.colors = array3;
val.subMeshCount = 2;
val.SetTriangles(data.triangles, 0);
val.SetTriangles(Array.Empty<int>(), 1);
if (data.normals != null && data.normals.Length == num * 3)
{
Vector3[] array4 = (Vector3[])(object)new Vector3[num];
for (int j = 0; j < num; j++)
{
array4[j] = new Vector3(data.normals[j * 3], data.normals[j * 3 + 1], data.normals[j * 3 + 2]);
}
val.normals = array4;
}
else
{
val.RecalculateNormals();
}
val.RecalculateBounds();
return val;
}
internal static void Validate(MeshData data, string expected)
{
if (data == null || data.name != expected || data.positions == null || data.triangles == null || data.uv == null)
{
throw new InvalidDataException("Missing or mismatched mesh: " + expected);
}
int n = data.positions.Length / 3;
if (!string.IsNullOrEmpty(data.texture) && data.texture != "albedo.png")
{
throw new InvalidDataException("Unsupported texture path: " + expected);
}
if (data.normals != null && data.normals.Length != 0)
{
if (data.normals.Length != data.positions.Length || data.normals.Any((float x) => float.IsNaN(x) || float.IsInfinity(x)))
{
throw new InvalidDataException("Invalid normal data: " + expected);
}
for (int num = 0; num < data.normals.Length; num += 3)
{
float num2 = data.normals[num] * data.normals[num] + data.normals[num + 1] * data.normals[num + 1] + data.normals[num + 2] * data.normals[num + 2];
if (num2 < 0.98f || num2 > 1.02f)
{
throw new InvalidDataException("Non-unit normal: " + expected);
}
}
}
if (n == 0 || n > 65000 || data.positions.Length % 3 != 0 || data.uv.Length != n * 2 || data.triangles.Length == 0 || data.triangles.Length % 3 != 0)
{
throw new InvalidDataException("Invalid mesh dimensions: " + expected);
}
if (data.positions.Any((float x) => float.IsNaN(x) || float.IsInfinity(x) || Math.Abs(x) > 8f) || data.uv.Any((float x) => float.IsNaN(x) || float.IsInfinity(x) || x < 0f || x > 1f) || data.triangles.Any((int i) => i < 0 || i >= n))
{
throw new InvalidDataException("Invalid mesh coordinates or indices: " + expected);
}
}
private static void Set(object target, string name, object value)
{
((target.GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public) ?? throw new MissingMemberException(target.GetType().FullName, name)).GetSetMethod(nonPublic: true) ?? throw new MissingMethodException(name)).Invoke(target, new object[1] { value });
}
private static void SetStatic(Type type, string name, object value)
{
((type.GetProperty(name, BindingFlags.Static | BindingFlags.Public) ?? throw new MissingMemberException(type.FullName, name)).GetSetMethod(nonPublic: true) ?? throw new MissingMethodException(name)).Invoke(null, new object[1] { value });
}
private IEnumerator SmokeTest()
{
yield return (object)new WaitForSecondsRealtime(18f);
List<string> list = new List<string>
{
"version=0.5.2",
"registered=" + hats.Count,
"contentSHA256=" + contentFingerprint
};
IReadOnlyDictionary<Type, IReadOnlyList<CustomizationData>> allCustomizationsData = MoreCustomizationsPlugin.AllCustomizationsData;
list.Add("customNonHatEntries=" + allCustomizationsData.Where((KeyValuePair<Type, IReadOnlyList<CustomizationData>> p) => (int)p.Key != 50).Sum((KeyValuePair<Type, IReadOnlyList<CustomizationData>> p) => p.Value.Count));
list.Add("customHatEntries=" + allCustomizationsData[(Type)50].Count);
list.Add("pcabFiles=" + Directory.GetFiles(Paths.PluginPath, "*.pcab", SearchOption.AllDirectories).Length);
try
{
foreach (CustomHat_V1 hat in hats)
{
GameObject val = Object.Instantiate<GameObject>(hat.Prefab);
val.SetActive(true);
MeshRenderer component = val.GetComponent<MeshRenderer>();
Mesh sharedMesh = val.GetComponent<MeshFilter>().sharedMesh;
bool flag = (Object)(object)hat.MainTexture == (Object)(object)hats[0].MainTexture && hat.MainTexture.height == 16 && (int)hat.MainTexture.filterMode == 0;
bool flag2 = sharedMesh.normals.Length == sharedMesh.vertexCount;
list.Add(((Object)hat).name + ": active=" + val.activeSelf + ", vertices=" + sharedMesh.vertexCount + ", renderer=" + ((Object)(object)component != (Object)null));
Object.Destroy((Object)(object)val);
if (!flag || !flag2)
{
throw new InvalidOperationException("Shared palette/normal assertion failed: " + ((Object)hat).name);
}
}
Shader val2 = Shader.Find("W/Character");
list.Add("characterShader=" + ((Object)(object)val2 != (Object)null));
list.Add("runtime=" + Application.unityVersion);
if (!Object.op_Implicit((Object)(object)val2))
{
throw new InvalidOperationException("Game character shader missing.");
}
VerifyPreservedCatalog(allCustomizationsData);
if (CatalogMerge.Append(allCustomizationsData, (Type)50, hats.Cast<CustomizationData>().ToArray(), (CustomizationData item) => ((Object)item).name)[(Type)50].Count != allCustomizationsData[(Type)50].Count)
{
throw new InvalidOperationException("Duplicate registration changed the catalog.");
}
list.Add("existingCatalogPreserved=PASS; duplicateRegistration=PASS");
IntegrationSmoke(list);
list.Add("result=PASS");
}
catch (Exception ex)
{
list.Add("result=FAIL: " + ex);
((BaseUnityPlugin)this).Logger.LogError((object)("JOJO integration check: " + ex));
}
File.WriteAllLines(Path.Combine(Paths.BepInExRootPath, "jojo-smoke.txt"), list);
((BaseUnityPlugin)this).Logger.LogInfo((object)("JOJO_SMOKE_FINISHED: " + list.Last()));
if (Environment.GetCommandLineArgs().Contains("--jojo-test-quit"))
{
Application.Quit();
}
}
private void VerifyPreservedCatalog(IReadOnlyDictionary<Type, IReadOnlyList<CustomizationData>> actual)
{
//IL_002e: 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_005c: 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)
//IL_00e2: Invalid comparison between Unknown and I4
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
if (originalCatalog == null)
{
throw new InvalidOperationException("Missing pre-registration snapshot.");
}
foreach (KeyValuePair<Type, IReadOnlyList<CustomizationData>> item in originalCatalog)
{
if (!actual.TryGetValue(item.Key, out IReadOnlyList<CustomizationData> value) || value.Count < item.Value.Count)
{
throw new InvalidOperationException("Existing category removed or shortened: " + ((object)item.Key/*cast due to .constrained prefix*/).ToString());
}
for (int i = 0; i < item.Value.Count; i++)
{
if (value[i] != item.Value[i])
{
throw new InvalidOperationException("Existing cosmetic changed index: " + ((object)item.Key/*cast due to .constrained prefix*/).ToString() + "/" + i);
}
}
if ((int)item.Key != 50 && value.Count != item.Value.Count)
{
throw new InvalidOperationException("Unrelated cosmetic category changed.");
}
}
string[] ids = Ids;
foreach (string id in ids)
{
if (actual[(Type)50].Count((CustomizationData item) => ((Object)item).name == "jojo_mvp_" + id) != 1)
{
throw new InvalidOperationException("Missing or duplicate JOJO hat: " + id);
}
}
}
private void IntegrationSmoke(List<string> results)
{
//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
//IL_03be: Unknown result type (might be due to invalid IL or missing references)
//IL_03e3: Unknown result type (might be due to invalid IL or missing references)
//IL_03e8: Unknown result type (might be due to invalid IL or missing references)
//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
//IL_0300: Unknown result type (might be due to invalid IL or missing references)
//IL_0321: Unknown result type (might be due to invalid IL or missing references)
//IL_0326: Unknown result type (might be due to invalid IL or missing references)
//IL_045b: Unknown result type (might be due to invalid IL or missing references)
//IL_0460: Unknown result type (might be due to invalid IL or missing references)
//IL_0481: Unknown result type (might be due to invalid IL or missing references)
//IL_0486: Unknown result type (might be due to invalid IL or missing references)
//IL_0513: Unknown result type (might be due to invalid IL or missing references)
//IL_051a: Expected O, but got Unknown
GameObject obj = Resources.Load<GameObject>("Character");
if (!Object.op_Implicit((Object)(object)obj))
{
throw new InvalidOperationException("Game Character prefab not found.");
}
Type type = typeof(MoreCustomizationsPlugin).Assembly.GetType("MoreCustomizations.Patches.CharacterCustomizationPatch", throwOnError: true);
Type type2 = typeof(MoreCustomizationsPlugin).Assembly.GetType("MoreCustomizations.Patches.PassportManagerPatch", throwOnError: true);
FieldInfo fieldInfo = type.GetField("_characterShader", BindingFlags.Static | BindingFlags.NonPublic) ?? throw new MissingFieldException(type.FullName, "_characterShader");
FieldInfo fieldInfo2 = type2.GetField("materialTemplate", BindingFlags.Static | BindingFlags.NonPublic) ?? throw new MissingFieldException(type2.FullName, "materialTemplate");
object value = fieldInfo.GetValue(null);
object value2 = fieldInfo2.GetValue(null);
HashSet<int> hashSet = new HashSet<int>(from material in Resources.FindObjectsOfTypeAll<Material>()
select ((Object)material).GetInstanceID());
HashSet<int> optionsBeforePassport = null;
GameObject val = Object.Instantiate<GameObject>(obj, templates.transform, false);
GameObject val2 = null;
int baseHatCount = MoreCustomizationsPlugin.BaseHatCount;
int overrideHatCount = MoreCustomizationsPlugin.OverrideHatCount;
try
{
((Object)val).name = "JOJO isolated prefab integration";
CharacterCustomization component = val.GetComponent<CharacterCustomization>();
if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component.refs))
{
throw new InvalidOperationException("CharacterCustomization refs missing.");
}
int num = component.refs.playerHats.Length;
type.GetMethod("Awake", BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, new object[1] { component });
Renderer[] array = component.refs.playerHats.Where((Renderer r) => Object.op_Implicit((Object)(object)r) && ((Object)r).name.StartsWith("jojo_mvp_", StringComparison.Ordinal)).ToArray();
if (array.Length != 6)
{
throw new InvalidOperationException("Not all six hats attached to actual Character prefab.");
}
int count = MoreCustomizationsPlugin.AllCustomizationsData[(Type)50].Count;
if (component.refs.playerHats.Length < num + count)
{
throw new InvalidOperationException("Existing custom hat renderers missing.");
}
results.Add($"actualCharacterPrefab: baseRenderers={num}; jojoRenderers={array.Length}");
Renderer[] array2 = array;
foreach (Renderer val3 in array2)
{
Mesh sharedMesh = ((Component)val3).GetComponent<MeshFilter>().sharedMesh;
if (sharedMesh.normals.Length != sharedMesh.vertexCount || sharedMesh.normals.Any((Vector3 n) => ((Vector3)(ref n)).sqrMagnitude < 0.98f || ((Vector3)(ref n)).sqrMagnitude > 1.02f))
{
throw new InvalidOperationException("Missing or invalid authored normals: " + ((Object)val3).name);
}
if (val3.sharedMaterials.Any((Material m) => !Object.op_Implicit((Object)(object)m) || (Object)(object)m.shader != (Object)(object)Shader.Find("W/Character")))
{
throw new InvalidOperationException("Wrong renderer shader: " + ((Object)val3).name);
}
results.Add(((Object)val3).name + ": headLocalPosition=" + ((object)((Component)val3).transform.localPosition/*cast due to .constrained prefix*/).ToString() + "; rotation=" + ((object)((Component)val3).transform.localEulerAngles/*cast due to .constrained prefix*/).ToString());
results.Add(((Object)val3).name + ": authoredNormals=" + sharedMesh.normals.Length);
}
results.Add("headTransform=" + (object)component.refs.hatTransform);
results.Add("bodyTransform=" + ((object)((Component)component.refs.mainRenderer).transform.position/*cast due to .constrained prefix*/).ToString() + "; scale=" + ((object)((Component)component.refs.mainRenderer).transform.lossyScale/*cast due to .constrained prefix*/).ToString());
foreach (Renderer item2 in component.refs.playerHats.Take(8))
{
if (Object.op_Implicit((Object)(object)item2))
{
results.Add("baseHat=" + ((Object)item2).name + "; local=" + ((object)((Component)item2).transform.localPosition/*cast due to .constrained prefix*/).ToString() + "; world=" + ((object)((Component)item2).transform.position/*cast due to .constrained prefix*/).ToString());
}
}
if (Environment.GetCommandLineArgs().Contains("--jojo-network-index-test"))
{
NetworkIndexSmoke.Verify(results, Array.FindIndex(component.refs.playerHats, (Renderer renderer) => Object.op_Implicit((Object)(object)renderer) && ((Object)renderer).name == "jojo_mvp_" + Ids[0]));
}
else
{
results.Add("localGameSerializationRoundTrip=NOT_RUN; requires real initialized passport; twoClientMultiplayer=NOT_TESTED");
}
val2 = new GameObject("JOJO isolated passport registration");
val2.transform.SetParent(templates.transform, false);
object customization = val2.AddComponent(typeof(Customization));
FieldInfo[] fields = typeof(Customization).GetFields(BindingFlags.Instance | BindingFlags.Public);
foreach (FieldInfo fieldInfo3 in fields)
{
if (fieldInfo3.FieldType == typeof(CustomizationOption[]))
{
fieldInfo3.SetValue(customization, Array.Empty<CustomizationOption>());
}
}
object obj2 = val2.AddComponent(typeof(PassportManager));
optionsBeforePassport = new HashSet<int>(from option in Resources.FindObjectsOfTypeAll<CustomizationOption>()
select ((Object)option).GetInstanceID());
type2.GetMethod("Awake", BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, new object[1] { obj2 });
CustomizationOption[] array3 = (CustomizationOption[])typeof(Customization).GetField("hats").GetValue(customization);
CustomizationOption[] array4 = array3.Where((CustomizationOption o) => ((Object)o).name.StartsWith("jojo_mvp_", StringComparison.Ordinal)).ToArray();
if (array3.Length < count)
{
throw new InvalidOperationException("Existing custom passport hats missing.");
}
if (array4.Length != 6 || array4.Where((CustomizationOption o, int i) => ((Object)o).name != ((Object)hats[i]).name || (Object)(object)o.texture != (Object)(object)((CustomizationData)hats[i]).IconTexture).Any())
{
throw new InvalidOperationException("Passport names/icons/order mismatch.");
}
IEnumerable<CustomizationOption> source = (from field in typeof(Customization).GetFields(BindingFlags.Instance | BindingFlags.Public)
where field.FieldType == typeof(CustomizationOption[])
select field).SelectMany((FieldInfo field) => (CustomizationOption[])field.GetValue(customization));
foreach (KeyValuePair<Type, IReadOnlyList<CustomizationData>> item3 in originalCatalog)
{
foreach (CustomizationData item in item3.Value)
{
if (!source.Any((CustomizationOption option) => ((Object)option).name == ((Object)item).name))
{
throw new InvalidOperationException("Existing passport cosmetic was lost: " + ((Object)item).name);
}
}
}
results.Add($"isolatedPassportRegistration={array3.Length}; jojoOptions=6; existing custom entries preserved; all JOJO icons and names match fixed order");
}
finally
{
CustomizationOption[] array5 = ((optionsBeforePassport == null) ? Array.Empty<CustomizationOption>() : (from option in Resources.FindObjectsOfTypeAll<CustomizationOption>()
where !optionsBeforePassport.Contains(((Object)option).GetInstanceID())
select option).ToArray());
HashSet<Material> hashSet2 = new HashSet<Material>();
Renderer[] array2 = val.GetComponentsInChildren<Renderer>(true);
for (int num2 = 0; num2 < array2.Length; num2++)
{
Material[] sharedMaterials = array2[num2].sharedMaterials;
foreach (Material val4 in sharedMaterials)
{
if (Object.op_Implicit((Object)(object)val4) && !hashSet.Contains(((Object)val4).GetInstanceID()))
{
hashSet2.Add(val4);
}
}
}
CustomizationOption[] array6 = array5;
foreach (CustomizationOption obj3 in array6)
{
FieldInfo[] fields = typeof(CustomizationOption).GetFields(BindingFlags.Instance | BindingFlags.Public);
foreach (FieldInfo fieldInfo4 in fields)
{
if (fieldInfo4.FieldType == typeof(Material))
{
object? value3 = fieldInfo4.GetValue(obj3);
Material val5 = (Material)((value3 is Material) ? value3 : null);
if (val5 != null && Object.op_Implicit((Object)(object)val5) && !hashSet.Contains(((Object)val5).GetInstanceID()))
{
hashSet2.Add(val5);
}
}
}
}
object? value4 = fieldInfo2.GetValue(null);
Material val6 = (Material)((value4 is Material) ? value4 : null);
if (val6 != null && Object.op_Implicit((Object)(object)val6) && !hashSet.Contains(((Object)val6).GetInstanceID()))
{
hashSet2.Add(val6);
}
try
{
SetStatic(typeof(MoreCustomizationsPlugin), "BaseHatCount", baseHatCount);
SetStatic(typeof(MoreCustomizationsPlugin), "OverrideHatCount", overrideHatCount);
fieldInfo.SetValue(null, value);
fieldInfo2.SetValue(null, value2);
results.Add("isolatedFrameworkGlobalsRestored=PASS");
}
finally
{
array6 = array5;
foreach (CustomizationOption val7 in array6)
{
if (Object.op_Implicit((Object)(object)val7))
{
Object.Destroy((Object)(object)val7);
}
}
foreach (Material item4 in hashSet2)
{
if (Object.op_Implicit((Object)(object)item4))
{
Object.Destroy((Object)(object)item4);
}
}
if (Object.op_Implicit((Object)(object)val2))
{
Object.Destroy((Object)(object)val2);
}
Object.Destroy((Object)(object)val);
}
}
}
}
[Serializable]
internal sealed class MeshData
{
public string name = "";
public float[] positions = Array.Empty<float>();
public int[] triangles = Array.Empty<int>();
public float[] uv = Array.Empty<float>();
public float[] normals = Array.Empty<float>();
public string texture = "";
}
}