Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of RandomAppearance v1.0.0
RandomAppearance.dll
Decompiled a day agousing System; using System.Collections; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyTitle("RandomAppearance")] [assembly: AssemblyProduct("RandomAppearance")] [assembly: CompilationRelaxations(8)] [assembly: AssemblyFileVersion("2.2.1.0")] [assembly: AssemblyVersion("2.2.1.0")] namespace RandomAppearance; [BepInPlugin("marcelo.randomappearance", "RandomAppearance", "1.0.0")] public class RandomAppearancePlugin : BaseUnityPlugin { public const string PluginGuid = "marcelo.randomappearance"; public const string PluginName = "RandomAppearance"; public const string PluginVersion = "1.0.0"; private const float Gap = 8f; internal static ManualLogSource Log; private static ConfigEntry<bool> _enabled; private static ConfigEntry<string> _label; private static ConfigEntry<float> _offsetX; private static ConfigEntry<float> _offsetY; private static ConfigEntry<float> _clickInterval; private static ConfigEntry<bool> _randomizeGender; private static readonly FieldInfo HairsField = AccessTools.Field(typeof(PlayerCustomizaton), "m_hairs"); private static readonly FieldInfo BeardsField = AccessTools.Field(typeof(PlayerCustomizaton), "m_beards"); private static readonly MethodInfo SetHairMethod = AccessTools.Method(typeof(PlayerCustomizaton), "SetHair", (Type[])null, (Type[])null); private static readonly MethodInfo SetBeardMethod = AccessTools.Method(typeof(PlayerCustomizaton), "SetBeard", (Type[])null, (Type[])null); private static readonly MethodInfo HairIndexMethod = AccessTools.Method(typeof(PlayerCustomizaton), "GetHairIndex", (Type[])null, (Type[])null); private static readonly MethodInfo BeardIndexMethod = AccessTools.Method(typeof(PlayerCustomizaton), "GetBeardIndex", (Type[])null, (Type[])null); private static readonly FieldInfo GamePadHintField = AccessTools.Field(typeof(UIGamePad), "m_hint"); private static float _lastClick; private static PlayerCustomizaton _customization; private static GameObject _root; private static RectTransform _template; private static RectTransform _box; private void Awake() { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; _enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Turns the button off without uninstalling."); _label = ((BaseUnityPlugin)this).Config.Bind<string>("Button", "Label", "", "Button text. Leave empty to use Aleatório for Brazilian Portuguese or Random for other game languages."); _offsetX = ((BaseUnityPlugin)this).Config.Bind<float>("Button", "OffsetX", 0f, new ConfigDescription("Nudge right from the spot under the appearance box, in the game's own UI units.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1000f, 1000f), new object[0])); _offsetY = ((BaseUnityPlugin)this).Config.Bind<float>("Button", "OffsetY", 0f, new ConfigDescription("Nudge up, same units.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1000f, 1000f), new object[0])); _clickInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Randomizing", "MinSecondsBetweenClicks", 0.3f, new ConfigDescription("Shortest gap between two rolls. Humanoid.SetHair destroys and reinstantiates the model attachment, so every roll is a model rebuild, and rebuilds in quick succession make the character visibly flash. Measured on a 4K setup: at 0.2 a held click produced five rebuilds a second, which still flickers. Raise it if that bothers you, lower it if the button feels sluggish. 0 removes the limit.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), new object[0])); _randomizeGender = ((BaseUnityPlugin)this).Config.Bind<bool>("Randomizing", "RandomizeGender", false, "Also flips between male and female. Off by default: sex is usually the one choice someone has already made before reaching for a random look."); _offsetX.SettingChanged += delegate { Place(); }; _offsetY.SettingChanged += delegate { Place(); }; _label.SettingChanged += delegate { ApplyLabel(); }; Localization.OnLanguageChange = (Action)Delegate.Combine(Localization.OnLanguageChange, new Action(ApplyLabel)); if (HairsField == null || BeardsField == null || SetHairMethod == null || SetBeardMethod == null) { Log.LogError((object)("PlayerCustomizaton members not found (" + ((HairsField == null) ? "m_hairs " : "") + ((BeardsField == null) ? "m_beards " : "") + ((SetHairMethod == null) ? "SetHair " : "") + ((SetBeardMethod == null) ? "SetBeard " : "") + "). Hair and beard will not randomize.")); } Log.LogInfo((object)"RandomAppearance 1.0.0 loaded."); } private void OnDestroy() { Localization.OnLanguageChange = (Action)Delegate.Remove(Localization.OnLanguageChange, new Action(ApplyLabel)); } private void Update() { FejdStartup instance = FejdStartup.instance; if ((Object)(object)instance == (Object)null) { Teardown(); return; } GameObject newCharacterPanel = instance.m_newCharacterPanel; if ((Object)(object)newCharacterPanel == (Object)null || !newCharacterPanel.activeInHierarchy) { return; } if (!_enabled.Value) { if ((Object)(object)_root != (Object)null && _root.activeSelf) { _root.SetActive(false); } return; } if ((Object)(object)_root == (Object)null) { CreateButton(instance, newCharacterPanel); } if ((Object)(object)_root != (Object)null && !_root.activeSelf) { _root.SetActive(true); } } private static PlayerCustomizaton Customization() { if ((Object)(object)_customization != (Object)null) { return _customization; } FejdStartup instance = FejdStartup.instance; if ((Object)(object)instance != (Object)null && (Object)(object)instance.m_newCharacterPanel != (Object)null) { _customization = instance.m_newCharacterPanel.GetComponentInChildren<PlayerCustomizaton>(true); } if ((Object)(object)_customization == (Object)null) { _customization = Object.FindAnyObjectByType<PlayerCustomizaton>((FindObjectsInactive)1); } return _customization; } private static void CreateButton(FejdStartup fs, GameObject panel) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Expected O, but got Unknown //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Expected O, but got Unknown Button val = fs.m_csNewCharacterDone; if ((Object)(object)val == (Object)null) { val = panel.GetComponentInChildren<Button>(true); } if ((Object)(object)val == (Object)null) { Log.LogError((object)"No native button found on the character panel; Random button not created."); _enabled.Value = false; return; } _template = (RectTransform)((Component)val).transform; _box = FindAppearanceBox(panel.transform); Transform val2 = (((Object)(object)_box != (Object)null) ? ((Transform)_box).parent : ((Transform)_template).parent); _root = Object.Instantiate<GameObject>(((Component)val).gameObject, val2, false); ((Object)_root).name = "RandomAppearanceButton"; UIGamePad[] componentsInChildren = _root.GetComponentsInChildren<UIGamePad>(true); foreach (UIGamePad val3 in componentsInChildren) { GameObject val4 = (GameObject)((GamePadHintField != null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val4 != (Object)null) { Object.Destroy((Object)(object)val4); } Object.Destroy((Object)(object)val3); } Button component = _root.GetComponent<Button>(); component.onClick = new ButtonClickedEvent(); ((UnityEvent)component.onClick).AddListener(new UnityAction(Randomize)); ((Selectable)component).interactable = true; LayoutElement val5 = _root.GetComponent<LayoutElement>(); if ((Object)(object)val5 == (Object)null) { val5 = _root.AddComponent<LayoutElement>(); } val5.ignoreLayout = true; ApplyLabel(); Place(); Describe(val); } private static RectTransform FindAppearanceBox(Transform stop) { PlayerCustomizaton val = Customization(); if ((Object)(object)val == (Object)null || (Object)(object)val.m_selectedHair == (Object)null || (Object)(object)val.m_hairTone == (Object)null) { return null; } Transform val2 = null; Transform val3 = val.m_selectedHair.transform; while ((Object)(object)val3 != (Object)null) { if (((Component)val.m_hairTone).transform.IsChildOf(val3)) { val2 = val3; break; } val3 = val3.parent; } if ((Object)(object)val2 == (Object)null) { return null; } Canvas.ForceUpdateCanvases(); Transform val4 = val2; while ((Object)(object)val4 != (Object)null && (Object)(object)val4 != (Object)(object)stop) { RectTransform val5 = (RectTransform)(object)((val4 is RectTransform) ? val4 : null); if (!((Object)(object)val5 == (Object)null) && !((Object)(object)((Component)val4).GetComponent<Image>() == (Object)null)) { if (ScreenWidth(val5) >= (float)Screen.width * 0.5f) { break; } return val5; } val4 = val4.parent; } return (RectTransform)(object)((val2 is RectTransform) ? val2 : null); } private static float ScreenWidth(RectTransform rt) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0038: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) Vector3[] array = (Vector3[])(object)new Vector3[4]; rt.GetWorldCorners(array); Canvas componentInParent = ((Component)rt).GetComponentInParent<Canvas>(); Camera val = (((Object)(object)componentInParent != (Object)null && (int)componentInParent.renderMode != 0) ? componentInParent.worldCamera : null); return RectTransformUtility.WorldToScreenPoint(val, array[3]).x - RectTransformUtility.WorldToScreenPoint(val, array[0]).x; } private static void Place() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_0030: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: 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) //IL_0169: 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_0073: 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) if (!((Object)(object)_root == (Object)null) && !((Object)(object)_template == (Object)null)) { RectTransform val = (RectTransform)_root.transform; Rect rect = _template.rect; float height = ((Rect)(ref rect)).height; if ((Object)(object)_box == (Object)null) { val.anchoredPosition = _template.anchoredPosition + new Vector2(_offsetX.Value, height + 8f + _offsetY.Value); return; } Canvas.ForceUpdateCanvases(); Vector3[] array = (Vector3[])(object)new Vector3[4]; _box.GetWorldCorners(array); Transform parent = ((Transform)val).parent; Vector3 val2 = parent.InverseTransformPoint(array[0]); Vector3 val3 = parent.InverseTransformPoint(array[3]); val.anchorMin = new Vector2(0.5f, 0.5f); val.anchorMax = new Vector2(0.5f, 0.5f); val.pivot = new Vector2(0.5f, 0.5f); val.sizeDelta = new Vector2(val3.x - val2.x, height); ((Transform)val).localPosition = new Vector3((val2.x + val3.x) * 0.5f + _offsetX.Value, val2.y - 8f - height * 0.5f + _offsetY.Value, 0f); } } private static void ApplyLabel() { if (!((Object)(object)_root == (Object)null)) { string text = _label.Value; if (string.IsNullOrEmpty(text)) { string a = ((Localization.instance != null) ? Localization.instance.GetSelectedLanguage() : null); text = (string.Equals(a, "Portuguese_Brazilian", StringComparison.Ordinal) ? "Aleatório" : "Random"); } TMP_Text componentInChildren = _root.GetComponentInChildren<TMP_Text>(true); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.text = text; } } } private static void Describe(Button template) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) RectTransform val = (RectTransform)_root.transform; object obj; if (!((Object)(object)_box == (Object)null)) { object[] array = new object[4] { "'", Path((Transform)(object)_box), "' size ", null }; Rect rect = _box.rect; array[3] = ((Rect)(ref rect)).size; obj = string.Concat(array); } else { obj = "NOT FOUND (fallback above Done)"; } string text = (string)obj; string text2 = ""; foreach (Transform item in ((Transform)val).parent) { Transform val2 = item; text2 = text2 + ((text2.Length > 0) ? ", " : "") + ((Object)val2).name; } Log.LogInfo((object)string.Concat("button cloned from '", ((Object)template).name, "', appearance box ", text, ", placed at ", Vector2.op_Implicit(((Transform)val).localPosition), " size ", val.sizeDelta, ", siblings [", text2, "]")); } private static string Path(Transform t) { string text = ((Object)t).name; Transform parent = t.parent; while ((Object)(object)parent != (Object)null) { text = ((Object)parent).name + " > " + text; parent = parent.parent; } return text; } private static void Teardown() { if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)_root); } _root = null; _template = null; _box = null; _customization = null; } private static void Randomize() { if (Time.unscaledTime - _lastClick < _clickInterval.Value) { return; } _lastClick = Time.unscaledTime; PlayerCustomizaton val = Customization(); if ((Object)(object)val == (Object)null) { Log.LogWarning((object)"Random clicked, but the customization screen was not found."); return; } if (_randomizeGender.Value) { val.SetPlayerModel(Random.Range(0, 2)); } SetIndexed(val, HairsField, SetHairMethod, HairIndexMethod); SetIndexed(val, BeardsField, SetBeardMethod, BeardIndexMethod); Shuffle(val.m_skinHue, (Action<float>)val.OnSkinHueChange); Shuffle(val.m_hairLevel, (Action<float>)val.OnHairHueChange); Shuffle(val.m_hairTone, (Action<float>)val.OnHairHueChange); } private static void SetIndexed(PlayerCustomizaton pc, FieldInfo field, MethodInfo setter, MethodInfo getter) { if (field == null || setter == null || !(field.GetValue(pc) is ICollection { Count: not 0, Count: var count })) { return; } int num = Random.Range(0, count); if (getter != null && count > 1) { object obj = getter.Invoke(pc, null); if (obj is int && (int)obj == num) { num = (num + Random.Range(1, count)) % count; } } setter.Invoke(pc, new object[1] { num }); } private static void Shuffle(Slider slider, Action<float> handler) { if (!((Object)(object)slider == (Object)null)) { float value = slider.value; float obj = (slider.value = Random.Range(slider.minValue, slider.maxValue)); if (handler != null && Mathf.Approximately(value, slider.value)) { handler(obj); } } } }