Decompiled source of Artisan v1.1.0
Artisan.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
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<T>(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<T>(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<SystemLanguage, Dictionary<string, string>> Translations = new Dictionary<SystemLanguage, Dictionary<string, string>>(); 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<string, string>(); 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<LocalisationManager>(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<Spell>(projectile, "OwnerSpell"); NetworkIdentity fieldValue2 = HarmonyUtil.GetFieldValue<NetworkIdentity>(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<int, HashSet<uint>> DamagedTargetsByProjectile = new Dictionary<int, HashSet<uint>>(); 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<LayerMask>(projectile, "pushableLayer"); return ((1 << ((Component)target).gameObject.layer) & ((LayerMask)(ref fieldValue)).value) != 0; } private static bool WasRigidbodyAlreadyAffected(ProjectilePush projectile, Rigidbody targetRigidbody) { return HarmonyUtil.GetFieldValue<HashSet<Rigidbody>>(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<NpcBehaviour>(ref val)) { val.OnHit(context.DamageAmount, context.ForceDirection, false, context.Caster); } Pawn val2 = default(Pawn); if (context.AffectPlayers && ((Component)targetIdentity).TryGetComponent<Pawn>(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<uint>(); 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<EnemyHealthBar>(); if ((Object)(object)enemyHealthBar == (Object)null) { enemyHealthBar = ((Component)hurtbox).gameObject.AddComponent<EnemyHealthBar>(); } 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<NpcBehaviour>(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<TextMeshPro>(); } 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<TextMeshPro>(); DamageText3D component2 = val.GetComponent<DamageText3D>(); 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<NpcHurtbox>(); if (!((Object)(object)_npcHurtbox == (Object)null)) { _npcBehaviour = ((Component)this).GetComponent<NpcBehaviour>(); _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>(); _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<RectTransform>(); 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<Billboard>(); 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<Collider>(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<Renderer>(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<TextMeshProUGUI>(); ((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<RectTransform>(); 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<Image>(); val2.sprite = GetSharedWhiteSprite(); ((Graphic)val2).color = color; RectTransform component = val.GetComponent<RectTransform>(); 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<UIInventorySlot[]>(__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<RectTransform>(); 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<LayoutGroup>(); 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<ContentSizeFitter>(); 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<RectTransform>(); 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<UIInventorySlot>(inventory, "leftHandSlot"); if ((Object)(object)fieldValue == (Object)null) { return; } RectTransform component = ((Component)fieldValue).GetComponent<RectTransform>(); 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<RectTransform> list = new List<RectTransform>(); 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<RectTransform>(); 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<RectTransform>(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<TextMeshProUGUI>(inventory, "currentSelectedItemNameText"); if (!((Object)(object)fieldValue == (Object)null)) { RectTransform component = ((Component)fieldValue).GetComponent<RectTransform>(); 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<CanvasGroup>(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<Image>(); ((Graphic)component).color = OverlayColor; ((Graphic)component).raycastTarget = false; CanvasGroup component2 = overlayObject.GetComponent<CanvasGroup>(); 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<RectTransform>(); 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<Image>(); 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<RectTransform>(); 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<PawnInventory>(inventoryUi, "_playerInventory"); if ((Object)(object)fieldValue == (Object)null) { return; } UIInventorySlot[] fieldValue2 = HarmonyUtil.GetFieldValue<UIInventorySlot[]>(inventoryUi, "inventorySlots"); if (fieldValue2 == null) { return; } foreach (UIInventorySlot val in fieldValue2) { if (!((Object)(object)val == (Object)null)) { InventoryLockedSlotOverlay inventoryLockedSlotOverlay = ((Component)val).GetComponent<InventoryLockedSlotOverlay>(); if ((Object)(object)inventoryLockedSlotOverlay == (Object)null) { inventoryLockedSlotOverlay = ((Component)val).gameObject.AddComponent<InventoryLockedSlotOverlay>(); } 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<UIInventorySlot[]>(__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<GameObject>(((Component)val).gameObject, parent); ((Object)val2).name = "ArtisanInventorySlot_" + j; val2.SetActive(true); UIInventorySlot component = val2.GetComponent<UIInventorySlot>(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)val2); continue; } ((TMP_Text)GetSlotKeyText(component)).text = (j + 1).ToString(); LayoutElement component2 = val2.GetComponent<LayoutElement>(); 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<TextMeshProUGUI>(); } } 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<Mesh>(); 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<Camera>(); 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<MeshFilter>(); MeshRenderer val5 = val3.AddComponent<MeshRenderer>(); 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<SaveManager>(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<SaveManager>(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<Pawn>(); } 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<PawnInventory> RestoringInventories = new HashSet<PawnInventory>(); [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<PawnInventory>(__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<UIInventory>(__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<PawnInventory>(); } return null; } private static PawnInventory GetPlayerInventory(UIInventory inventoryUi) { if (!((Object)(object)inventoryUi == (Object)null)) { return HarmonyUtil.GetFieldValue<PawnInventory>(inventoryUi, "_playerInventory"); } return null; } private static UIInventorySlot GetDraggedSlot(UIInventory inventoryUi) { if (!((Object)(object)inventoryUi == (Object)null)) { return HarmonyUtil.GetFieldValue<UIInventorySlot>(inventoryUi, "_draggedSlot"); } return null; } private static PawnPropInteractions GetPropInteractions(PawnInventory inventory) { if ((Object)(object)inventory == (Object)null) { return null; } PawnPropInteractions fieldValue = HarmonyUtil.GetFieldValue<PawnPropInteractions>(inventory, "propInteractions"); if (!((Object)(object)fieldValue != (Object)null)) { return ((Component)inventory).GetComponent<PawnPropInteractions>(); } 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<NetworkPuppetProp>(); } 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 ShowIngredientInve