using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using Artisan.Configuration; using Artisan.Features.Inventory.Effects; using Artisan.Features.Inventory.Interactables; using Artisan.Features.Inventory.Network; using Artisan.Features.Inventory.Patches; using Artisan.Features.Inventory.Services; using Artisan.Features.Inventory.UI; using Artisan.Features.Monsters.UI; using Artisan.Features.Spells.Patches; using Artisan.Localization; using Artisan.Shared.Reflection; using Artisan.Source.Features.Spells.Context; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using FMODUnity; using HarmonyLib; using Mirror; using Mirror.RemoteCalls; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using TMPro; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Utilities; using UnityEngine.UI; using YAPYAP; using YAPYAP.Npc.Shopkeeper; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Artisan")] [assembly: AssemblyDescription("A general-purpose quality-of-life mod for YAPYAP with inventory extension support, multiplayer monster health bars, damage indicators, and spell balance improvements.")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Hadaward")] [assembly: AssemblyProduct("Artisan")] [assembly: AssemblyCopyright("Copyright © Hadaward 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("2295655e-9260-4eae-a7c1-b44cabf62fea")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.1.0.0")] namespace Artisan { [BepInPlugin("gamedroit.artisan", "Artisan", "1.1.0")] public sealed class ArtisanMod : BaseUnityPlugin { public const string PluginGuid = "gamedroit.artisan"; public const string PluginName = "Artisan"; public const string PluginVersion = "1.1.0"; private Harmony _harmony; internal static ManualLogSource Logger { get; private set; } internal static ArtisanConfig Settings { get; private set; } public void Awake() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown Logger = ((BaseUnityPlugin)this).Logger; Settings = new ArtisanConfig(((BaseUnityPlugin)this).Config); InventorySlotUpgradeNetwork.Register(); InventoryUpgradeStationInteractable.RegisterTranslations(); _harmony = new Harmony("gamedroit.artisan"); try { _harmony.PatchAll(Assembly.GetExecutingAssembly()); foreach (MethodBase patchedMethod in _harmony.GetPatchedMethods()) { Logger.LogDebug((object)("Patched: " + patchedMethod.DeclaringType?.FullName + "." + patchedMethod.Name)); } } catch (Exception arg) { Logger.LogError((object)$"Harmony patch failed: {arg}"); } Logger.LogInfo((object)"Artisan 1.1.0 loaded."); } public void OnDestroy() { Logger.LogInfo((object)"Artisan is being unloaded."); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } } namespace Artisan.Shared.Reflection { public static class HarmonyUtil { public static T GetFieldValue(object instance, string fieldName) { if (instance == null) { return default(T); } FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), fieldName); if (fieldInfo == null && instance.GetType().BaseType != null) { fieldInfo = AccessTools.Field(instance.GetType().BaseType, fieldName); } if (fieldInfo == null) { ArtisanMod.Logger.LogWarning((object)("Field '" + fieldName + "' was not found on '" + instance.GetType().FullName + "'.")); return default(T); } object value = fieldInfo.GetValue(instance); if (value is T) { return (T)value; } return default(T); } public static void SetFieldValue(object instance, string fieldName, T value) { if (instance != null) { FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), fieldName); if (fieldInfo == null && instance.GetType().BaseType != null) { fieldInfo = AccessTools.Field(instance.GetType().BaseType, fieldName); } if (fieldInfo == null) { ArtisanMod.Logger.LogWarning((object)("Field '" + fieldName + "' was not found on '" + instance.GetType().FullName + "'.")); } else { fieldInfo.SetValue(instance, value); } } } } } namespace Artisan.Localization { public static class ArtisanLocalization { private static readonly Dictionary> Translations = new Dictionary>(); public static void AddTranslation(SystemLanguage language, string key, string value) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (!Translations.TryGetValue(language, out var value2)) { value2 = new Dictionary(); Translations[language] = value2; } value2[key] = value; } public static string Translate(string key, params object[] args) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: 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) SystemLanguage val = (SystemLanguage)10; LocalisationManager val2 = default(LocalisationManager); if (Service.Get(ref val2) && val2.CurrentTranslator != null) { val = val2.CurrentTranslator.Language; } if (Translations.TryGetValue(val, out var value) && value.TryGetValue(key, out var value2)) { return string.Format(value2, args); } if (Translations.TryGetValue((SystemLanguage)10, out var value3) && value3.TryGetValue(key, out var value4)) { return string.Format(value4, args); } ArtisanMod.Logger.LogWarning((object)$"Translation key '{key}' not found for language '{val}'."); return key; } } } namespace Artisan.Source.Features.Spells.Patches { [HarmonyPatch(typeof(ProjectilePush), "OnDestroy")] public static class ProjectilePushDamageCleanupPatch { private static void Prefix(ProjectilePush __instance) { ProjectilePushDamagePatch.ClearProjectile(__instance); } } } namespace Artisan.Source.Features.Spells.Context { internal readonly struct ProjectilePushDamageContext { public static readonly ProjectilePushDamageContext Disabled = new ProjectilePushDamageContext(isEnabled: false, 0, affectPlayers: false, null, Vector3.zero); public bool IsEnabled { get; } public int DamageAmount { get; } public bool AffectPlayers { get; } public NetworkIdentity Caster { get; } public Vector3 ForceDirection { get; } public ProjectilePushDamageContext(bool isEnabled, int damageAmount, bool affectPlayers, NetworkIdentity caster, Vector3 forceDirection) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) IsEnabled = isEnabled; DamageAmount = damageAmount; AffectPlayers = affectPlayers; Caster = caster; ForceDirection = forceDirection; } public static ProjectilePushDamageContext Create(ProjectilePush projectile) { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) Spell fieldValue = HarmonyUtil.GetFieldValue(projectile, "OwnerSpell"); NetworkIdentity fieldValue2 = HarmonyUtil.GetFieldValue(projectile, "Caster"); if ((Object)(object)fieldValue == (Object)null) { return Disabled; } if (((object)fieldValue).GetType() == typeof(PushSpell)) { return new ProjectilePushDamageContext(ArtisanMod.Settings.Spells.Aero.Enabled.Value, ArtisanMod.Settings.Spells.Aero.Damage.Value, ArtisanMod.Settings.Spells.Aero.DamagePlayers.Value, fieldValue2, ((Component)projectile).transform.forward); } if (((object)fieldValue).GetType() == typeof(LevitationBlastSpell)) { return new ProjectilePushDamageContext(ArtisanMod.Settings.Spells.TeleBlast.Enabled.Value, ArtisanMod.Settings.Spells.TeleBlast.Damage.Value, ArtisanMod.Settings.Spells.TeleBlast.DamagePlayers.Value, fieldValue2, ((Component)projectile).transform.forward); } return Disabled; } } } namespace Artisan.Features.Spells.Patches { [HarmonyPatch(typeof(ProjectilePush), "OnTargetHit")] public static class ProjectilePushDamagePatch { private static readonly Dictionary> DamagedTargetsByProjectile = new Dictionary>(); private static void Prefix(ProjectilePush __instance, Collider target, Rigidbody targetRigidbody, NetworkIdentity targetIdentity) { if (CanProcessHit(__instance, target, targetRigidbody, targetIdentity)) { ProjectilePushDamageContext context = ProjectilePushDamageContext.Create(__instance); if (context.IsEnabled && IsTargetPushable(__instance, target) && !WasRigidbodyAlreadyAffected(__instance, targetRigidbody) && TryMarkTargetDamaged(__instance, targetIdentity)) { ApplyDamage(context, targetIdentity); } } } public static void ClearProjectile(ProjectilePush projectile) { if (!((Object)(object)projectile == (Object)null)) { DamagedTargetsByProjectile.Remove(((Object)projectile).GetInstanceID()); } } private static bool CanProcessHit(ProjectilePush projectile, Collider target, Rigidbody targetRigidbody, NetworkIdentity targetIdentity) { if (NetworkServer.active && (Object)(object)projectile != (Object)null && ((NetworkBehaviour)projectile).isServer && (Object)(object)target != (Object)null && (Object)(object)targetRigidbody != (Object)null) { return (Object)(object)targetIdentity != (Object)null; } return false; } private static bool IsTargetPushable(ProjectilePush projectile, Collider target) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) LayerMask fieldValue = HarmonyUtil.GetFieldValue(projectile, "pushableLayer"); return ((1 << ((Component)target).gameObject.layer) & ((LayerMask)(ref fieldValue)).value) != 0; } private static bool WasRigidbodyAlreadyAffected(ProjectilePush projectile, Rigidbody targetRigidbody) { return HarmonyUtil.GetFieldValue>(projectile, "affectedRigidbodies")?.Contains(targetRigidbody) ?? false; } private static void ApplyDamage(ProjectilePushDamageContext context, NetworkIdentity targetIdentity) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) NpcBehaviour val = default(NpcBehaviour); if (((Component)targetIdentity).TryGetComponent(ref val)) { val.OnHit(context.DamageAmount, context.ForceDirection, false, context.Caster); } Pawn val2 = default(Pawn); if (context.AffectPlayers && ((Component)targetIdentity).TryGetComponent(ref val2) && !((Object)(object)val2.Hurtbox == (Object)null)) { uint num = (((Object)(object)context.Caster != (Object)null) ? context.Caster.netId : 0u); val2.Hurtbox.OnHit(context.DamageAmount, 0f, context.ForceDirection, (StatusSO)null, false, false, false, num); } } private static bool TryMarkTargetDamaged(ProjectilePush projectile, NetworkIdentity targetIdentity) { int instanceID = ((Object)projectile).GetInstanceID(); uint netId = targetIdentity.netId; if (!DamagedTargetsByProjectile.TryGetValue(instanceID, out var value)) { value = new HashSet(); DamagedTargetsByProjectile[instanceID] = value; } if (value.Contains(netId)) { return false; } value.Add(netId); return true; } } } namespace Artisan.Features.Monsters.Patches { [HarmonyPatch] public static class NpcHurtboxClientHitUiPatch { [HarmonyTargetMethod] private static MethodBase TargetMethod() { return AccessTools.Method(typeof(NpcHurtbox), "UserCode_RpcOnHit__Int32__Vector3", (Type[])null, (Type[])null); } [HarmonyPostfix] private static void Postfix(NpcHurtbox __instance, int damage, Vector3 forceDir) { if ((Object)(object)__instance == (Object)null || !IsAnyHitUiEnabled()) { return; } try { if (ArtisanMod.Settings.CombatUI.ShowMonsterHealthBars.Value) { ShowHealthBar(__instance); } if (ArtisanMod.Settings.CombatUI.ShowMonsterDamageIndicators.Value) { ShowDamageIndicator(__instance, damage); } } catch (Exception ex) { ArtisanMod.Logger.LogWarning((object)("[MonsterHitUI] Failed to render hit UI: " + ex)); } } private static bool IsAnyHitUiEnabled() { if (!ArtisanMod.Settings.CombatUI.ShowMonsterHealthBars.Value) { return ArtisanMod.Settings.CombatUI.ShowMonsterDamageIndicators.Value; } return true; } private static void ShowHealthBar(NpcHurtbox hurtbox) { EnemyHealthBar enemyHealthBar = ((Component)hurtbox).GetComponent(); if ((Object)(object)enemyHealthBar == (Object)null) { enemyHealthBar = ((Component)hurtbox).gameObject.AddComponent(); } enemyHealthBar.EnsureInitialized(); enemyHealthBar.ResetTimer(); enemyHealthBar.UpdateHealthDisplay(); } private static void ShowDamageIndicator(NpcHurtbox hurtbox, int damage) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) int damage2 = Mathf.Clamp(damage, 1, 9999); DamageTextFactory.Create(GetDamageIndicatorPosition(hurtbox), damage2); } private static Vector3 GetDamageIndicatorPosition(NpcHurtbox hurtbox) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)hurtbox).transform.position; NpcBehaviour val = default(NpcBehaviour); if (((Component)hurtbox).TryGetComponent(ref val)) { if ((Object)(object)val.Rigidbody != (Object)null) { position = ((Component)val.Rigidbody).transform.position; } else if ((Object)(object)val.CameraTargetTransform != (Object)null) { position = val.CameraTargetTransform.position; } } return position + new Vector3(Random.Range(-0.5f, 0.5f), Random.Range(1f, 1.5f), Random.Range(-0.5f, 0.5f)); } } } namespace Artisan.Features.Monsters.UI { public sealed class DamageText3D : MonoBehaviour { private TextMeshPro _textComponent; private Vector3 _baseWorldPosition; private float _timer = 1.5f; private float _floatHeight; private void Awake() { _textComponent = ((Component)this).GetComponent(); } private void Start() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) _baseWorldPosition = ((Component)this).transform.position; FaceCamera(); } private void Update() { UpdatePosition(); FaceCamera(); UpdateLifetime(); UpdateScale(); UpdateAlpha(); } public void Setup(float lifetime) { _timer = lifetime; } private void UpdatePosition() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) _floatHeight += Time.deltaTime * 0.8f; ((Component)this).transform.position = _baseWorldPosition + Vector3.up * _floatHeight; } private void FaceCamera() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Camera.main == (Object)null)) { ((Component)this).transform.rotation = Quaternion.LookRotation(((Component)this).transform.position - ((Component)Camera.main).transform.position); } } private void UpdateLifetime() { _timer -= Time.deltaTime; if (_timer <= 0f) { Object.Destroy((Object)(object)((Component)this).gameObject); } } private void UpdateScale() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (!(_timer <= 0f) && !(_timer >= 0.75f)) { float num = Mathf.Lerp(1f, 0.5f, (0.75f - _timer) / 0.75f); ((Component)this).transform.localScale = Vector3.one * num; } } private void UpdateAlpha() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_0027: 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_0044: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_textComponent == (Object)null)) { Color color = ((Graphic)_textComponent).color; ((Graphic)_textComponent).color = new Color(color.r, color.g, color.b, Mathf.Clamp01(_timer * 2f)); } } } public static class DamageTextFactory { private readonly struct DamageTextStyle { public Color Color { get; } public float FontSize { get; } public float Lifetime { get; } private DamageTextStyle(Color color, float fontSize, float lifetime) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) Color = color; FontSize = fontSize; Lifetime = lifetime; } public static DamageTextStyle FromDamage(int damage) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) if (damage >= 50) { return new DamageTextStyle(Color.red, 6f, 3f); } if (damage >= 25) { return new DamageTextStyle(Color.yellow, 5f, 2f); } return new DamageTextStyle(new Color(1f, 0.5f, 0f), 4f, 1.5f); } } public static void Create(Vector3 position, int damage) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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) GameObject val = new GameObject("DamageText", new Type[2] { typeof(TextMeshPro), typeof(DamageText3D) }); TextMeshPro component = val.GetComponent(); DamageText3D component2 = val.GetComponent(); DamageTextStyle damageTextStyle = DamageTextStyle.FromDamage(damage); ((TMP_Text)component).alignment = (TextAlignmentOptions)514; ((TMP_Text)component).text = $"-{damage}"; ((Graphic)component).color = damageTextStyle.Color; ((TMP_Text)component).fontSize = damageTextStyle.FontSize; val.transform.position = position; component2.Setup(damageTextStyle.Lifetime); } } public sealed class EnemyHealthBar : MonoBehaviour { private sealed class Billboard : MonoBehaviour { private Camera _mainCamera; private void LateUpdate() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_mainCamera == (Object)null) { _mainCamera = Camera.main; } if (!((Object)(object)_mainCamera == (Object)null)) { ((Component)this).transform.rotation = Quaternion.Euler(((Component)_mainCamera).transform.eulerAngles.x, ((Component)_mainCamera).transform.eulerAngles.y, 0f); } } } private static Sprite _sharedWhiteSprite; private readonly Vector2 _size = new Vector2(20f, 2.5f); private readonly Color _backgroundColor = new Color(0.3f, 0.3f, 0.3f, 0.9f); private readonly Color _healthColor = Color.red; private float _lastDamageTime; private bool _isActive = true; private bool _initialized; private Vector3 _worldOffset = new Vector3(0f, 1.25f, 0f); private Canvas _canvas; private Image _foreground; private Image _background; private TextMeshProUGUI _healthText; private NpcHurtbox _npcHurtbox; private NpcBehaviour _npcBehaviour; private Transform _followTransform; private Camera _mainCamera; private float _targetFillAmount = 1f; private int _lastHealthCurrent = int.MinValue; private int _lastHealthMax = int.MinValue; private float _nextVisibilityUpdateTime; private float _nextFollowResolveTime; private float _nextOffsetResolveTime; public void EnsureInitialized() { if (!_initialized) { _npcHurtbox = ((Component)this).GetComponent(); if (!((Object)(object)_npcHurtbox == (Object)null)) { _npcBehaviour = ((Component)this).GetComponent(); _followTransform = ResolveFollowTransform(); _mainCamera = Camera.main; InitializeCanvas(); UpdateWorldOffsetFromBounds(force: true); UpdateCanvasWorldPosition(); UpdateHealthDisplay(); ResetTimer(); _initialized = true; } } } public void ResetTimer() { _lastDamageTime = Time.time; if (!_isActive && (Object)(object)_canvas != (Object)null) { ReactivateHealthBar(); } } public void UpdateHealthDisplay() { if (!((Object)(object)_npcHurtbox == (Object)null)) { int num = Mathf.Max(0, _npcHurtbox.MaxHealth); int num2 = Mathf.Clamp(_npcHurtbox.Health, 0, num); _targetFillAmount = ((num > 0) ? Mathf.Clamp01((float)num2 / (float)num) : 0f); UpdateHealthText(); } } private void InitializeCanvas() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_005c: 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_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("ArtisanEnemyHealthCanvas"); _canvas = val.AddComponent(); _canvas.renderMode = (RenderMode)2; ((Component)_canvas).transform.SetParent(((Object)(object)_followTransform != (Object)null) ? _followTransform : ((Component)this).transform, false); ((Component)_canvas).transform.localPosition = _worldOffset; RectTransform component = ((Component)_canvas).GetComponent(); component.sizeDelta = _size; ((Transform)component).localScale = new Vector3(0.03f, 0.03f, 0.03f); _background = CreateBarElement(((Component)_canvas).transform, _backgroundColor, "Background"); _foreground = CreateBarElement(((Component)_canvas).transform, _healthColor, "Foreground"); _foreground.type = (Type)3; _foreground.fillMethod = (FillMethod)0; _foreground.fillOrigin = 0; _foreground.fillAmount = _targetFillAmount; val.AddComponent(); CreateHealthText(((Component)_canvas).transform); } private Transform ResolveFollowTransform() { if ((Object)(object)_npcBehaviour != (Object)null) { if ((Object)(object)_npcBehaviour.Rigidbody != (Object)null) { return ((Component)_npcBehaviour.Rigidbody).transform; } if ((Object)(object)_npcBehaviour.CameraTargetTransform != (Object)null) { return _npcBehaviour.CameraTargetTransform; } } return ((Component)this).transform; } private Transform ResolveBoundsRoot() { if (!((Object)(object)_npcBehaviour != (Object)null)) { return ((Component)this).transform; } return ((Component)_npcBehaviour).transform; } private void Update() { EnsureInitialized(); if (!_initialized || !_isActive) { return; } if (Time.time - _lastDamageTime > 10f) { HideHealthBar(); } else if (!((Object)(object)_npcHurtbox == (Object)null) && !((Object)(object)_foreground == (Object)null) && !((Object)(object)_background == (Object)null)) { RefreshFollowTransform(); UpdateWorldOffsetFromBounds(force: false); UpdateCanvasWorldPosition(); UpdateHealthValues(); UpdateForegroundAnimation(); if (Time.time >= _nextVisibilityUpdateTime) { UpdateCanvasVisibility(); _nextVisibilityUpdateTime = Time.time + 0.1f; } } } private void RefreshFollowTransform() { //IL_0064: Unknown result type (might be due to invalid IL or missing references) if (Time.time < _nextFollowResolveTime) { return; } Transform val = ResolveFollowTransform(); if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)_followTransform) { _followTransform = val; if ((Object)(object)_canvas != (Object)null) { ((Component)_canvas).transform.SetParent(_followTransform, false); ((Component)_canvas).transform.localPosition = _worldOffset; } UpdateWorldOffsetFromBounds(force: true); } _nextFollowResolveTime = Time.time + 0.5f; } private void UpdateHealthValues() { int health = _npcHurtbox.Health; int maxHealth = _npcHurtbox.MaxHealth; if (maxHealth > 0 && (health != _lastHealthCurrent || maxHealth != _lastHealthMax)) { _lastHealthCurrent = health; _lastHealthMax = maxHealth; _targetFillAmount = Mathf.Clamp01((float)health / (float)maxHealth); UpdateHealthText(); } } private void UpdateForegroundAnimation() { //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) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) _foreground.fillAmount = Mathf.Lerp(_foreground.fillAmount, _targetFillAmount, Time.deltaTime * 10f); Color color = ((Graphic)_foreground).color; if (_targetFillAmount < 0.3f) { float num = Mathf.PingPong(Time.time * 2f, 1f); ((Graphic)_foreground).color = new Color(1f, num, num, color.a); } else { ((Graphic)_foreground).color = new Color(_healthColor.r, _healthColor.g, _healthColor.b, color.a); } } private void UpdateWorldOffsetFromBounds(bool force) { //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_00db: 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) if (!force && Time.time < _nextOffsetResolveTime) { return; } _nextOffsetResolveTime = Time.time + 1f; Transform val = ResolveBoundsRoot(); if (!((Object)(object)val == (Object)null) && !((Object)(object)_followTransform == (Object)null) && TryGetWorldBounds(val, out var bounds)) { float y = _followTransform.position.y; float num = Mathf.Clamp(((Bounds)(ref bounds)).max.y - y + 0.15f, 0.35f, 12f); float value = ArtisanMod.Settings.CombatUI.MonsterHealthBarExtraHeightOffset.Value; float num2 = Mathf.Clamp(num + value, 0.35f, 20f); if (!(Mathf.Abs(_worldOffset.y - num2) <= 0.01f)) { _worldOffset = new Vector3(_worldOffset.x, num2, _worldOffset.z); UpdateCanvasWorldPosition(); } } } private void UpdateCanvasWorldPosition() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_canvas == (Object)null) && !((Object)(object)_followTransform == (Object)null)) { ((Component)_canvas).transform.position = _followTransform.position + new Vector3(_worldOffset.x, 0f, _worldOffset.z) + Vector3.up * _worldOffset.y; } } private static bool TryGetWorldBounds(Transform root, out Bounds bounds) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) bounds = default(Bounds); bool flag = false; Collider[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); foreach (Collider val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !val.isTrigger) { if (!flag) { bounds = val.bounds; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val.bounds); } } } if (flag) { return true; } Renderer[] componentsInChildren2 = ((Component)root).GetComponentsInChildren(true); foreach (Renderer val2 in componentsInChildren2) { if (!((Object)(object)val2 == (Object)null)) { if (!flag) { bounds = val2.bounds; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val2.bounds); } } } return flag; } private void CreateHealthText(Transform parent) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("HealthText"); val.transform.SetParent(parent, false); _healthText = val.AddComponent(); ((TMP_Text)_healthText).alignment = (TextAlignmentOptions)514; ((TMP_Text)_healthText).fontSize = 10f; ((Graphic)_healthText).color = Color.white; ((TMP_Text)_healthText).margin = new Vector4(0f, 0f, 0f, 10f); RectTransform component = ((Component)_healthText).GetComponent(); component.anchorMin = new Vector2(0.5f, 1f); component.anchorMax = new Vector2(0.5f, 1f); component.pivot = new Vector2(0.5f, 0.5f); component.anchoredPosition = new Vector2(0f, 5f); component.sizeDelta = new Vector2(100f, 20f); } private void UpdateHealthText() { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_healthText == (Object)null) && !((Object)(object)_npcHurtbox == (Object)null)) { int num = Mathf.Max(0, _npcHurtbox.MaxHealth); int num2 = Mathf.Clamp(_npcHurtbox.Health, 0, num); ((TMP_Text)_healthText).text = $"{num2}/{num}"; ((Graphic)_healthText).color = ((num > 0 && (float)num2 / (float)num < 0.3f) ? Color.yellow : Color.white); } } private Image CreateBarElement(Transform parent, Color color, string name) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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_003d: 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_0052: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); val.transform.SetParent(parent, false); Image val2 = val.AddComponent(); val2.sprite = GetSharedWhiteSprite(); ((Graphic)val2).color = color; RectTransform component = val.GetComponent(); component.anchorMin = Vector2.zero; component.anchorMax = Vector2.one; component.offsetMin = Vector2.zero; component.offsetMax = Vector2.zero; return val2; } private static Sprite GetSharedWhiteSprite() { //IL_0032: 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) if ((Object)(object)_sharedWhiteSprite != (Object)null) { return _sharedWhiteSprite; } Texture2D whiteTexture = Texture2D.whiteTexture; _sharedWhiteSprite = Sprite.Create(whiteTexture, new Rect(0f, 0f, (float)((Texture)whiteTexture).width, (float)((Texture)whiteTexture).height), new Vector2(0.5f, 0.5f)); return _sharedWhiteSprite; } private void UpdateCanvasVisibility() { //IL_006a: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: 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_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_mainCamera == (Object)null) { _mainCamera = Camera.main; } if (!((Object)(object)_mainCamera == (Object)null) && !((Object)(object)_foreground == (Object)null) && !((Object)(object)_background == (Object)null)) { Vector3 val = (((Object)(object)_canvas != (Object)null) ? ((Component)_canvas).transform.position : ((Component)this).transform.position); float num = Vector3.Distance(((Component)_mainCamera).transform.position, val); float num2 = Mathf.Clamp01(1f - num / 50f); ((Graphic)_foreground).color = new Color(((Graphic)_foreground).color.r, ((Graphic)_foreground).color.g, ((Graphic)_foreground).color.b, num2); ((Graphic)_background).color = new Color(_backgroundColor.r, _backgroundColor.g, _backgroundColor.b, num2 * 0.8f); if ((Object)(object)_healthText != (Object)null) { ((TMP_Text)_healthText).alpha = num2; } } } private void ReactivateHealthBar() { _isActive = true; if ((Object)(object)_canvas != (Object)null) { ((Component)_canvas).gameObject.SetActive(true); } UpdateHealthDisplay(); UpdateCanvasVisibility(); } private void HideHealthBar() { _isActive = false; if ((Object)(object)_canvas != (Object)null) { ((Component)_canvas).gameObject.SetActive(false); } } private void OnDestroy() { if ((Object)(object)_canvas != (Object)null) { Object.Destroy((Object)(object)((Component)_canvas).gameObject); } _canvas = null; } } } namespace Artisan.Features.Inventory.UI { [HarmonyPatch(typeof(UIInventory), "InitializeSlots")] public static class InventoryGridPatch { public static void Postfix(UIInventory __instance) { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: 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_00c8: 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) if ((Object)(object)__instance == (Object)null || !ArtisanMod.Settings.Inventory.EnableExtendedSlots.Value) { return; } UIInventorySlot[] fieldValue = HarmonyUtil.GetFieldValue(__instance, "inventorySlots"); if (fieldValue == null || fieldValue.Length == 0 || (Object)(object)fieldValue[0] == (Object)null) { return; } Transform parent = ((Component)fieldValue[0]).transform.parent; RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null); if (!((Object)(object)val == (Object)null)) { DisableLayoutComponents(val); if (ArtisanMod.Settings.Inventory.HideInventoryBackground.Value) { HideInventoryBackground(__instance); } RectTransform component = ((Component)fieldValue[0]).GetComponent(); Vector2 slotSize = (Vector2)(((Object)(object)component != (Object)null) ? component.sizeDelta : new Vector2(36f, 36f)); RepositionInventorySlotFrames(__instance, val, slotSize, fieldValue.Length); RepositionInventorySlots(fieldValue, slotSize); RepositionLeftHandSlotAndFrame(__instance, val, slotSize, fieldValue.Length); RepositionSelectedItemName(__instance, val, slotSize, fieldValue.Length); RepositionInputPrompts(__instance, val, slotSize, fieldValue.Length); LayoutRebuilder.MarkLayoutForRebuild(val); } } private static void DisableLayoutComponents(RectTransform container) { LayoutGroup[] components = ((Component)container).GetComponents(); for (int i = 0; i < components.Length; i++) { if ((Object)(object)components[i] != (Object)null) { ((Behaviour)components[i]).enabled = false; } } ContentSizeFitter component = ((Component)container).GetComponent(); if ((Object)(object)component != (Object)null) { ((Behaviour)component).enabled = false; } } private static void HideInventoryBackground(UIInventory inventory) { Transform val = ((Component)inventory).transform.Find("InventoryPanel/BottomRight/InventoryFrame"); if ((Object)(object)val == (Object)null) { ArtisanMod.Logger.LogWarning((object)"InventoryFrame was not found."); } else { ((Component)val).gameObject.SetActive(false); } } private static int GetGridColumns() { return Mathf.Max(ArtisanMod.Settings.Inventory.GridColumns.Value, 3); } private static Vector2 CalculateSlotPosition(int index, Vector2 slotSize, int slotCount) { //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: 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_00d2: 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_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) Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(ArtisanMod.Settings.Inventory.GridPositionX.Value, ArtisanMod.Settings.Inventory.GridPositionY.Value); int gridColumns = GetGridColumns(); int num = Mathf.Min(gridColumns, slotCount); int num2 = Mathf.CeilToInt((float)slotCount / (float)gridColumns); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(ArtisanMod.Settings.Inventory.SlotSpacingX.Value, ArtisanMod.Settings.Inventory.SlotSpacingY.Value); if (ArtisanMod.Settings.Inventory.EnableAdaptiveGridPosition.Value) { float num3 = (float)(num - 1) * (slotSize.x + val2.x); float num4 = (float)(num2 - 1) * (slotSize.y + val2.y); float num5 = (float)(Mathf.Min(3, slotCount) - 1) * (slotSize.x + val2.x); val += new Vector2(num5 * 0.5f - num3, num4); } int num6 = index / gridColumns; int num7 = index % gridColumns; return val + new Vector2((float)num7 * (slotSize.x + val2.x), (float)(-num6) * (slotSize.y + val2.y)); } private static float CalculateLeftHandSlotX(Vector2 slotSize, int slotCount) { //IL_0030: 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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(ArtisanMod.Settings.Inventory.SlotSpacingX.Value, ArtisanMod.Settings.Inventory.SlotSpacingY.Value); return CalculateSlotPosition(0, slotSize, slotCount).x - slotSize.x - val.x - ArtisanMod.Settings.Inventory.LeftHandSlotSpacingX.Value; } private static void MoveRectToInventoryXOnly(RectTransform rect, RectTransform targetParent, float targetX, Vector2 targetSize) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_005c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)rect == (Object)null) && !((Object)(object)targetParent == (Object)null)) { Vector3 position = ((Transform)rect).position; Quaternion localRotation = ((Transform)rect).localRotation; ((Transform)rect).SetParent((Transform)(object)targetParent, false); SetRectTransformCenteredAnchor(rect); Vector3 val = ((Transform)targetParent).InverseTransformPoint(position); rect.anchoredPosition = new Vector2(targetX, val.y); rect.sizeDelta = targetSize; ((Transform)rect).localScale = Vector3.one; ((Transform)rect).localRotation = localRotation; } } private static void SetRectTransformCenteredAnchor(RectTransform rect) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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) rect.anchorMin = new Vector2(0.5f, 0.5f); rect.anchorMax = new Vector2(0.5f, 0.5f); rect.pivot = new Vector2(0.5f, 0.5f); } private static void RepositionInventorySlots(UIInventorySlot[] slots, Vector2 slotSize) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) int num = slots.Length; for (int i = 0; i < num; i++) { UIInventorySlot val = slots[i]; if (!((Object)(object)val == (Object)null)) { RectTransform component = ((Component)val).GetComponent(); if (!((Object)(object)component == (Object)null)) { SetRectTransformCenteredAnchor(component); component.anchoredPosition = CalculateSlotPosition(i, slotSize, num); ((Transform)component).SetSiblingIndex(i); } } } } private static void CopyRectTransform(RectTransform source, RectTransform target) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) target.anchorMin = source.anchorMin; target.anchorMax = source.anchorMax; target.pivot = source.pivot; target.anchoredPosition = source.anchoredPosition; ((Transform)target).localScale = Vector3.one; ((Transform)target).localRotation = Quaternion.identity; } private static void RepositionLeftHandSlotAndFrame(UIInventory inventory, RectTransform container, Vector2 slotSize, int slotCount) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) UIInventorySlot fieldValue = HarmonyUtil.GetFieldValue(inventory, "leftHandSlot"); if ((Object)(object)fieldValue == (Object)null) { return; } RectTransform component = ((Component)fieldValue).GetComponent(); if (!((Object)(object)component == (Object)null)) { Transform obj = ((Component)inventory).transform.Find("InventoryPanel/BottomRight/OffhandItem"); RectTransform val = (RectTransform)(object)((obj is RectTransform) ? obj : null); if ((Object)(object)val == (Object)null) { ArtisanMod.Logger.LogWarning((object)"OffhandItem frame was not found."); return; } float targetX = CalculateLeftHandSlotX(slotSize, slotCount); MoveRectToInventoryXOnly(component, container, targetX, slotSize + new Vector2(6f, 6f)); ((Transform)val).SetParent(((Transform)component).parent, false); CopyRectTransform(component, val); val.sizeDelta = component.sizeDelta + Vector2.one; ((Component)val).gameObject.SetActive(true); ((Transform)val).SetSiblingIndex(((Transform)component).GetSiblingIndex()); ((Transform)component).SetSiblingIndex(((Transform)val).GetSiblingIndex() + 1); } } private static Vector2 ConvertAnchoredPositionToTargetParent(RectTransform sourceParent, RectTransform targetParent, Vector2 sourceAnchoredPosition) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((Transform)sourceParent).TransformPoint(Vector2.op_Implicit(sourceAnchoredPosition)); Vector2 result = default(Vector2); RectTransformUtility.ScreenPointToLocalPointInRectangle(targetParent, RectTransformUtility.WorldToScreenPoint((Camera)null, val), (Camera)null, ref result); return result; } private static void RepositionInventorySlotFrames(UIInventory inventory, RectTransform slotContainer, Vector2 slotSize, int slotCount) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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) //IL_0056: 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_0064: Unknown result type (might be due to invalid IL or missing references) Transform obj = ((Component)inventory).transform.Find("InventoryPanel/BottomRight/InventoryContainer"); RectTransform val = (RectTransform)(object)((obj is RectTransform) ? obj : null); if ((Object)(object)val == (Object)null) { ArtisanMod.Logger.LogWarning((object)"InventoryContainer was not found."); return; } RectTransform[] orCreateInventorySlotFrames = GetOrCreateInventorySlotFrames((Transform)(object)val, slotCount); for (int i = 0; i < slotCount && i < orCreateInventorySlotFrames.Length; i++) { RectTransform val2 = orCreateInventorySlotFrames[i]; if (!((Object)(object)val2 == (Object)null)) { Vector2 sourceAnchoredPosition = CalculateSlotPosition(i, slotSize, slotCount); Vector2 anchoredPosition = ConvertAnchoredPositionToTargetParent(slotContainer, val, sourceAnchoredPosition); SetRectTransformCenteredAnchor(val2); val2.anchoredPosition = anchoredPosition; ((Transform)val2).SetSiblingIndex(i); ((Component)val2).gameObject.SetActive(true); } } for (int j = slotCount; j < orCreateInventorySlotFrames.Length; j++) { if ((Object)(object)orCreateInventorySlotFrames[j] != (Object)null) { ((Component)orCreateInventorySlotFrames[j]).gameObject.SetActive(false); } } } private static RectTransform[] GetOrCreateInventorySlotFrames(Transform frameContainer, int slotCount) { List list = new List(); for (int i = 0; i < frameContainer.childCount; i++) { Transform child = frameContainer.GetChild(i); if (!((Object)(object)child == (Object)null) && !(((Object)child).name != "InventoryItem")) { RectTransform component = ((Component)child).GetComponent(); if ((Object)(object)component != (Object)null) { list.Add(component); } } } if (list.Count == 0) { ArtisanMod.Logger.LogWarning((object)"No InventoryItem frame template was found."); return (RectTransform[])(object)new RectTransform[0]; } RectTransform val = list[0]; while (list.Count < slotCount) { RectTransform val2 = Object.Instantiate(val, frameContainer); ((Object)val2).name = "InventoryItem"; list.Add(val2); } return list.ToArray(); } private static void RepositionSelectedItemName(UIInventory inventory, RectTransform container, Vector2 slotSize, int slotCount) { //IL_0033: 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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) TextMeshProUGUI fieldValue = HarmonyUtil.GetFieldValue(inventory, "currentSelectedItemNameText"); if (!((Object)(object)fieldValue == (Object)null)) { RectTransform component = ((Component)fieldValue).GetComponent(); if (!((Object)(object)component == (Object)null)) { int num = Mathf.Min(GetGridColumns(), slotCount); float x = CalculateSlotPosition(0, slotSize, slotCount).x; float x2 = CalculateSlotPosition(num - 1, slotSize, slotCount).x; float num2 = (x + x2) * 0.5f; float num3 = Mathf.Abs(x2 - x) + slotSize.x; Vector2 val = CalculateSlotPosition(0, slotSize, slotCount); ((Transform)component).SetParent((Transform)(object)container, false); SetRectTransformCenteredAnchor(component); component.anchoredPosition = new Vector2(num2, val.y + slotSize.y); component.sizeDelta = new Vector2(num3, component.sizeDelta.y); ((TMP_Text)fieldValue).alignment = (TextAlignmentOptions)514; ((TMP_Text)fieldValue).textWrappingMode = (TextWrappingModes)0; ((TMP_Text)fieldValue).margin = Vector4.zero; ((Transform)component).SetAsLastSibling(); } } } private static void RepositionInputPrompts(UIInventory inventory, RectTransform container, Vector2 slotSize, int slotCount) { //IL_0031: 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_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) CanvasGroup fieldValue = HarmonyUtil.GetFieldValue(inventory, "scrollCanvasGroup"); if (!((Object)(object)fieldValue == (Object)null)) { Transform parent = ((Component)fieldValue).transform.parent; RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null); if (!((Object)(object)val == (Object)null)) { float num = CalculateLeftHandSlotX(slotSize, slotCount); ((Transform)val).SetParent((Transform)(object)container, false); SetRectTransformCenteredAnchor(val); val.anchoredPosition = new Vector2(num - 75f, CalculateSlotPosition(slotCount - 1, slotSize, slotCount).y + 25f); ((Transform)val).localScale = Vector3.one; ((Transform)val).localRotation = Quaternion.identity; ((Transform)val).SetAsLastSibling(); } } } } public sealed class InventoryLockedSlotOverlay : MonoBehaviour { private const string OverlayName = "Artisan_LockedSlotOverlay"; private const string LockIconName = "Artisan_LockedSlotIcon"; private static readonly Vector2 OverlayInset = new Vector2(2f, 2f); private static readonly Vector2 LockIconSize = new Vector2(24f, 24f); private static readonly Vector2 LockIconOffset = new Vector2(0f, 4f); private static readonly Color OverlayColor = new Color(0.35f, 0.02f, 0.02f, 0.45f); private static readonly Color LockIconColor = new Color(0.86f, 0.9f, 0.92f, 0.96f); private GameObject overlayObject; private Image lockImage; public bool IsLocked { get; private set; } public void SetLocked(bool isLocked) { EnsureCreated(); SyncOverlayRect(); IsLocked = isLocked; if ((Object)(object)overlayObject != (Object)null) { overlayObject.SetActive(isLocked); } } private void EnsureCreated() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_007f: 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_00fd: Expected O, but got Unknown //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_015a: 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) //IL_018c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)overlayObject != (Object)null)) { overlayObject = new GameObject("Artisan_LockedSlotOverlay", new Type[3] { typeof(RectTransform), typeof(CanvasGroup), typeof(Image) }); overlayObject.transform.SetParent(((Component)this).transform, false); overlayObject.transform.SetAsLastSibling(); Image component = overlayObject.GetComponent(); ((Graphic)component).color = OverlayColor; ((Graphic)component).raycastTarget = false; CanvasGroup component2 = overlayObject.GetComponent(); component2.blocksRaycasts = false; component2.interactable = false; Sprite orCreate = TeleLockSpriteFactory.GetOrCreate(); if ((Object)(object)orCreate == (Object)null) { ArtisanMod.Logger.LogWarning((object)"Tele-lock mesh sprite could not be created. Locked slot icon will be hidden."); overlayObject.SetActive(false); return; } GameObject val = new GameObject("Artisan_LockedSlotIcon", new Type[2] { typeof(RectTransform), typeof(Image) }); val.transform.SetParent(overlayObject.transform, false); RectTransform component3 = val.GetComponent(); component3.anchorMin = new Vector2(0.5f, 0.5f); component3.anchorMax = new Vector2(0.5f, 0.5f); component3.pivot = new Vector2(0.5f, 0.5f); component3.sizeDelta = LockIconSize; component3.anchoredPosition = LockIconOffset; lockImage = val.GetComponent(); lockImage.sprite = orCreate; ((Graphic)lockImage).color = LockIconColor; ((Graphic)lockImage).raycastTarget = false; lockImage.preserveAspect = true; overlayObject.SetActive(false); } } private void SyncOverlayRect() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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) if (!((Object)(object)overlayObject == (Object)null)) { RectTransform component = overlayObject.GetComponent(); if (!((Object)(object)component == (Object)null)) { component.anchorMin = Vector2.zero; component.anchorMax = Vector2.one; component.pivot = new Vector2(0.5f, 0.5f); component.offsetMin = OverlayInset; component.offsetMax = -OverlayInset; ((Transform)component).localScale = Vector3.one; ((Transform)component).localRotation = Quaternion.identity; overlayObject.transform.SetAsLastSibling(); } } } } [HarmonyPatch] public static class InventoryLockedSlotOverlayPatch { [HarmonyPatch(typeof(UIInventory), "RefreshInventoryDisplay")] [HarmonyPostfix] private static void RefreshInventoryDisplayPostfix(UIInventory __instance) { Refresh(__instance); } public static void RefreshCurrentInventory() { if (!((Object)(object)UIManager.Instance == (Object)null) && !((Object)(object)UIManager.Instance.uiGame == (Object)null) && !((Object)(object)UIManager.Instance.uiGame.uiPlayer == (Object)null) && !((Object)(object)UIManager.Instance.uiGame.uiPlayer.uiInventory == (Object)null)) { Refresh(UIManager.Instance.uiGame.uiPlayer.uiInventory); } } private static void Refresh(UIInventory inventoryUi) { if ((Object)(object)inventoryUi == (Object)null) { return; } PawnInventory fieldValue = HarmonyUtil.GetFieldValue(inventoryUi, "_playerInventory"); if ((Object)(object)fieldValue == (Object)null) { return; } UIInventorySlot[] fieldValue2 = HarmonyUtil.GetFieldValue(inventoryUi, "inventorySlots"); if (fieldValue2 == null) { return; } foreach (UIInventorySlot val in fieldValue2) { if (!((Object)(object)val == (Object)null)) { InventoryLockedSlotOverlay inventoryLockedSlotOverlay = ((Component)val).GetComponent(); if ((Object)(object)inventoryLockedSlotOverlay == (Object)null) { inventoryLockedSlotOverlay = ((Component)val).gameObject.AddComponent(); } bool locked = InventorySlotUpgradeService.IsEnabled() && !InventorySlotUpgradeService.IsSlotUnlocked(fieldValue, val.SlotIndex); inventoryLockedSlotOverlay.SetLocked(locked); } } } } [HarmonyPatch(typeof(UIInventory), "OnStartPawnAuthorityChanged")] public static class InventorySlotExpansionPatch { public static void Prefix(UIInventory __instance) { if ((Object)(object)__instance == (Object)null || !InventorySlotCapacityPatch.IsEnabled()) { return; } UIInventorySlot[] fieldValue = HarmonyUtil.GetFieldValue(__instance, "inventorySlots"); int maxInventorySlots = InventorySlotCapacityPatch.GetMaxInventorySlots(); if (fieldValue == null || fieldValue.Length == 0 || fieldValue.Length >= maxInventorySlots) { return; } UIInventorySlot val = fieldValue[0]; if ((Object)(object)val == (Object)null) { return; } Transform parent = ((Component)val).transform.parent; if ((Object)(object)parent == (Object)null) { return; } UIInventorySlot[] array = (UIInventorySlot[])(object)new UIInventorySlot[maxInventorySlots]; for (int i = 0; i < fieldValue.Length; i++) { array[i] = fieldValue[i]; } for (int j = fieldValue.Length; j < maxInventorySlots; j++) { GameObject val2 = Object.Instantiate(((Component)val).gameObject, parent); ((Object)val2).name = "ArtisanInventorySlot_" + j; val2.SetActive(true); UIInventorySlot component = val2.GetComponent(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)val2); continue; } ((TMP_Text)GetSlotKeyText(component)).text = (j + 1).ToString(); LayoutElement component2 = val2.GetComponent(); if ((Object)(object)component2 != (Object)null) { component2.ignoreLayout = true; } array[j] = component; } HarmonyUtil.SetFieldValue(__instance, "inventorySlots", array); } private static TextMeshProUGUI GetSlotKeyText(UIInventorySlot slot) { if ((Object)(object)slot == (Object)null) { return null; } Transform val = ((Component)slot).transform.Find("Key"); if ((Object)(object)val == (Object)null) { return null; } return ((Component)val).GetComponent(); } } public static class TeleLockSpriteFactory { private const string MeshName = "SM_VFX_Tele_Lock_03"; private static Sprite cachedSprite; public static Sprite GetOrCreate() { if ((Object)(object)cachedSprite != (Object)null) { return cachedSprite; } Mesh val = FindTeleLockMesh(); if ((Object)(object)val == (Object)null) { return null; } cachedSprite = RenderMeshToSprite(val); if ((Object)(object)cachedSprite != (Object)null) { ((Object)cachedSprite).name = "Artisan_TeleLockSprite"; } return cachedSprite; } private static Mesh FindTeleLockMesh() { Mesh[] array = Resources.FindObjectsOfTypeAll(); foreach (Mesh val in array) { if (!((Object)(object)val == (Object)null) && (((Object)val).name == "SM_VFX_Tele_Lock_03" || ((Object)val).name.Contains("SM_VFX_Tele_Lock_03"))) { return val; } } ArtisanMod.Logger.LogWarning((object)"Could not find mesh asset: SM_VFX_Tele_Lock_03"); return null; } private static void RemoveBlackBackground(Texture2D texture) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) Color[] pixels = texture.GetPixels(); for (int i = 0; i < pixels.Length; i++) { Color val = pixels[i]; if (val.r < 0.03f && val.g < 0.03f && val.b < 0.03f) { pixels[i] = new Color(0f, 0f, 0f, 0f); } } texture.SetPixels(pixels); texture.Apply(); } private static Sprite RenderMeshToSprite(Mesh mesh) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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) //IL_00e2: Expected O, but got Unknown //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Expected O, but got Unknown //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_015e: 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_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Expected O, but got Unknown //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) RenderTexture val = null; GameObject val2 = null; GameObject val3 = null; Material val4 = null; RenderTexture active = RenderTexture.active; try { val = new RenderTexture(128, 128, 24, (RenderTextureFormat)0); ((Object)val).name = "Artisan_TeleLockRenderTexture"; val.antiAliasing = 4; val.Create(); val2 = new GameObject("Artisan_TeleLockRenderCamera"); Camera obj = val2.AddComponent(); obj.clearFlags = (CameraClearFlags)2; obj.backgroundColor = new Color(0f, 0f, 0f, 0f); obj.orthographic = true; obj.orthographicSize = 0.7f; obj.nearClipPlane = 0.01f; obj.farClipPlane = 10f; ((Component)obj).transform.position = new Vector3(0f, 0f, -3f); ((Component)obj).transform.rotation = Quaternion.identity; obj.targetTexture = val; ((Behaviour)obj).enabled = false; val3 = new GameObject("Artisan_TeleLockRenderMesh"); MeshFilter obj2 = val3.AddComponent(); MeshRenderer val5 = val3.AddComponent(); obj2.sharedMesh = mesh; Shader val6 = Shader.Find("Unlit/Color"); if ((Object)(object)val6 == (Object)null) { val6 = Shader.Find("UI/Default"); } if ((Object)(object)val6 == (Object)null) { val6 = Shader.Find("Sprites/Default"); } val4 = new Material(val6); val4.color = Color.white; ((Renderer)val5).sharedMaterial = val4; val3.transform.rotation = Quaternion.Euler(-90f, 0f, 180f); Bounds bounds = mesh.bounds; float num = Mathf.Max(((Bounds)(ref bounds)).size.x, Mathf.Max(((Bounds)(ref bounds)).size.y, ((Bounds)(ref bounds)).size.z)); if (num > 0f) { val3.transform.localScale = Vector3.one * (1f / num); } val3.transform.position = -((Bounds)(ref bounds)).center * val3.transform.localScale.x; obj.Render(); RenderTexture.active = val; Texture2D val7 = new Texture2D(128, 128, (TextureFormat)4, false); ((Object)val7).name = "Artisan_TeleLockTexture"; val7.ReadPixels(new Rect(0f, 0f, 128f, 128f), 0, 0); val7.Apply(); RemoveBlackBackground(val7); return Sprite.Create(val7, new Rect(0f, 0f, (float)((Texture)val7).width, (float)((Texture)val7).height), new Vector2(0.5f, 0.5f), 128f); } finally { RenderTexture.active = active; if ((Object)(object)val2 != (Object)null) { Object.Destroy((Object)(object)val2); } if ((Object)(object)val3 != (Object)null) { Object.Destroy((Object)(object)val3); } if ((Object)(object)val4 != (Object)null) { Object.Destroy((Object)(object)val4); } if ((Object)(object)val != (Object)null) { val.Release(); Object.Destroy((Object)(object)val); } } } } } namespace Artisan.Features.Inventory.Services { public static class InventorySlotUpgradeService { private const int VanillaSlotCount = 3; private const string UnlockedExtraSlotsKey = ".UNLOCKED_EXTRA_SLOTS"; public static bool IsEnabled() { if (InventorySlotCapacityPatch.IsEnabled()) { return ArtisanMod.Settings.Inventory.EnableSlotUpgrades.Value; } return false; } public static int GetMaxExtraSlots() { return Mathf.Max(0, InventorySlotCapacityPatch.GetMaxInventorySlots() - 3); } public static int GetUnlockedExtraSlots(PawnInventory inventory) { if (!IsEnabled()) { return GetMaxExtraSlots(); } Pawn pawn = GetPawn(inventory); if ((Object)(object)pawn == (Object)null || string.IsNullOrEmpty(pawn.PlayerId)) { return 0; } SaveManager val = default(SaveManager); if (!Service.Get(ref val)) { return 0; } int num = default(int); if (!val.TryGetInt(GetUnlockedExtraSlotsKey(pawn.PlayerId), ref num)) { return 0; } return Mathf.Clamp(num, 0, GetMaxExtraSlots()); } public static int GetUnlockedSlotCount(PawnInventory inventory) { return 3 + GetUnlockedExtraSlots(inventory); } public static bool IsSlotUnlocked(PawnInventory inventory, int slotIndex) { if (slotIndex < 3) { return true; } if (slotIndex >= 0) { return slotIndex < GetUnlockedSlotCount(inventory); } return false; } public static int GetNextUpgradePrice(PawnInventory inventory) { int unlockedExtraSlots = GetUnlockedExtraSlots(inventory); int num = Mathf.Max(0, ArtisanMod.Settings.Inventory.ExtraSlotBasePrice.Value); float num2 = Mathf.Max(1f, ArtisanMod.Settings.Inventory.ExtraSlotPriceMultiplier.Value); return Mathf.CeilToInt((float)num * Mathf.Pow(num2, (float)unlockedExtraSlots)); } public static bool CanPurchaseNextUpgrade(PawnInventory inventory) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (!IsEnabled()) { return false; } if (!NetworkServer.active) { return false; } if ((Object)(object)GameManager.Instance == (Object)null || (int)GameManager.Instance.CurrentGameState != 0) { return false; } Pawn pawn = GetPawn(inventory); if ((Object)(object)pawn == (Object)null || string.IsNullOrEmpty(pawn.PlayerId)) { return false; } if (GetUnlockedExtraSlots(inventory) >= GetMaxExtraSlots()) { return false; } return GameManager.Instance.Gold >= GetNextUpgradePrice(inventory); } public static bool TryPurchaseNextUpgrade(PawnInventory inventory) { if (!CanPurchaseNextUpgrade(inventory)) { return false; } Pawn pawn = GetPawn(inventory); SaveManager val = default(SaveManager); if ((Object)(object)pawn == (Object)null || !Service.Get(ref val)) { return false; } int nextUpgradePrice = GetNextUpgradePrice(inventory); int num = GetUnlockedExtraSlots(inventory) + 1; GameManager.Instance.ModifyGold(-nextUpgradePrice); val.SetInt(GetUnlockedExtraSlotsKey(pawn.PlayerId), num); inventory.ServerPersistInventory(); return true; } public static int GetFirstUnlockedEmptySlot(PawnInventory inventory) { //IL_0034: 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) if ((Object)(object)inventory == (Object)null) { return -1; } int unlockedSlotCount = GetUnlockedSlotCount(inventory); for (int i = 0; i < unlockedSlotCount; i++) { if (!IsSlotUnlocked(inventory, i)) { continue; } if (i < inventory.Items.Count) { InventoryItem val = inventory.Items[i]; if (!((InventoryItem)(ref val)).IsEmpty) { continue; } } return i; } return -1; } private static Pawn GetPawn(PawnInventory inventory) { if (!((Object)(object)inventory == (Object)null)) { return ((Component)inventory).GetComponent(); } return null; } private static string GetUnlockedExtraSlotsKey(string playerId) { return "PLAYER." + playerId + ".INV.UNLOCKED_EXTRA_SLOTS"; } } } namespace Artisan.Features.Inventory.Patches { [HarmonyPatch] public static class InventoryExtendedPersistencePatch { private static readonly HashSet RestoringInventories = new HashSet(); [HarmonyPatch(typeof(PawnInventory), "ServerTryRestoreFromKvp")] [HarmonyPrefix] private static void ServerTryRestoreFromKvpPrefix(PawnInventory __instance, SaveManager save, string playerId) { if (!CanHandle(__instance, save, playerId)) { return; } RestoringInventories.Add(__instance); try { DropSavedOverflowSlots(__instance, save, playerId); } catch (Exception ex) { ArtisanMod.Logger.LogWarning((object)("[InventoryPersistence] Failed to drop saved overflow slots: " + ex.Message)); } } [HarmonyPatch(typeof(PawnInventory), "ServerTryRestoreFromKvp")] [HarmonyPostfix] private static void ServerTryRestoreFromKvpPostfix(PawnInventory __instance, SaveManager save, string playerId) { if (!CanHandle(__instance, save, playerId)) { return; } try { RestoreExtendedSlots(__instance, save, playerId); } catch (Exception ex) { ArtisanMod.Logger.LogWarning((object)("[InventoryPersistence] Failed to restore extended slots: " + ex.Message)); } finally { RestoringInventories.Remove(__instance); } __instance.ServerPersistInventory(); } [HarmonyPatch(typeof(PawnInventory), "ServerSerializeToKvp")] [HarmonyPostfix] private static void ServerSerializeToKvpPostfix(PawnInventory __instance, SaveManager save, string playerId) { if (!CanHandle(__instance, save, playerId) || RestoringInventories.Contains(__instance)) { return; } try { SerializeExtendedSlots(__instance, save, playerId); } catch (Exception ex) { ArtisanMod.Logger.LogWarning((object)("[InventoryPersistence] Failed to serialize extended slots: " + ex.Message)); } } private static bool CanHandle(PawnInventory inventory, SaveManager save, string playerId) { if ((Object)(object)inventory != (Object)null && (Object)(object)save != (Object)null && !string.IsNullOrEmpty(playerId)) { return InventorySlotCapacityPatch.IsEnabled(); } return false; } private static void SerializeExtendedSlots(PawnInventory inventory, SaveManager save, string playerId) { string keyPrefix = GetKeyPrefix(playerId); int maxInventorySlots = InventorySlotCapacityPatch.GetMaxInventorySlots(); save.SetInt(keyPrefix + ".SLOT_COUNT", maxInventorySlots); save.SetInt(keyPrefix + ".MAIN", Mathf.Clamp(inventory.CurrentMainHandSlot, 0, maxInventorySlots - 1)); MethodInfo methodInfo = AccessTools.Method(typeof(PawnInventory), "SerializeProp", (Type[])null, (Type[])null); if (!(methodInfo == null)) { for (int i = 0; i < maxInventorySlots; i++) { NetworkPuppetProp slotProp = GetSlotProp(inventory, i); methodInfo.Invoke(inventory, new object[3] { save, $"{keyPrefix}.S{i}", slotProp }); } } } private static void RestoreExtendedSlots(PawnInventory inventory, SaveManager save, string playerId) { //IL_006d: 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_00ba: Unknown result type (might be due to invalid IL or missing references) string keyPrefix = GetKeyPrefix(playerId); int maxInventorySlots = InventorySlotCapacityPatch.GetMaxInventorySlots(); MethodInfo methodInfo = AccessTools.Method(typeof(PawnInventory), "TryRestoreProp", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(PawnInventory), "ServerAddItemToSlot", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { return; } for (int i = 3; i < maxInventorySlots; i++) { if (i < inventory.Items.Count) { InventoryItem val = inventory.Items[i]; if (!((InventoryItem)(ref val)).IsEmpty) { continue; } } NetworkPuppetProp val2 = TryRestoreProp(inventory, save, playerId, $"{keyPrefix}.S{i}", methodInfo); if (!((Object)(object)val2 == (Object)null)) { if ((bool)methodInfo2.Invoke(inventory, new object[2] { i, (object)new InventoryItem(val2) })) { SetPropInInventory(val2, inventory); } else { DropRestoredOverflowProp(val2); } } } RestoreSelectedMainSlot(inventory, save, keyPrefix, maxInventorySlots); NormalizeRestoredInventoryProps(inventory); } private static void DropSavedOverflowSlots(PawnInventory inventory, SaveManager save, string playerId) { string keyPrefix = GetKeyPrefix(playerId); int maxInventorySlots = InventorySlotCapacityPatch.GetMaxInventorySlots(); int num = default(int); if (!save.TryGetInt(keyPrefix + ".SLOT_COUNT", ref num) || num <= maxInventorySlots) { return; } MethodInfo methodInfo = AccessTools.Method(typeof(PawnInventory), "TryRestoreProp", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(PawnInventory), "SerializeProp", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { return; } for (int i = maxInventorySlots; i < num; i++) { string text = $"{keyPrefix}.S{i}"; NetworkPuppetProp val = TryRestoreProp(inventory, save, playerId, text, methodInfo); if (!((Object)(object)val == (Object)null)) { DropRestoredOverflowProp(val); ClearSavedSlot(inventory, save, text, methodInfo2); ArtisanMod.Logger.LogInfo((object)$"Dropped overflow inventory item from saved slot {i + 1}."); } } } private static NetworkPuppetProp TryRestoreProp(PawnInventory inventory, SaveManager save, string playerId, string key, MethodInfo tryRestoreProp) { object[] array = new object[4] { save, key, playerId, null }; if (!(bool)tryRestoreProp.Invoke(inventory, array)) { return null; } object obj = array[3]; return (NetworkPuppetProp)((obj is NetworkPuppetProp) ? obj : null); } private static void ClearSavedSlot(PawnInventory inventory, SaveManager save, string slotKey, MethodInfo serializeProp) { serializeProp.Invoke(inventory, new object[3] { save, slotKey, null }); } private static NetworkPuppetProp GetSlotProp(PawnInventory inventory, int slotIndex) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (slotIndex < 0 || slotIndex >= inventory.Items.Count) { return null; } InventoryItem val = inventory.Items[slotIndex]; if (!((InventoryItem)(ref val)).IsEmpty) { return ((InventoryItem)(ref val)).PropInstance; } return null; } private static void DropRestoredOverflowProp(NetworkPuppetProp prop) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)prop == (Object)null)) { prop.IsShopItem = false; prop.ServerHandleDrop(true, default(Vector3)); ((Interactable)prop).RefreshLocalInteractable(); } } private static void SetPropInInventory(NetworkPuppetProp prop, PawnInventory inventory) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)prop == (Object)null) && !((Object)(object)inventory == (Object)null)) { object? obj = AccessTools.Field(typeof(PawnInventory), "propInteractions")?.GetValue(inventory); PawnPropInteractions val = (PawnPropInteractions)((obj is PawnPropInteractions) ? obj : null); if ((Object)(object)val != (Object)null) { prop.ServerSetInInventory(val); } else { prop.CurrentState = new PropStateData((PropState)2, (PawnPropInteractions)null, true); } } } private static void NormalizeRestoredInventoryProps(PawnInventory inventory) { if ((Object)(object)inventory == (Object)null) { return; } int currentMainHandSlot = inventory.CurrentMainHandSlot; for (int i = 0; i < inventory.Items.Count; i++) { if (i != currentMainHandSlot) { NetworkPuppetProp slotProp = GetSlotProp(inventory, i); if ((Object)(object)slotProp != (Object)null) { SetPropInInventory(slotProp, inventory); } } } if ((Object)(object)GetSlotProp(inventory, currentMainHandSlot) != (Object)null) { inventory.SelectSlotWithMainHand(currentMainHandSlot); } } private static void RestoreSelectedMainSlot(PawnInventory inventory, SaveManager save, string keyPrefix, int maxSlots) { int num = default(int); if (save.TryGetInt(keyPrefix + ".MAIN", ref num)) { num = Mathf.Clamp(num, 0, maxSlots - 1); if (!((Object)(object)GetSlotProp(inventory, num) == (Object)null)) { inventory.SelectSlotWithMainHand(num); } } } private static string GetKeyPrefix(string playerId) { return "PLAYER." + playerId + ".INV"; } } [HarmonyPatch(typeof(UIInventory), "Update")] public static class InventoryExtendedHotkeysPatch { private static void Postfix(UIInventory __instance) { if (!InventorySlotCapacityPatch.IsEnabled()) { return; } PawnInventory fieldValue = HarmonyUtil.GetFieldValue(__instance, "_playerInventory"); if ((Object)(object)fieldValue == (Object)null) { return; } int maxInventorySlots = InventorySlotCapacityPatch.GetMaxInventorySlots(); for (int i = 3; i < maxInventorySlots; i++) { if (InventorySlotUpgradeService.IsSlotUnlocked(fieldValue, i)) { InputAction slotAction = InventorySlotRebindSettings.GetSlotAction(i); if (slotAction != null && slotAction.WasPressedThisFrame()) { fieldValue.CmdSelectSlotWithMainHand(i); break; } } } } } [HarmonyPatch] public static class InventoryLockedSlotPatch { [HarmonyPatch(typeof(PawnInventory), "SelectSlotWithMainHand")] [HarmonyPrefix] private static bool SelectSlotWithMainHandPrefix(PawnInventory __instance, int slotIndex) { return IsSlotSelectionAllowed(__instance, slotIndex); } [HarmonyPatch(typeof(PawnInventory), "UserCode_CmdSelectSlotWithMainHand__Int32")] [HarmonyPrefix] private static bool CmdSelectSlotPrefix(PawnInventory __instance, int slotIndex) { return IsSlotSelectionAllowed(__instance, slotIndex); } [HarmonyPatch(typeof(PawnInventory), "UserCode_CmdSwapSlotWithRightHand__Int32")] [HarmonyPrefix] private static bool CmdSwapSlotPrefix(PawnInventory __instance, int slotIndex) { return IsSlotSelectionAllowed(__instance, slotIndex); } [HarmonyPatch(typeof(PawnInventory), "UserCode_CmdMoveItemInInventory__UInt32__Int32")] [HarmonyPrefix] private static bool CmdMoveItemPrefix(PawnInventory __instance, uint sourcePropNetId, int targetSlotIndex) { return IsSlotSelectionAllowed(__instance, targetSlotIndex); } [HarmonyPatch(typeof(PawnInventory), "UserCode_CmdCycleSlot__Boolean")] [HarmonyPrefix] private static bool CmdCycleSlotPrefix(PawnInventory __instance, bool cycleForward) { if (!InventorySlotUpgradeService.IsEnabled()) { return true; } return TryCycleToUnlockedSlot(__instance, cycleForward); } [HarmonyPatch(typeof(PawnInventory), "UserCode_CmdAttemptPickup__NetworkPuppetProp")] [HarmonyPrefix] private static bool CmdAttemptPickupPrefix(PawnInventory __instance, NetworkPuppetProp prop) { if (!InventorySlotUpgradeService.IsEnabled()) { return true; } if (InventorySlotUpgradeService.IsSlotUnlocked(__instance, __instance.CurrentMainHandSlot)) { return true; } __instance.ServerTryPickup(prop, 0); return false; } [HarmonyPatch(typeof(PawnInventory), "ServerTryPickup")] [HarmonyPrefix] private static bool ServerTryPickupPrefix(PawnInventory __instance, NetworkPuppetProp prop, int preferredSlotIndex, ref bool __result) { if (!InventorySlotUpgradeService.IsEnabled()) { return true; } __result = TryPickupInUnlockedSpace(__instance, prop, preferredSlotIndex); return false; } [HarmonyPatch(typeof(PawnInventory), "ServerTryPickupInventorySlotOnly")] [HarmonyPrefix] private static bool ServerTryPickupInventorySlotOnlyPrefix(PawnInventory __instance, int slotIndex, ref bool __result) { if (!InventorySlotUpgradeService.IsEnabled()) { return true; } if (InventorySlotUpgradeService.IsSlotUnlocked(__instance, slotIndex)) { return true; } __result = false; return false; } [HarmonyPatch(typeof(UIInventory), "OnSlotDrop")] [HarmonyPrefix] private static bool OnSlotDropPrefix(UIInventory __instance, UIInventorySlot targetSlot) { PawnInventory playerInventory = GetPlayerInventory(__instance); UIInventorySlot draggedSlot = GetDraggedSlot(__instance); if (!IsDropBlocked(playerInventory, targetSlot, draggedSlot)) { return true; } __instance.StopDrag(); return false; } [HarmonyPatch(typeof(UIInventory), "OnDragHoverEnter")] [HarmonyPrefix] private static bool OnDragHoverEnterPrefix(UIInventory __instance, UIInventorySlot slot) { return !IsLockedInventorySlot(GetPlayerInventory(__instance), slot); } [HarmonyPatch(typeof(UIInventorySlot), "OnBeginDrag")] [HarmonyPrefix] private static bool OnBeginDragPrefix(UIInventorySlot __instance) { return !IsLockedInventorySlot(GetPlayerInventory(HarmonyUtil.GetFieldValue(__instance, "_inventory")), __instance); } [HarmonyPatch(typeof(PawnInventory), "TryRestoreIfPossible")] [HarmonyPostfix] private static void TryRestoreIfPossiblePostfix(PawnInventory __instance) { DropItemsFromLockedSlots(__instance); } [HarmonyPatch(typeof(NetworkPuppetProp), "ShowTooltip")] [HarmonyPrefix] private static bool NetworkPuppetPropShowTooltipPrefix(NetworkPuppetProp __instance, NetworkIdentity identity) { if (!InventorySlotUpgradeService.IsEnabled()) { return true; } PawnInventory inventory = GetInventory(identity); if ((Object)(object)inventory == (Object)null || HasAvailablePickupSpace(inventory)) { return true; } ShowInventoryFullTooltip(__instance); return false; } [HarmonyPatch(typeof(PropIngredient), "CustomTooltipAction")] [HarmonyPostfix] private static void PropIngredientCustomTooltipActionPostfix(PropIngredient __instance, Interactable interactable, NetworkIdentity identity) { if (!InventorySlotUpgradeService.IsEnabled()) { return; } PawnInventory inventory = GetInventory(identity); if (!((Object)(object)inventory == (Object)null) && !HasAvailablePickupSpace(inventory)) { NetworkPuppetProp val = ResolvePuppetProp(__instance, interactable); if (!((Object)(object)val == (Object)null)) { ShowIngredientInventoryFullTooltip(val); } } } public static void DropItemsFromLockedSlots(PawnInventory inventory) { if (!NetworkServer.active || (Object)(object)inventory == (Object)null || !InventorySlotUpgradeService.IsEnabled()) { return; } bool flag = false; for (int i = 0; i < inventory.Items.Count; i++) { if (!InventorySlotUpgradeService.IsSlotUnlocked(inventory, i) && DropItemFromLockedSlot(inventory, i)) { flag = true; } } if (flag) { inventory.ServerPersistInventory(); } } private static bool DropItemFromLockedSlot(PawnInventory inventory, int slotIndex) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) if (slotIndex < 0 || slotIndex >= inventory.Items.Count) { return false; } InventoryItem val = inventory.Items[slotIndex]; if (((InventoryItem)(ref val)).IsEmpty || val.propNetId == 0) { return false; } NetworkPuppetProp val2 = inventory.SvGetPropFromNetId(val.propNetId); if ((Object)(object)val2 == (Object)null) { return false; } if (!inventory.ServerRemoveItem(val.propNetId)) { return false; } val2.IsShopItem = false; val2.ServerHandleDrop(true, default(Vector3)); ((Interactable)val2).RefreshLocalInteractable(); return true; } private static bool IsSlotSelectionAllowed(PawnInventory inventory, int slotIndex) { return InventorySlotUpgradeService.IsSlotUnlocked(inventory, slotIndex); } private static bool TryCycleToUnlockedSlot(PawnInventory inventory, bool cycleForward) { if ((Object)(object)inventory == (Object)null) { return false; } int unlockedSlotCount = InventorySlotUpgradeService.GetUnlockedSlotCount(inventory); if (unlockedSlotCount <= 0) { return false; } int num = inventory.CurrentMainHandSlot; for (int i = 0; i < unlockedSlotCount; i++) { num = GetNextSlotIndex(num, unlockedSlotCount, cycleForward); if (InventorySlotUpgradeService.IsSlotUnlocked(inventory, num)) { inventory.SelectSlotWithMainHand(num); return false; } } return false; } private static int GetNextSlotIndex(int currentSlot, int slotCount, bool cycleForward) { int num = (cycleForward ? (currentSlot - 1) : (currentSlot + 1)); if (num < 0) { return slotCount - 1; } if (num >= slotCount) { return 0; } return num; } private static bool TryPickupInUnlockedSpace(PawnInventory inventory, NetworkPuppetProp prop, int preferredSlotIndex) { if ((Object)(object)inventory == (Object)null || (Object)(object)prop == (Object)null || !prop.CanPickedUpBy(((NetworkBehaviour)inventory).netIdentity)) { return false; } int slotIndex = ResolvePreferredSlot(inventory, preferredSlotIndex); if (TryPickupIntoSlot(inventory, prop, slotIndex)) { return true; } if (TryPickupIntoLeftHand(inventory, prop)) { return true; } int firstUnlockedEmptySlot = InventorySlotUpgradeService.GetFirstUnlockedEmptySlot(inventory); if (firstUnlockedEmptySlot >= 0) { return inventory.ServerTryPickupInventorySlotOnly(prop, firstUnlockedEmptySlot); } return false; } private static int ResolvePreferredSlot(PawnInventory inventory, int preferredSlotIndex) { if (preferredSlotIndex != -1) { return preferredSlotIndex; } return inventory.CurrentMainHandSlot; } private static bool TryPickupIntoSlot(PawnInventory inventory, NetworkPuppetProp prop, int slotIndex) { if (InventorySlotUpgradeService.IsSlotUnlocked(inventory, slotIndex)) { return inventory.ServerTryPickupInventorySlotOnly(prop, slotIndex); } return false; } private static bool TryPickupIntoLeftHand(PawnInventory inventory, NetworkPuppetProp prop) { PawnPropInteractions propInteractions = GetPropInteractions(inventory); if ((Object)(object)propInteractions == (Object)null || (Object)(object)propInteractions.NetworkCurrentLeftHandNetworkProp != (Object)null) { return false; } prop.ServerHandleHeld(propInteractions, false); return true; } private static bool HasAvailablePickupSpace(PawnInventory inventory) { if ((Object)(object)inventory == (Object)null) { return false; } if (InventorySlotUpgradeService.GetFirstUnlockedEmptySlot(inventory) >= 0) { return true; } PawnPropInteractions propInteractions = GetPropInteractions(inventory); if ((Object)(object)propInteractions != (Object)null) { return (Object)(object)propInteractions.NetworkCurrentLeftHandNetworkProp == (Object)null; } return false; } private static bool IsDropBlocked(PawnInventory inventory, UIInventorySlot targetSlot, UIInventorySlot draggedSlot) { if ((Object)(object)inventory == (Object)null || (Object)(object)targetSlot == (Object)null) { return false; } if (!IsLockedInventorySlot(inventory, targetSlot)) { return IsLockedInventorySlot(inventory, draggedSlot); } return true; } private static bool IsLockedInventorySlot(PawnInventory inventory, UIInventorySlot slot) { if ((Object)(object)inventory == (Object)null || (Object)(object)slot == (Object)null || slot.IsHandSlot) { return false; } return !InventorySlotUpgradeService.IsSlotUnlocked(inventory, slot.SlotIndex); } private static PawnInventory GetInventory(NetworkIdentity identity) { if (!((Object)(object)identity == (Object)null)) { return ((Component)identity).GetComponent(); } return null; } private static PawnInventory GetPlayerInventory(UIInventory inventoryUi) { if (!((Object)(object)inventoryUi == (Object)null)) { return HarmonyUtil.GetFieldValue(inventoryUi, "_playerInventory"); } return null; } private static UIInventorySlot GetDraggedSlot(UIInventory inventoryUi) { if (!((Object)(object)inventoryUi == (Object)null)) { return HarmonyUtil.GetFieldValue(inventoryUi, "_draggedSlot"); } return null; } private static PawnPropInteractions GetPropInteractions(PawnInventory inventory) { if ((Object)(object)inventory == (Object)null) { return null; } PawnPropInteractions fieldValue = HarmonyUtil.GetFieldValue(inventory, "propInteractions"); if (!((Object)(object)fieldValue != (Object)null)) { return ((Component)inventory).GetComponent(); } return fieldValue; } private static NetworkPuppetProp ResolvePuppetProp(PropIngredient ingredient, Interactable interactable) { NetworkPuppetProp val = (NetworkPuppetProp)(object)((interactable is NetworkPuppetProp) ? interactable : null); if (val != null) { return val; } if (!((Object)(object)ingredient == (Object)null)) { return ((Component)ingredient).GetComponent(); } return null; } private static void ShowInventoryFullTooltip(NetworkPuppetProp prop) { UIManager instance = UIManager.Instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.uiTooltip == (Object)null) && !((Object)(object)prop == (Object)null)) { string text = prop.DisplayName + " (" + instance.uiTooltip.InventoryFullStr + ")"; instance.uiTooltip.ShowTooltip(text, (InputTarget)2, false, false, prop.IsGrabable ? instance.uiTooltip.DefaultGrabStr : string.Empty, (InputTarget)8, prop.IsGrabable, false, (string)null, (InputTarget)9, true, false); } } private static void ShowIngredientInventoryFullTooltip(NetworkPuppetProp prop) { UIManager instance = UIManager.Instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.uiTooltip == (Object)null) && !((Object)(object)prop == (Object)null)) { string text = prop.DisplayName + " (" + instance.uiTooltip.InventoryFullStr + ")"; instance.uiTooltip.ShowTooltip(text, (InputTarget)2, false, false, (string)null, (InputTarget)8, prop.IsGrabable, false, prop.IsGrabable ? instance.uiTooltip.DefaultGrabStr : string.Empty, (InputTarget)8, prop.IsGrabable, false); } } } [HarmonyPatch(typeof(UISettings))] public static class InventorySlotRebindSettingsPatch { [HarmonyPatch("Awake")] [HarmonyPrefix] private static void BeforeAwake() { InventorySlotRebindSettings.RemoveLegacyArtisanOverridesFromGamePrefs(); } [HarmonyPatch("Awake")] [HarmonyPostfix] private static void AfterAwake(UISettings __instance) { InventorySlotRebindSettings.Install(__instance); } [HarmonyPatch("OnDisable")] [HarmonyPostfix] private static void AfterOnDisable() { InventorySlotRebindSettings.SaveOverrides(); InventorySlotRebindSettings.SaveGameOverridesWithoutArtisanBindings(); } } [HarmonyPatch(typeof(UISettingRebind), "UpdateBindingDisplay")] public static class InventorySlotRebindDisplayPatch { private static bool Prefix(UISettingRebind __instance) { return !InventorySlotRebindSettings.TryUpdateDisplay(__instance); } } [HarmonyPatch(typeof(UISettingRebind), "Localise")] public static class InventorySlotRebindLocalisePatch { private static void Postfix(UISettingRebind __instance) { InventorySlotRebindSettings.RefreshLabel(__instance); } } [HarmonyPatch(typeof(UISettingRebind), "ResetToDefault")] public static class InventorySlotRebindResetPatch { private static bool Prefix(UISettingRebind __instance) { return !InventorySlotRebindSettings.TryResetToDefault(__instance); } } public static class InventorySlotRebindSettings { private const int FirstExtraSlotIndex = 3; private const string ActionMapName = "Artisan Inventory"; private const string HotkeyObjectPrefix = "ArtisanInventorySlotHotkey_"; private const string GameOverridePrefsKey = "rebinds"; private const string LegacyOverridePrefsKey = "artisan_inventory_slot_rebinds"; private const string OverridePrefsKeyPrefix = "artisan_inventory_slot_rebind_"; private const string KeyboardContentPath = "Window/Content/SettingsSection/Sec_Controls/KeyboardScrollView/Viewport/Content"; private const string SlotLabelKey = "inventory.controls.slot"; private const string UnboundLabelKey = "inventory.controls.unbound"; private const string KeyboardPathPrefix = "/"; private const string KeyboardMouseGroup = "Keyboard&Mouse"; private const string InputActionAssetFieldName = "inputActionAsset"; private const string RebindActionFieldName = "m_Action"; private const string RebindBindingIdFieldName = "m_BindingId"; private const string RebindInputFieldName = "input"; private const string RebindResetButtonFieldName = "resetButton"; private static readonly FieldInfo InputActionAssetMapsField = AccessTools.Field(typeof(InputActionAsset), "m_ActionMaps"); private static readonly FieldInfo InputActionMapAssetField = AccessTools.Field(typeof(InputActionMap), "m_Asset"); private static readonly Dictionary SlotActions = new Dictionary(); private static readonly HashSet InstalledSettingsIds = new HashSet(); private static readonly List> InstalledSettings = new List>(); private static readonly Dictionary SetKeyMethods = new Dictionary(); private static InputActionAsset inputActionAsset; private static InputActionMap actionMap; private static bool isSubscribedToConfigChanges; private static int lastMaxSlots = -1; public static void Install(UISettings settings) { if ((Object)(object)settings == (Object)null) { return; } SubscribeToConfigChanges(); if (ArtisanMod.Settings.Inventory.EnableExtraSlotControlBindings.Value) { RegisterTranslations(); inputActionAsset = HarmonyUtil.GetFieldValue(settings, "inputActionAsset"); if ((Object)(object)inputActionAsset == (Object)null) { ArtisanMod.Logger.LogWarning((object)"Unable to install inventory slot rebinds because UISettings.inputActionAsset was not found."); return; } lastMaxSlots = GetMaxSlots(); EnsureActions(); LoadOverrides(); AddControlsUi(settings); } } public static InputAction GetSlotAction(int slotIndex) { if (!SlotActions.TryGetValue(slotIndex, out var value)) { return null; } return value; } public static void SaveOverrides() { ForEachValidSlotAction(delegate(int slotIndex, InputAction action) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) InputBinding val = action.bindings[0]; string overridePrefsKey = GetOverridePrefsKey(slotIndex); if (((InputBinding)(ref val)).hasOverrides) { PlayerPrefs.SetString(overridePrefsKey, ((InputBinding)(ref val)).overridePath ?? string.Empty); } else { PlayerPrefs.DeleteKey(overridePrefsKey); } }); PlayerPrefs.Save(); } public static void SaveGameOverridesWithoutArtisanBindings() { if (!((Object)(object)inputActionAsset == (Object)null)) { Dictionary overrides = CaptureArtisanOverrides(); ClearAllArtisanBindingOverrides(); PlayerPrefs.SetString("rebinds", InputActionRebindingExtensions.SaveBindingOverridesAsJson((IInputActionCollection2)(object)inputActionAsset)); RestoreArtisanOverrides(overrides); PlayerPrefs.Save(); } } public static void RefreshLabel(UISettingRebind rebind) { if (TryGetSlotNumber(rebind, out var slotNumber)) { SetRebindLabel(rebind, GetSlotLabel(slotNumber)); } } public static bool TryUpdateDisplay(UISettingRebind rebind) { if (!TryGetSlotNumber(rebind, out var slotNumber)) { return false; } InputAction slotAction = GetSlotAction(slotNumber - 1); if (!HasPrimaryBinding(slotAction)) { return true; } RefreshRebindUi(rebind, slotNumber, slotAction); return true; } public static bool TryResetToDefault(UISettingRebind rebind) { if (!TryGetSlotNumber(rebind, out var slotNumber)) { return false; } InputAction val = default(InputAction); int num = default(int); if (!rebind.ResolveActionAndBinding(ref val, ref num)) { return true; } InputActionRebindingExtensions.RemoveBindingOverride(val, num); RefreshRebindUi(rebind, slotNumber, val); SaveOverrides(); return true; } public static void RemoveLegacyArtisanOverridesFromGamePrefs() { string @string = PlayerPrefs.GetString("rebinds", string.Empty); if (!string.IsNullOrWhiteSpace(@string) && @string.Contains("Artisan Inventory")) { string text = RemoveJsonObjectByName(@string, "Artisan Inventory"); if (!(text == @string)) { PlayerPrefs.SetString("rebinds", text); PlayerPrefs.Save(); } } } private static void SubscribeToConfigChanges() { if (!isSubscribedToConfigChanges) { ArtisanMod.Settings.Inventory.MaxSlots.SettingChanged += OnMaxSlotsChanged; isSubscribedToConfigChanges = true; } } private static void OnMaxSlotsChanged(object sender, EventArgs args) { if (!ArtisanMod.Settings.Inventory.EnableExtraSlotControlBindings.Value) { return; } int maxSlots = GetMaxSlots(); if (maxSlots != lastMaxSlots) { lastMaxSlots = maxSlots; if (!((Object)(object)inputActionAsset == (Object)null)) { EnsureActions(); LoadOverrides(); RefreshInstalledControlsUi(); SaveGameOverridesWithoutArtisanBindings(); } } } private static int GetMaxSlots() { return InventorySlotCapacityPatch.GetMaxInventorySlots(); } private static void RegisterTranslations() { ArtisanLocalization.AddTranslation((SystemLanguage)10, "inventory.controls.slot", "Slot {0}"); ArtisanLocalization.AddTranslation((SystemLanguage)10, "inventory.controls.unbound", "Unbound"); ArtisanLocalization.AddTranslation((SystemLanguage)28, "inventory.controls.slot", "Slot {0}"); ArtisanLocalization.AddTranslation((SystemLanguage)28, "inventory.controls.unbound", "Não vinculado"); } private static void EnsureActions() { int maxSlots = GetMaxSlots(); bool enabled = inputActionAsset.enabled; if (enabled) { inputActionAsset.Disable(); } try { SlotActions.Clear(); actionMap = GetOrCreateActionMap(); for (int i = 3; i < maxSlots; i++) { SlotActions[i] = GetOrCreateSlotAction(i); } } finally { if (enabled) { inputActionAsset.Enable(); } EnableSlotActions(); } } private static InputActionMap GetOrCreateActionMap() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown InputActionMap val = inputActionAsset.FindActionMap("Artisan Inventory", false); if (val != null) { return val; } val = new InputActionMap("Artisan Inventory"); AddActionMapToAsset(inputActionAsset, val); return val; } private static InputAction GetOrCreateSlotAction(int slotIndex) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) string actionName = GetActionName(slotIndex); InputAction val = actionMap.FindAction(actionName, false); if (val == null) { val = InputActionSetupExtensions.AddAction(actionMap, actionName, (InputActionType)1, (string)null, (string)null, (string)null, (string)null, (string)null); } if (val.bindings.Count == 0) { AddDefaultOrEmptyBinding(val, GetDefaultBindingPath(slotIndex + 1)); } return val; } private static void EnableSlotActions() { foreach (InputAction value in SlotActions.Values) { if (value != null && !value.enabled) { value.Enable(); } } } private static void AddDefaultOrEmptyBinding(InputAction action, string defaultBindingPath) { //IL_0017: 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_0036: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrEmpty(defaultBindingPath)) { InputActionSetupExtensions.AddBinding(action, defaultBindingPath, (string)null, (string)null, (string)null); return; } InputBinding val = default(InputBinding); ((InputBinding)(ref val)).path = string.Empty; ((InputBinding)(ref val)).groups = "Keyboard&Mouse"; InputActionSetupExtensions.AddBinding(action, val); } private static string GetActionName(int slotIndex) { return $"Inventory Slot {slotIndex + 1}"; } private static string GetDefaultBindingPath(int slotNumber) { if (slotNumber < 4 || slotNumber > 9) { return string.Empty; } return string.Format("{0}{1}", "/", slotNumber); } private static void LoadOverrides() { PlayerPrefs.DeleteKey("artisan_inventory_slot_rebinds"); ForEachValidSlotAction(delegate(int slotIndex, InputAction action) { string overridePrefsKey = GetOverridePrefsKey(slotIndex); if (PlayerPrefs.HasKey(overridePrefsKey)) { string @string = PlayerPrefs.GetString(overridePrefsKey, string.Empty); InputActionRebindingExtensions.ApplyBindingOverride(action, 0, @string); } }); } private static void AddControlsUi(UISettings settings) { int instanceID = ((Object)settings).GetInstanceID(); if (!InstalledSettingsIds.Contains(instanceID) && TryGetControlsContent(settings, out var content)) { UISettingRebind val = FindBestTemplate(content); if ((Object)(object)val == (Object)null) { ArtisanMod.Logger.LogWarning((object)"Unable to find UISettingRebind template."); return; } InstalledSettingsIds.Add(instanceID); TrackInstalledSettings(settings); RebuildControlsUi(content, val); } } private static void RefreshInstalledControlsUi() { for (int num = InstalledSettings.Count - 1; num >= 0; num--) { if (!InstalledSettings[num].TryGetTarget(out var target) || (Object)(object)target == (Object)null) { InstalledSettings.RemoveAt(num); } else { RefreshControlsUi(target); } } } private static void RefreshControlsUi(UISettings settings) { if (TryGetControlsContent(settings, out var content)) { UISettingRebind val = FindBestTemplate(content); if ((Object)(object)val == (Object)null) { ArtisanMod.Logger.LogWarning((object)"Unable to refresh inventory slot rebinds because no template was found."); } else { RebuildControlsUi(content, val); } } } private static void RebuildControlsUi(Transform content, UISettingRebind template) { RemovePreviousHotkeyUi(content); foreach (KeyValuePair slotAction in SlotActions) { CreateRebindSetting(content, template, slotAction.Key, slotAction.Value); } RebuildLayout(content); } private static bool TryGetControlsContent(UISettings settings, out Transform content) { content = ((Component)settings).transform.Find("Window/Content/SettingsSection/Sec_Controls/KeyboardScrollView/Viewport/Content"); if ((Object)(object)content != (Object)null) { return true; } ArtisanMod.Logger.LogWarning((object)"Unable to find Window/Content/SettingsSection/Sec_Controls/KeyboardScrollView/Viewport/Content."); return false; } private static void TrackInstalledSettings(UISettings settings) { for (int num = InstalledSettings.Count - 1; num >= 0; num--) { if (!InstalledSettings[num].TryGetTarget(out var target) || (Object)(object)target == (Object)null) { InstalledSettings.RemoveAt(num); } else if (((Object)target).GetInstanceID() == ((Object)settings).GetInstanceID()) { return; } } InstalledSettings.Add(new WeakReference(settings)); } private static void CreateRebindSetting(Transform parent, UISettingRebind template, int slotIndex, InputAction action) { //IL_006c: 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) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) if (HasPrimaryBinding(action)) { bool activeSelf = ((Component)template).gameObject.activeSelf; ((Component)template).gameObject.SetActive(false); UISettingRebind obj = Object.Instantiate(template, parent); int num = slotIndex + 1; ((Object)((Component)obj).gameObject).name = string.Format("{0}{1}", "ArtisanInventorySlotHotkey_", num); InputActionReference val = ScriptableObject.CreateInstance(); val.Set(action); HarmonyUtil.SetFieldValue(obj, "m_Action", val); InputBinding val2 = action.bindings[0]; HarmonyUtil.SetFieldValue(obj, "m_BindingId", ((InputBinding)(ref val2)).id.ToString()); ((Component)template).gameObject.SetActive(activeSelf); ((Component)obj).gameObject.SetActive(true); RefreshRebindUi(obj, num, action); } } private static UISettingRebind FindBestTemplate(Transform content) { UISettingRebind[] componentsInChildren = ((Component)content).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { if (!IsArtisanHotkey(componentsInChildren[i]) && HasText(componentsInChildren[i], "Slot 1")) { return componentsInChildren[i]; } } for (int j = 0; j < componentsInChildren.Length; j++) { if (!IsArtisanHotkey(componentsInChildren[j])) { return componentsInChildren[j]; } } return null; } private static bool IsArtisanHotkey(UISettingRebind rebind) { if ((Object)(object)rebind != (Object)null) { return ((Object)((Component)rebind).gameObject).name.StartsWith("ArtisanInventorySlotHotkey_", StringComparison.Ordinal); } return false; } private static bool HasText(UISettingRebind rebind, string expectedText) { TMP_Text[] componentsInChildren = ((Component)rebind).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { if ((Object)(object)componentsInChildren[i] != (Object)null && componentsInChildren[i].text == expectedText) { return true; } } return false; } private static void RemovePreviousHotkeyUi(Transform content) { List list = new List(); for (int i = 0; i < content.childCount; i++) { Transform child = content.GetChild(i); if ((Object)(object)child != (Object)null && ((Object)child).name.StartsWith("ArtisanInventorySlotHotkey_", StringComparison.Ordinal)) { list.Add(((Component)child).gameObject); } } for (int j = 0; j < list.Count; j++) { Object.Destroy((Object)(object)list[j]); } } private static void RebuildLayout(Transform content) { RectTransform component = ((Component)content).GetComponent(); if ((Object)(object)component != (Object)null) { LayoutRebuilder.ForceRebuildLayoutImmediate(component); } } private static bool TryGetSlotNumber(UISettingRebind rebind, out int slotNumber) { slotNumber = -1; if ((Object)(object)rebind == (Object)null) { return false; } string name = ((Object)((Component)rebind).gameObject).name; if (!name.StartsWith("ArtisanInventorySlotHotkey_", StringComparison.Ordinal)) { return false; } return int.TryParse(name.Substring("ArtisanInventorySlotHotkey_".Length), out slotNumber); } private static string GetSlotLabel(int slotNumber) { return ArtisanLocalization.Translate("inventory.controls.slot", slotNumber); } private static string GetUnboundLabel() { return ArtisanLocalization.Translate("inventory.controls.unbound"); } private static string GetDisplayText(InputAction action) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //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) if (!HasPrimaryBinding(action)) { return GetUnboundLabel(); } InputBinding val = action.bindings[0]; string effectivePath = ((InputBinding)(ref val)).effectivePath; if (string.IsNullOrEmpty(effectivePath)) { return GetUnboundLabel(); } if (!effectivePath.StartsWith("/", StringComparison.OrdinalIgnoreCase)) { return InputActionRebindingExtensions.GetBindingDisplayString(action, 0, (DisplayStringOptions)0); } return FormatKeyboardPath(effectivePath.Substring("/".Length)); } private static string FormatKeyboardPath(string key) { if (string.IsNullOrEmpty(key)) { return GetUnboundLabel(); } if (key.Length == 1 && char.IsDigit(key[0])) { return key; } if (key.StartsWith("digit", StringComparison.OrdinalIgnoreCase)) { return key.Substring("digit".Length); } return key.ToUpperInvariant(); } private static void RefreshRebindUi(UISettingRebind rebind, int slotNumber, InputAction action) { SetRebindLabel(rebind, GetSlotLabel(slotNumber)); SetInputText(rebind, GetDisplayText(action)); SetResetButtonState(rebind, action); } private static void SetRebindLabel(UISettingRebind rebind, string text) { Transform val = ((Component)rebind).transform.Find("Title"); if (!((Object)(object)val == (Object)null)) { LocalisedTMP component = ((Component)val).GetComponent(); if ((Object)(object)component != (Object)null) { ((Behaviour)component).enabled = false; Object.Destroy((Object)(object)component); } TMP_Text component2 = ((Component)val).GetComponent(); if ((Object)(object)component2 != (Object)null) { component2.text = text; } } } private static void SetInputText(UISettingRebind rebind, string text) { object fieldValue = HarmonyUtil.GetFieldValue(rebind, "input"); if (fieldValue != null) { GetSetKeyMethod(fieldValue.GetType())?.Invoke(fieldValue, new object[1] { text }); } } private static MethodInfo GetSetKeyMethod(Type inputType) { if (inputType == null) { return null; } if (SetKeyMethods.TryGetValue(inputType, out var value)) { return value; } value = AccessTools.Method(inputType, "SetKey", new Type[1] { typeof(string) }, (Type[])null); SetKeyMethods[inputType] = value; return value; } private static void SetResetButtonState(UISettingRebind rebind, InputAction action) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) Button fieldValue = HarmonyUtil.GetFieldValue