using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("Digger.Core")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ForgeStack")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Send resources to the Forge with G: tap for 1, hold for the whole stack, keep holding and scroll the hotbar to dump every stack. Hosting, the whole stack is credited at once. Anywhere or near-Forge mode. Only you need it.")]
[assembly: AssemblyFileVersion("1.1.1.0")]
[assembly: AssemblyInformationalVersion("1.1.1+fb776bf142bca17ae66fbd035a8d0f6d6af8b232")]
[assembly: AssemblyProduct("ForgeStack")]
[assembly: AssemblyTitle("ForgeStack")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace ForgeStack
{
internal sealed class ConfigHotReload : IDisposable
{
private const float DebounceSeconds = 0.5f;
private const float RetrySeconds = 0.5f;
private const int MaxRetries = 5;
private readonly ConfigFile _config;
private readonly ManualLogSource _log;
private readonly string _path;
private FileSystemWatcher _watcher;
private int _eventFlag;
private float _lastEventTime = -1f;
private float _retryAt = -1f;
private int _retries;
private long _appliedStamp;
private bool _pollFailedLogged;
public ConfigHotReload(ConfigFile config, ManualLogSource log)
{
_config = config;
_log = log;
_path = ((config != null) ? config.ConfigFilePath : null);
try
{
string directoryName = Path.GetDirectoryName(_path);
string fileName = Path.GetFileName(_path);
if (string.IsNullOrEmpty(directoryName) || string.IsNullOrEmpty(fileName) || !Directory.Exists(directoryName))
{
_log.LogWarning((object)"ForgeStack: pasta da config não encontrada, recarga automática desligada.");
return;
}
_appliedStamp = ReadStamp();
_watcher = new FileSystemWatcher(directoryName, fileName)
{
NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime),
IncludeSubdirectories = false
};
_watcher.Changed += OnFileEvent;
_watcher.Created += OnFileEvent;
_watcher.Renamed += OnFileEvent;
_watcher.EnableRaisingEvents = true;
}
catch (Exception ex)
{
_log.LogWarning((object)("ForgeStack: não foi possível observar o arquivo de config (edições só valem ao reiniciar o jogo): " + ex.Message));
DisposeWatcher();
}
}
private void OnFileEvent(object sender, FileSystemEventArgs e)
{
Interlocked.Exchange(ref _eventFlag, 1);
}
public void Poll(float now)
{
if (_config == null)
{
return;
}
try
{
if (Interlocked.Exchange(ref _eventFlag, 0) == 1)
{
_lastEventTime = now;
}
bool num = _lastEventTime >= 0f && now - _lastEventTime >= 0.5f;
bool flag = _retryAt >= 0f && now >= _retryAt;
if (num || flag)
{
_lastEventTime = -1f;
_retryAt = -1f;
TryReload(now);
}
}
catch (Exception ex)
{
if (!_pollFailedLogged)
{
_pollFailedLogged = true;
_log.LogWarning((object)("ForgeStack: erro ao verificar a config: " + ex.Message));
}
}
}
private void TryReload(float now)
{
long num;
try
{
num = ReadStamp();
}
catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException)
{
ScheduleRetry(now);
return;
}
if (num == _appliedStamp)
{
_retries = 0;
return;
}
bool saveOnConfigSet = _config.SaveOnConfigSet;
_config.SaveOnConfigSet = false;
try
{
_config.Reload();
_appliedStamp = num;
_retries = 0;
_pollFailedLogged = false;
_log.LogInfo((object)"ForgeStack: config recarregada do arquivo.");
}
catch (Exception ex2) when (ex2 is IOException || ex2 is UnauthorizedAccessException)
{
ScheduleRetry(now);
}
finally
{
_config.SaveOnConfigSet = saveOnConfigSet;
}
}
private void ScheduleRetry(float now)
{
if (_retries >= 5)
{
_retries = 0;
_log.LogWarning((object)"ForgeStack: não foi possível ler a config agora (arquivo em uso).");
}
else
{
_retries++;
_retryAt = now + 0.5f;
}
}
private long ReadStamp()
{
FileInfo fileInfo = new FileInfo(_path);
fileInfo.Refresh();
if (!fileInfo.Exists)
{
return 0L;
}
return fileInfo.LastWriteTimeUtc.Ticks * 31 + fileInfo.Length;
}
public void Dispose()
{
DisposeWatcher();
}
private void DisposeWatcher()
{
if (_watcher != null)
{
try
{
_watcher.EnableRaisingEvents = false;
_watcher.Changed -= OnFileEvent;
_watcher.Created -= OnFileEvent;
_watcher.Renamed -= OnFileEvent;
_watcher.Dispose();
}
catch
{
}
_watcher = null;
}
}
}
internal sealed class FeedbackHud
{
private struct TallyItem
{
public string ItemId;
public int Units;
}
private const float TallySeconds = 2.5f;
private const float FadeSeconds = 0.5f;
private readonly List<TallyItem> _tally = new List<TallyItem>();
private float _tallyUpdatedAt = -100f;
private string _hint;
private float _hintUntil;
private string _notice;
private Color _noticeColor = Color.white;
private float _noticeUntil;
public float HoldProgress = -1f;
public bool Sweeping;
public int QueuedUnits;
private GUIStyle _textStyle;
private GUIStyle _noticeStyle;
private float _styleScale;
private readonly StringBuilder _sb = new StringBuilder();
public void AddSent(string itemId, int units, float now)
{
if (now - _tallyUpdatedAt > 2.5f)
{
_tally.Clear();
}
for (int i = 0; i < _tally.Count; i++)
{
if (!(_tally[i].ItemId != itemId))
{
TallyItem value = _tally[i];
value.Units += units;
_tally[i] = value;
_tallyUpdatedAt = now;
return;
}
}
_tally.Add(new TallyItem
{
ItemId = itemId,
Units = units
});
_tallyUpdatedAt = now;
}
public void ShowHint(string text, float now, float seconds = 1.6f)
{
_hint = text;
_hintUntil = now + seconds;
}
public void ShowNotice(string text, Color color, float now, float seconds)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
_notice = text;
_noticeColor = color;
_noticeUntil = now + seconds;
}
public void Draw(float now, bool showFeedback)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Invalid comparison between Unknown and I4
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_0108: Unknown result type (might be due to invalid IL or missing references)
//IL_0146: 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)
//IL_0171: Unknown result type (might be due to invalid IL or missing references)
//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
//IL_0223: Unknown result type (might be due to invalid IL or missing references)
//IL_0243: Unknown result type (might be due to invalid IL or missing references)
//IL_01be: Unknown result type (might be due to invalid IL or missing references)
//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
//IL_028e: Unknown result type (might be due to invalid IL or missing references)
//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
if (Event.current == null || (int)Event.current.type != 7)
{
return;
}
float num = Mathf.Clamp((float)Screen.height / 1080f, 0.75f, 2.5f);
EnsureStyles(num);
float num2 = (float)Screen.width / 2f;
float num3 = (float)Screen.height / 2f;
if (now < _noticeUntil && !string.IsNullOrEmpty(_notice))
{
float alpha = Fade(now, _noticeUntil);
DrawShadowed(new Rect(0f, (float)Screen.height * 0.12f, (float)Screen.width, 40f * num), _notice, _noticeStyle, _noticeColor, alpha);
}
if (showFeedback)
{
if (HoldProgress >= 0f)
{
float num4 = 150f * num;
float num5 = 8f * num;
Rect val = default(Rect);
((Rect)(ref val))..ctor(num2 - num4 / 2f, num3 + 38f * num, num4, num5);
GUI.color = new Color(0f, 0f, 0f, 0.6f);
GUI.DrawTexture(new Rect(((Rect)(ref val)).x - 2f, ((Rect)(ref val)).y - 2f, ((Rect)(ref val)).width + 4f, ((Rect)(ref val)).height + 4f), (Texture)(object)Texture2D.whiteTexture);
GUI.color = (Sweeping ? new Color(0.45f, 1f, 0.45f, 0.95f) : new Color(1f, 0.62f, 0.2f, 0.95f));
GUI.DrawTexture(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y, ((Rect)(ref val)).width * Mathf.Clamp01(HoldProgress), ((Rect)(ref val)).height), (Texture)(object)Texture2D.whiteTexture);
GUI.color = Color.white;
}
if (_tally.Count > 0 && now - _tallyUpdatedAt <= 2.5f)
{
float alpha2 = Fade(now, _tallyUpdatedAt + 2.5f);
DrawShadowed(new Rect(0f, num3 + 70f * num, (float)Screen.width, 32f * num), BuildTallyText(), _textStyle, new Color(1f, 0.85f, 0.45f), alpha2);
}
if (now < _hintUntil && !string.IsNullOrEmpty(_hint))
{
float alpha3 = Fade(now, _hintUntil);
DrawShadowed(new Rect(0f, num3 + 104f * num, (float)Screen.width, 30f * num), _hint, _textStyle, new Color(1f, 0.55f, 0.35f), alpha3);
}
GUI.color = Color.white;
}
}
private string BuildTallyText()
{
_sb.Clear();
foreach (TallyItem item in _tally)
{
if (_sb.Length > 0)
{
_sb.Append(" ");
}
_sb.Append('+').Append(item.Units).Append(' ')
.Append(ItemNames.Get(item.ItemId));
}
_sb.Append(" → Forja");
if (QueuedUnits > 0)
{
_sb.Append(" …");
}
return _sb.ToString();
}
private static float Fade(float now, float until)
{
return Mathf.Clamp01((until - now) / 0.5f);
}
private static void DrawShadowed(Rect rect, string text, GUIStyle style, Color color, float alpha)
{
//IL_0017: 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)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: 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_007b: Unknown result type (might be due to invalid IL or missing references)
GUI.color = new Color(0f, 0f, 0f, 0.85f * alpha);
GUI.Label(new Rect(((Rect)(ref rect)).x + 2f, ((Rect)(ref rect)).y + 2f, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height), text, style);
GUI.color = new Color(color.r, color.g, color.b, alpha);
GUI.Label(rect, text, style);
GUI.color = Color.white;
}
private void EnsureStyles(float scale)
{
//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_0035: 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_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Expected O, but got Unknown
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: 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_0092: Expected O, but got Unknown
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
if (_textStyle == null || !Mathf.Approximately(scale, _styleScale))
{
_styleScale = scale;
_textStyle = new GUIStyle(GUI.skin.label)
{
alignment = (TextAnchor)4,
fontStyle = (FontStyle)1,
fontSize = Mathf.RoundToInt(20f * scale),
wordWrap = false
};
_textStyle.normal.textColor = Color.white;
_noticeStyle = new GUIStyle(_textStyle)
{
fontSize = Mathf.RoundToInt(22f * scale)
};
_noticeStyle.normal.textColor = Color.white;
}
}
}
internal enum Block
{
None,
NotInRun,
PlayerState,
Menu,
Paused
}
internal static class ForgeGame
{
private const float FarOriginDistance = 10f;
private static Forge _forge;
private static float _nextForgeSearch;
private static bool _loggedFallback;
public static bool TryGetRun(out FirstPersonController player, out Forge forge)
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Invalid comparison between Unknown and I4
player = null;
forge = null;
GameManager instance = GameManager.Instance;
if ((Object)(object)instance == (Object)null || !instance.IsInitialized || (Object)(object)instance.sceneManager == (Object)null || (int)instance.SceneType != 1)
{
return false;
}
Forge val = FindForge();
if ((Object)(object)val == (Object)null)
{
return false;
}
player = instance.LocalPlayer;
if ((Object)(object)player == (Object)null || !player.IsAvailable || (Object)(object)player.PlayerStats == (Object)null || (Object)(object)player.PlayerEquipment == (Object)null || (Object)(object)player.InventorySystem == (Object)null || (Object)(object)player.PlayerInteraction == (Object)null)
{
player = null;
return false;
}
forge = val;
return true;
}
private static Forge FindForge()
{
LevelManager instance = LevelManager.Instance;
if ((Object)(object)instance != (Object)null && (Object)(object)instance.Forge != (Object)null)
{
_forge = instance.Forge;
return _forge;
}
if ((Object)(object)_forge != (Object)null)
{
return _forge;
}
if (Time.unscaledTime < _nextForgeSearch)
{
return null;
}
_nextForgeSearch = Time.unscaledTime + 3f;
try
{
_forge = Object.FindAnyObjectByType<Forge>();
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("ForgeStack: erro procurando a Forja na cena: " + ex.Message));
return null;
}
if ((Object)(object)_forge != (Object)null && !_loggedFallback)
{
_loggedFallback = true;
Plugin.Log.LogInfo((object)"ForgeStack: a Forja não estava ligada no LevelManager desta partida; usando a que está na cena.");
}
return _forge;
}
public static void ForgetForge()
{
_forge = null;
_nextForgeSearch = 0f;
_loggedFallback = false;
}
public static Block CheckPlayer(FirstPersonController player)
{
//IL_003e: 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_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Invalid comparison between Unknown and I4
//IL_0048: 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_004d: Invalid comparison between Unknown and I4
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Invalid comparison between Unknown and I4
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Invalid comparison between Unknown and I4
if (player.PlayerStats.isDead)
{
return Block.PlayerState;
}
if (player.PlayerEquipment.HasCarriable() || (Object)(object)player.CurrentSiegeWeapon != (Object)null)
{
return Block.PlayerState;
}
InputManager instance = InputManager.Instance;
if ((Object)(object)instance == (Object)null)
{
return Block.Menu;
}
InputState currentInputState = instance.CurrentInputState;
if ((int)currentInputState != 2)
{
if (currentInputState - 9 <= 1 || (int)currentInputState == 19)
{
return Block.Paused;
}
return Block.Menu;
}
if (!Application.isFocused || (int)Cursor.lockState != 1)
{
return Block.Menu;
}
return Block.None;
}
public static bool IsTemporarilyBusy()
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
if (!NetworkClient.active || !NetworkClient.ready)
{
return true;
}
NetworkHelper instance = NetworkHelper.Instance;
if ((Object)(object)instance != (Object)null && (int)instance.NetworkblockingState != 0)
{
return true;
}
return false;
}
public static bool IsVanillaSlotActionPressed(FirstPersonController player)
{
//IL_0022: 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)
PlayerInteraction playerInteraction = player.PlayerInteraction;
PlayerInputActions playerInputActions = InputManager.PlayerInputActions;
if (playerInputActions == null)
{
if (!playerInteraction.isPrimaryHeld)
{
return playerInteraction.isHolding;
}
return true;
}
PlayerActions player2 = playerInputActions.Player;
bool num = playerInteraction.isPrimaryHeld && (((PlayerActions)(ref player2)).PrimaryAction.IsPressed() || playerInteraction.currentTarget is IItemInteractable);
bool flag = playerInteraction.isHolding || ((PlayerActions)(ref player2)).Interact.IsPressed() || ((PlayerActions)(ref player2)).HoldInteract.IsPressed();
if (!(num || flag) && !((PlayerActions)(ref player2)).Release.IsPressed())
{
return ((PlayerActions)(ref player2)).HoldRelease.IsPressed();
}
return true;
}
public static int SelectedSlot(FirstPersonController player)
{
return player.InventorySystem.slotSelected;
}
public static bool IsLookingAtForge(FirstPersonController player, Forge forge)
{
ICrosshairTarget currentTarget = player.PlayerInteraction.currentTarget;
Forge val = (Forge)(object)((currentTarget is Forge) ? currentTarget : null);
if (val != null)
{
return (Object)(object)val == (Object)(object)forge;
}
return false;
}
public static float DistanceToForge(FirstPersonController player, Forge forge)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
return Vector3.Distance(((Component)player).transform.position, ((Component)forge).transform.position);
}
public static bool IsForgeMaxLevel(Forge forge)
{
RogueLikeDatabaseSO rogueLikeDatabase = forge.rogueLikeDatabase;
int networkdisplayedLevel = forge.NetworkdisplayedLevel;
if ((Object)(object)rogueLikeDatabase != (Object)null && networkdisplayedLevel > 0)
{
return rogueLikeDatabase.IsMaxLevel(networkdisplayedLevel - 1);
}
return false;
}
public static bool IsForgeNetworkReachable(Forge forge)
{
NetworkIdentity netIdentity = ((NetworkBehaviour)forge).netIdentity;
if ((Object)(object)netIdentity == (Object)null || netIdentity.netId == 0 || !((Component)forge).gameObject.activeInHierarchy)
{
return false;
}
if (NetworkServer.active && !ForgeServer.CanDeliver(forge))
{
LocalConnectionToClient localConnection = NetworkServer.localConnection;
Dictionary<int, NetworkConnectionToClient> observers = netIdentity.observers;
if (localConnection != null && observers != null && !observers.ContainsKey(((NetworkConnectionToClient)localConnection).connectionId))
{
return false;
}
}
return true;
}
public static bool IsPlaceable(Forge forge, string itemId)
{
if (!string.IsNullOrEmpty(itemId) && forge.IsPlaceable(itemId))
{
return ResourceValue(forge, itemId) > 0;
}
return false;
}
public static int ResourceValue(Forge forge, string itemId)
{
RogueLikeDatabaseSO rogueLikeDatabase = forge.rogueLikeDatabase;
if (!((Object)(object)rogueLikeDatabase != (Object)null))
{
return 0;
}
return rogueLikeDatabase.GetResourceValueByID(itemId);
}
public static int FreePoolObjects(Forge forge, string itemId)
{
if (forge.itemPools == null || !forge.itemPools.TryGetValue(itemId, out var value) || value == null)
{
return -1;
}
int num = 0;
foreach (GameObject item in value)
{
if ((Object)(object)item != (Object)null && !item.activeSelf)
{
num++;
}
}
return num;
}
public static void GetAnimationOrigin(FirstPersonController player, Forge forge, out Vector3 position, out Quaternion rotation)
{
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: 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_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: 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_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: 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_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
//IL_0101: Unknown result type (might be due to invalid IL or missing references)
//IL_0106: 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_010e: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Unknown result type (might be due to invalid IL or missing references)
//IL_0118: Unknown result type (might be due to invalid IL or missing references)
PlayerEquipment playerEquipment = player.PlayerEquipment;
Transform val = null;
EquippedItem currentEquippedItem = playerEquipment.CurrentEquippedItem;
if ((Object)(object)currentEquippedItem != (Object)null && (Object)(object)currentEquippedItem.ItemAnimator != (Object)null)
{
val = ((Component)currentEquippedItem.ItemAnimator).transform;
}
if ((Object)(object)val == (Object)null)
{
val = (((Object)(object)playerEquipment.equipmentClientParent != (Object)null) ? playerEquipment.equipmentClientParent : ((Component)player).transform);
}
position = val.position;
rotation = val.rotation;
Vector3 val2 = (((Object)(object)forge.Target != (Object)null) ? forge.Target.position : ((Component)forge).transform.position);
Vector3 val3 = position - val2;
if (!(((Vector3)(ref val3)).sqrMagnitude <= 100f))
{
val3.y = 0f;
val3 = ((((Vector3)(ref val3)).sqrMagnitude > 0.001f) ? ((Vector3)(ref val3)).normalized : Vector3.forward);
position = val2 + val3 * 1.5f + Vector3.up * 2.5f;
rotation = Quaternion.LookRotation(-val3);
}
}
public static float RoundTripTime()
{
try
{
return (float)NetworkTime.rtt;
}
catch
{
return 0f;
}
}
}
internal enum DeliveryStop
{
Done,
LevelUp,
Blocked,
SlotChanged,
MaxLevel,
NoValue,
Unavailable,
Error
}
internal static class ForgeServer
{
private const int PoolReserveForOthers = 6;
private const int MaxVisualsPerDelivery = 6;
private static bool? _visualSafe;
private static float _nextErrorLog;
private static bool VisualSafe
{
get
{
if (!_visualSafe.HasValue)
{
bool flag = false;
try
{
MethodInfo methodInfo = AccessTools.Method(typeof(RogueLikeUpgradeManager), "AddResources", (Type[])null, (Type[])null);
Patches val = ((methodInfo != null) ? Harmony.GetPatchInfo((MethodBase)methodInfo) : null);
if (val != null)
{
foreach (Patch prefix in val.Prefixes)
{
if (prefix.owner == "catedralemchamas.stonewards.forgestack")
{
flag = true;
}
}
}
}
catch
{
flag = false;
}
_visualSafe = flag;
if (!flag)
{
Plugin.Log.LogWarning((object)"ForgeStack: patch de AddResources não encontrado; a entrega direta vai creditar sem animação.");
}
}
return _visualSafe.Value;
}
}
public static bool CanDeliver(Forge forge)
{
if (!Plugin.InstantWhenHost.Value || (Object)(object)forge == (Object)null || !NetworkServer.active || !((NetworkBehaviour)forge).isServer)
{
return false;
}
RogueLikeUpgradeManager instance = RogueLikeUpgradeManager.Instance;
if ((Object)(object)instance != (Object)null && (Object)(object)instance.rogueLikeDatabase != (Object)null)
{
return (Object)(object)NetworkHelper.Instance != (Object)null;
}
return false;
}
public static bool PhaseBlocked()
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
NetworkHelper instance = NetworkHelper.Instance;
if ((Object)(object)instance == (Object)null)
{
return true;
}
if ((int)instance.NetworkblockingState == 0)
{
return instance.isRogueUpgradePhaseActive;
}
return true;
}
public static DeliveryStop Deliver(FirstPersonController player, Forge forge, int slot, string itemId, int maxUnits, out int credited)
{
//IL_00a3: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
credited = 0;
if (maxUnits <= 0 || (Object)(object)player == (Object)null || string.IsNullOrEmpty(itemId) || !CanDeliver(forge))
{
return DeliveryStop.Unavailable;
}
InventorySystem inventorySystem = player.InventorySystem;
RogueLikeUpgradeManager instance = RogueLikeUpgradeManager.Instance;
if ((Object)(object)inventorySystem == (Object)null || (Object)(object)instance == (Object)null)
{
return DeliveryStop.Unavailable;
}
if (SafeIsMaxLevel(instance))
{
return DeliveryStop.MaxLevel;
}
if (ResourceValue(instance, itemId) <= 0)
{
return DeliveryStop.NoValue;
}
if (PhaseBlocked())
{
return DeliveryStop.Blocked;
}
if (!AnyPlayerAvailable())
{
return DeliveryStop.Blocked;
}
int num = VisualBudget(forge, itemId);
DeliveryStop result = DeliveryStop.Done;
for (int i = 0; i < maxUnits; i++)
{
SyncList<InventoryEntry> inventoryEntries = inventorySystem.InventoryEntries;
if (inventoryEntries == null || slot < 0 || slot >= inventoryEntries.Count)
{
result = DeliveryStop.SlotChanged;
break;
}
InventoryEntry val = inventoryEntries[slot];
if (((InventoryEntry)(ref val)).IsEmpty || val.itemID != itemId || val.count <= 0)
{
result = DeliveryStop.SlotChanged;
break;
}
if (SafeIsMaxLevel(instance))
{
result = DeliveryStop.MaxLevel;
break;
}
int count = val.count;
bool flag;
try
{
flag = inventorySystem.ServerRemoveItemFromSlot(slot, 1);
}
catch (Exception ex)
{
LogError($"ForgeStack: erro tirando {itemId} do espaço {slot} do inventário: {ex.Message}");
int num2 = SlotCount(inventorySystem, slot, itemId);
if (num2 >= 0 && count - num2 > 0)
{
credited += CreditUnits(instance, itemId, 1);
}
result = DeliveryStop.Error;
break;
}
int num3 = (flag ? MeasureRemoved(inventorySystem, slot, itemId, count) : 0);
if (num3 <= 0)
{
result = DeliveryStop.SlotChanged;
break;
}
int num4 = CreditUnits(instance, itemId, num3);
credited += num4;
if (num4 < num3)
{
Refund(player, instance, itemId, num3 - num4);
result = DeliveryStop.Error;
break;
}
if (num > 0 && PlayVisual(player, forge, itemId))
{
num--;
}
if (PhaseBlocked())
{
result = DeliveryStop.LevelUp;
break;
}
}
if (credited > 0)
{
AnnounceToGame(player, itemId, credited);
}
return result;
}
private static int CreditUnits(RogueLikeUpgradeManager manager, string itemId, int units)
{
int num = 0;
for (int i = 0; i < units; i++)
{
int num2 = 0;
int num3 = 0;
bool flag = false;
try
{
num2 = manager.GetCurrentCharge();
num3 = manager.GetCurrentLevel();
flag = true;
}
catch
{
}
try
{
manager.AddResources(itemId, 1);
num++;
}
catch (Exception ex)
{
bool flag2 = false;
if (flag)
{
try
{
flag2 = manager.GetCurrentCharge() != num2 || manager.GetCurrentLevel() != num3;
}
catch
{
}
}
if (flag2)
{
num++;
}
LogError($"ForgeStack: erro creditando {itemId} na Forja (creditado: {flag2}): {ex.Message}");
break;
}
}
return num;
}
private static void Refund(FirstPersonController player, RogueLikeUpgradeManager manager, string itemId, int units)
{
if (units <= 0)
{
return;
}
ItemDataSO val = ResourceItem(manager, itemId);
int num = units;
if ((Object)(object)val != (Object)null)
{
try
{
num = player.InventorySystem.ServerAddItem(val, units);
}
catch (Exception ex)
{
LogError($"ForgeStack: erro devolvendo {units}x {itemId} ao inventário: {ex.Message}");
num = units;
}
}
if (num > 0)
{
Plugin.Log.LogError((object)$"ForgeStack: {num}x {itemId} saiu do inventário sem ser creditado e não coube de volta (inventário cheio?).");
}
else
{
Plugin.Log.LogWarning((object)$"ForgeStack: {units}x {itemId} não foi creditado na Forja e voltou para o inventário.");
}
}
private static void AnnounceToGame(FirstPersonController player, string itemId, int units)
{
try
{
player.TargetRPCOnResourcesToForge(itemId, units);
}
catch (Exception ex)
{
LogError($"ForgeStack: erro avisando o jogo do depósito de {units}x {itemId}: {ex.Message}");
}
try
{
if ((Object)(object)player.FPSAudioPlayer != (Object)null)
{
((NetworkedAudioPlayer)player.FPSAudioPlayer).PlaySound("DROP_ITEM");
}
}
catch
{
}
}
private static int VisualBudget(Forge forge, string itemId)
{
if (!VisualSafe)
{
return 0;
}
int num = ForgeGame.FreePoolObjects(forge, itemId);
if (num < 0)
{
return 0;
}
return Mathf.Clamp(num - 6, 0, 6);
}
private static bool PlayVisual(FirstPersonController player, Forge forge, string itemId)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
try
{
ForgeGame.GetAnimationOrigin(player, forge, out var position, out var rotation);
forge.RpcPlayPlaceAnimation(position, rotation, itemId, 0);
return true;
}
catch (Exception ex)
{
LogError("ForgeStack: erro na animação da Forja: " + ex.Message);
_visualSafe = false;
return false;
}
}
private static int SlotCount(InventorySystem inventory, int slot, string itemId)
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: 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)
try
{
SyncList<InventoryEntry> inventoryEntries = inventory.InventoryEntries;
if (inventoryEntries == null || slot < 0 || slot >= inventoryEntries.Count)
{
return 0;
}
InventoryEntry val = inventoryEntries[slot];
return (val.itemID == itemId) ? Math.Max(0, val.count) : 0;
}
catch (Exception ex)
{
LogError($"ForgeStack: erro relendo o espaço {slot} do inventário: {ex.Message}");
return -1;
}
}
private static int MeasureRemoved(InventorySystem inventory, int slot, string itemId, int before)
{
int num = SlotCount(inventory, slot, itemId);
if (num < 0)
{
return 1;
}
int num2 = before - num;
if (num2 > 1)
{
LogError($"ForgeStack: o espaço {slot} perdeu {num2}x {itemId} numa remoção de 1; creditando 1 (algo mais mexeu no inventário).");
num2 = 1;
}
if (num2 >= 0)
{
return num2;
}
return 0;
}
private static int ResourceValue(RogueLikeUpgradeManager manager, string itemId)
{
try
{
return manager.rogueLikeDatabase.GetResourceValueByID(itemId);
}
catch (Exception ex)
{
LogError("ForgeStack: erro lendo o valor de " + itemId + " no gerenciador da Forja: " + ex.Message);
return 0;
}
}
private static ItemDataSO ResourceItem(RogueLikeUpgradeManager manager, string itemId)
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
try
{
SResourcesValue[] resourcesValues = manager.rogueLikeDatabase.ResourcesValues;
if (resourcesValues != null)
{
SResourcesValue[] array = resourcesValues;
foreach (SResourcesValue val in array)
{
if ((Object)(object)val.item != (Object)null && val.item.itemID == itemId)
{
return val.item;
}
}
}
}
catch (Exception ex)
{
LogError("ForgeStack: erro procurando o item " + itemId + " no banco da Forja: " + ex.Message);
}
return null;
}
private static bool SafeIsMaxLevel(RogueLikeUpgradeManager manager)
{
try
{
return manager.IsMaxLevel();
}
catch
{
return true;
}
}
private static bool AnyPlayerAvailable()
{
try
{
foreach (FirstPersonController localPlayer in FirstPersonController.LocalPlayers)
{
if ((Object)(object)localPlayer != (Object)null && localPlayer.IsAvailable)
{
return true;
}
}
}
catch
{
return false;
}
return false;
}
private static void LogError(string message)
{
if (!(Time.unscaledTime < _nextErrorLog))
{
_nextErrorLog = Time.unscaledTime + 10f;
Plugin.Log.LogError((object)message);
}
}
public static void Reset()
{
_visualSafe = null;
}
}
[HarmonyPatch(typeof(RogueLikeUpgradeManager), "AddResources")]
internal static class ForgeZeroCountAnimationPatch
{
private static bool Prefix(int _Count)
{
return _Count > 0;
}
}
internal class ForgeStackController : MonoBehaviour
{
private enum KeyPhase
{
Idle,
Holding,
Suppressed
}
private static readonly string[] ConflictingGuids = new string[2] { "catedralemchamas.stonewards.remoteforge", "br.begamerxd.stonewards.remoteforge" };
private const float BarDelaySeconds = 0.08f;
private const float TargetGraceSeconds = 1f;
private readonly SlotLedger _ledger = new SlotLedger();
private readonly SendQueue _queue = new SendQueue();
private readonly FeedbackHud _hud = new FeedbackHud();
private KeyPhase _phase;
private bool _keyWasDown;
private float _pressStart;
private bool _holdFired;
private int _sweepLastSlot = -1;
private FirstPersonController _lastPlayer;
private InventorySystem _subscribedInventory;
private readonly List<int> _slotEvents = new List<int>();
private float _quietUntil;
private float _targetFailSince = -1f;
private readonly HashSet<int> _timedOutSlots = new HashSet<int>();
private bool _modeKnown;
private SendMode _lastMode;
private bool _conflictChecked;
private string _conflictName;
private bool _conflictShown;
private readonly HashSet<string> _loggedErrors = new HashSet<string>();
private void Awake()
{
_queue.Sent = delegate(string itemId, int units)
{
_hud.AddSent(itemId, units, Time.unscaledTime);
};
_queue.NotCreditable = delegate(string itemId)
{
_hud.ShowHint("A Forja não aceita " + ItemNames.Get(itemId) + " agora", Time.unscaledTime);
};
_queue.Refused = delegate(string message)
{
_hud.ShowHint(message, Time.unscaledTime, 3f);
};
_ledger.TimedOut = delegate(int slot)
{
_queue.CancelSlot(slot);
_timedOutSlots.Add(slot);
Plugin.Log.LogWarning((object)$"ForgeStack: o servidor não confirmou o envio do espaço {slot}; envio cancelado (aperte de novo).");
};
}
private void Update()
{
float unscaledTime = Time.unscaledTime;
try
{
CheckConflicts();
CheckModeChanged(unscaledTime);
Tick(unscaledTime);
}
catch (Exception ex)
{
LogOnce(ex);
_queue.CancelAll();
_phase = KeyPhase.Suppressed;
_hud.HoldProgress = -1f;
}
}
private void OnGUI()
{
try
{
_hud.Draw(Time.unscaledTime, Plugin.ShowFeedback.Value);
}
catch (Exception ex)
{
LogOnce(ex);
}
}
private void Tick(float now)
{
bool keyDown = ReadKey();
if (!ForgeGame.TryGetRun(out var player, out var forge))
{
if ((Object)(object)_lastPlayer != (Object)null)
{
ResetRunState();
}
_lastPlayer = null;
HandleKey(keyDown, Block.NotInRun, null, null, now);
_hud.HoldProgress = -1f;
_hud.QueuedUnits = 0;
return;
}
if ((Object)(object)player != (Object)(object)_lastPlayer)
{
ResetRunState();
_lastPlayer = player;
SubscribeSlotEvents(player.InventorySystem);
ItemNames.Clear();
}
ShowConflictOnce(now);
_ledger.Refresh(player.InventorySystem.InventoryEntries, now);
Block block = ForgeGame.CheckPlayer(player);
switch (block)
{
case Block.Paused:
_quietUntil = Mathf.Max(_quietUntil, now + QuietSeconds());
break;
default:
_queue.CancelAll();
_quietUntil = Mathf.Max(_quietUntil, now + QuietSeconds());
break;
case Block.None:
if (ForgeGame.IsVanillaSlotActionPressed(player))
{
_quietUntil = Mathf.Max(_quietUntil, now + QuietSeconds());
}
break;
}
HandleKey(keyDown, block, player, forge, now);
PumpQueue(player, forge, block, now);
UpdateHud(block == Block.None, now);
}
private static string BlockHint(Block block)
{
return block switch
{
Block.NotInRun => "Forja só dentro da partida",
Block.PlayerState => "Não dá carregando algo, na arma de cerco ou caído",
Block.Menu => "Feche o menu primeiro",
Block.Paused => "Espere a tela fechar",
_ => "Não dá agora",
};
}
private static bool ReadKey()
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: 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)
KeyCode value = Plugin.Key.Value;
if ((int)value != 0)
{
return UnityInput.Current.GetKey(value);
}
return false;
}
private void HandleKey(bool keyDown, Block block, FirstPersonController player, Forge forge, float now)
{
bool flag = keyDown && !_keyWasDown;
_keyWasDown = keyDown;
switch (_phase)
{
case KeyPhase.Idle:
if (flag)
{
if (block == Block.None)
{
_phase = KeyPhase.Holding;
_pressStart = now;
_holdFired = false;
_sweepLastSlot = -1;
_timedOutSlots.Clear();
}
else
{
_hud.ShowHint(BlockHint(block), now, 2.5f);
_phase = KeyPhase.Suppressed;
}
}
break;
case KeyPhase.Holding:
switch (block)
{
case Block.Paused:
if (!keyDown)
{
_phase = KeyPhase.Idle;
}
else if (!_holdFired)
{
_phase = KeyPhase.Suppressed;
}
break;
default:
_phase = (keyDown ? KeyPhase.Suppressed : KeyPhase.Idle);
break;
case Block.None:
if (!_holdFired && now - _pressStart >= Plugin.HoldSeconds.Value)
{
_holdFired = true;
_slotEvents.Clear();
_sweepLastSlot = ForgeGame.SelectedSlot(player);
DoHold(player, forge, now);
}
else if (_holdFired && keyDown && Plugin.SweepWhileHolding.Value)
{
Sweep(player, forge, now);
}
if (!keyDown)
{
if (!_holdFired && Plugin.TapSendsOne.Value)
{
DoTap(player, forge, now);
}
_phase = KeyPhase.Idle;
}
break;
}
break;
case KeyPhase.Suppressed:
if (!keyDown)
{
_phase = KeyPhase.Idle;
}
break;
}
}
private void DoTap(FirstPersonController player, Forge forge, float now)
{
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
if (CanTarget(player, forge, now))
{
if (!TryGetSelectedResource(player, forge, out var slot, out var entry))
{
_hud.ShowHint("Selecione um recurso da Forja", now);
}
else if (!_timedOutSlots.Contains(slot))
{
_queue.Enqueue(slot, entry.itemID, 1, additive: true);
}
}
}
private void DoHold(FirstPersonController player, Forge forge, float now)
{
if (!CanTarget(player, forge, now))
{
return;
}
int slot;
InventoryEntry entry;
if (Plugin.HoldActionSetting.Value == HoldAction.AllResources)
{
SyncList<InventoryEntry> inventoryEntries = player.InventorySystem.InventoryEntries;
int num = ForgeGame.SelectedSlot(player);
int num2 = 0;
if (num >= 0 && num < inventoryEntries.Count && EnqueueWholeSlot(player, forge, num))
{
num2++;
}
for (int i = 0; i < inventoryEntries.Count; i++)
{
if (i != num && EnqueueWholeSlot(player, forge, i))
{
num2++;
}
}
if (num2 == 0 && !_queue.HasJobs)
{
_hud.ShowHint("Nenhum recurso da Forja no inventário", now);
}
}
else if (!TryGetSelectedResource(player, forge, out slot, out entry))
{
if (!Plugin.SweepWhileHolding.Value)
{
_hud.ShowHint("Selecione um recurso da Forja", now);
}
}
else
{
EnqueueWholeSlot(player, forge, slot);
}
}
private void Sweep(FirstPersonController player, Forge forge, float now)
{
foreach (int slotEvent in _slotEvents)
{
SweepSlot(player, forge, slotEvent, now);
}
_slotEvents.Clear();
SweepSlot(player, forge, ForgeGame.SelectedSlot(player), now);
}
private void SweepSlot(FirstPersonController player, Forge forge, int slot, float now)
{
//IL_002d: 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_004b: Unknown result type (might be due to invalid IL or missing references)
if (slot == _sweepLastSlot)
{
return;
}
_sweepLastSlot = slot;
SyncList<InventoryEntry> inventoryEntries = player.InventorySystem.InventoryEntries;
if (slot >= 0 && slot < inventoryEntries.Count)
{
InventoryEntry val = inventoryEntries[slot];
if (!((InventoryEntry)(ref val)).IsEmpty && ForgeGame.IsPlaceable(forge, val.itemID) && val.count - _ledger.Unconfirmed(slot) > 0 && !_timedOutSlots.Contains(slot) && CanTarget(player, forge, now))
{
EnqueueWholeSlot(player, forge, slot);
}
}
}
private bool EnqueueWholeSlot(FirstPersonController player, Forge forge, int slot)
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: 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_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
SyncList<InventoryEntry> inventoryEntries = player.InventorySystem.InventoryEntries;
if (slot < 0 || slot >= inventoryEntries.Count)
{
return false;
}
InventoryEntry val = inventoryEntries[slot];
if (((InventoryEntry)(ref val)).IsEmpty || !ForgeGame.IsPlaceable(forge, val.itemID) || _timedOutSlots.Contains(slot))
{
return false;
}
int num = val.count - _ledger.Unconfirmed(slot);
if (num <= 0)
{
return false;
}
_queue.Enqueue(slot, val.itemID, num, additive: false);
return true;
}
private static bool TryGetSelectedResource(FirstPersonController player, Forge forge, out int slot, out InventoryEntry entry)
{
//IL_0001: 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_0035: Unknown result type (might be due to invalid IL or missing references)
entry = default(InventoryEntry);
slot = ForgeGame.SelectedSlot(player);
SyncList<InventoryEntry> inventoryEntries = player.InventorySystem.InventoryEntries;
if (slot < 0 || slot >= inventoryEntries.Count)
{
return false;
}
entry = inventoryEntries[slot];
if (!((InventoryEntry)(ref entry)).IsEmpty)
{
return ForgeGame.IsPlaceable(forge, entry.itemID);
}
return false;
}
private bool CanTarget(FirstPersonController player, Forge forge, float now)
{
if (Plugin.Mode.Value == SendMode.NearForge)
{
if (!ForgeGame.IsLookingAtForge(player, forge))
{
_hud.ShowHint("Olhe para a Forja", now);
return false;
}
}
else
{
float value = Plugin.MaxDistance.Value;
if (value > 0f)
{
float num = ForgeGame.DistanceToForge(player, forge);
if (num > value)
{
_hud.ShowHint($"Forja longe demais ({num:0} m, máx. {value:0} m)", now);
return false;
}
}
}
if (ForgeGame.IsForgeMaxLevel(forge))
{
_hud.ShowHint("Forja no nível máximo", now);
return false;
}
if (!ForgeGame.IsForgeNetworkReachable(forge))
{
_hud.ShowHint("Forja fora do alcance: chegue mais perto", now);
return false;
}
return true;
}
private void PumpQueue(FirstPersonController player, Forge forge, Block block, float now)
{
if (!_queue.HasJobs)
{
_targetFailSince = -1f;
}
else
{
if (block != Block.None)
{
return;
}
if (!CanTarget(player, forge, now))
{
if (_targetFailSince < 0f)
{
_targetFailSince = now;
}
else if (now - _targetFailSince > 1f)
{
_queue.CancelAll();
_targetFailSince = -1f;
}
}
else
{
_targetFailSince = -1f;
if (!(now < _quietUntil) && !ForgeGame.IsTemporarilyBusy())
{
_queue.Tick(player, forge, _ledger, now);
}
}
}
}
private void UpdateHud(bool gatesOk, float now)
{
_hud.QueuedUnits = _queue.RemainingUnits;
if (_phase != KeyPhase.Holding || !gatesOk)
{
_hud.HoldProgress = -1f;
_hud.Sweeping = false;
return;
}
float num = now - _pressStart;
if (!_holdFired && num < 0.08f)
{
_hud.HoldProgress = -1f;
return;
}
float num2 = Mathf.Max(0.01f, Plugin.HoldSeconds.Value);
_hud.HoldProgress = (_holdFired ? 1f : Mathf.Clamp01(num / num2));
_hud.Sweeping = _holdFired;
}
private void SubscribeSlotEvents(InventorySystem inventory)
{
UnsubscribeSlotEvents();
if (!((Object)(object)inventory == (Object)null))
{
inventory.OnSlotSelectedUpdated += OnSlotSelected;
_subscribedInventory = inventory;
}
}
private void UnsubscribeSlotEvents()
{
if ((Object)(object)_subscribedInventory != (Object)null)
{
_subscribedInventory.OnSlotSelectedUpdated -= OnSlotSelected;
}
_subscribedInventory = null;
_slotEvents.Clear();
}
private void OnSlotSelected(int slot)
{
if (_phase == KeyPhase.Holding && _holdFired && _slotEvents.Count < 32)
{
_slotEvents.Add(slot);
}
}
private void OnDestroy()
{
try
{
UnsubscribeSlotEvents();
}
catch
{
}
}
private void ResetRunState()
{
ForgeGame.ForgetForge();
UnsubscribeSlotEvents();
_queue.ResetAll();
_ledger.Clear();
_holdFired = false;
_sweepLastSlot = -1;
_quietUntil = 0f;
_targetFailSince = -1f;
_timedOutSlots.Clear();
if (_phase == KeyPhase.Holding)
{
_phase = KeyPhase.Suppressed;
}
}
private static float QuietSeconds()
{
return Mathf.Max(0.5f, 0.3f + ForgeGame.RoundTripTime() * 3f);
}
private void CheckModeChanged(float now)
{
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
SendMode value = Plugin.Mode.Value;
if (!_modeKnown)
{
_modeKnown = true;
_lastMode = value;
}
else if (value != _lastMode)
{
_lastMode = value;
string text = ((value == SendMode.NearForge) ? "De perto" : "De longe");
_hud.ShowNotice("ForgeStack: modo " + text, new Color(0.55f, 1f, 0.55f), now, 3f);
Plugin.Log.LogInfo((object)$"ForgeStack: modo alterado para {value} ({text}).");
}
}
private void CheckConflicts()
{
if (_conflictChecked)
{
return;
}
_conflictChecked = true;
string[] conflictingGuids = ConflictingGuids;
foreach (string text in conflictingGuids)
{
if (Chainloader.PluginInfos != null && Chainloader.PluginInfos.TryGetValue(text, out var value))
{
object obj;
if (value == null)
{
obj = null;
}
else
{
BepInPlugin metadata = value.Metadata;
obj = ((metadata != null) ? metadata.Name : null);
}
if (obj == null)
{
obj = text;
}
_conflictName = (string)obj;
Plugin.Log.LogWarning((object)("ForgeStack: o mod '" + _conflictName + "' (" + text + ") também envia recursos para a Forja. Se os dois usarem a mesma tecla, cada aperto envia em dobro. Desative um deles ou troque a tecla."));
break;
}
}
}
private void ShowConflictOnce(float now)
{
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
if (!_conflictShown && _conflictName != null)
{
_conflictShown = true;
_hud.ShowNotice("ForgeStack: '" + _conflictName + "' na mesma tecla envia em dobro", new Color(1f, 0.5f, 0.35f), now, 8f);
}
}
private void LogOnce(Exception ex)
{
string item = ex.GetType().FullName + ":" + ex.Message;
if (_loggedErrors.Count < 20 && _loggedErrors.Add(item))
{
Plugin.Log.LogError((object)("ForgeStack: erro (mostrado uma vez): " + ex));
}
}
}
internal static class ItemNames
{
private static readonly Dictionary<string, string> Cache = new Dictionary<string, string>();
public static string Get(string itemId)
{
if (string.IsNullOrEmpty(itemId))
{
return "?";
}
if (Cache.TryGetValue(itemId, out var value))
{
return value;
}
string text = null;
try
{
ItemDataSO val = (((Object)(object)ItemManager.Instance != (Object)null) ? ItemManager.Instance.GetItemDataSoByID(itemId) : null);
if ((Object)(object)val != (Object)null)
{
text = val.GetLocalizedName();
}
}
catch (Exception)
{
}
if (string.IsNullOrEmpty(text) || text.IndexOf("No translation found", StringComparison.OrdinalIgnoreCase) >= 0)
{
return Prettify(itemId);
}
Cache[itemId] = text;
return text;
}
public static void Clear()
{
Cache.Clear();
}
private static string Prettify(string itemId)
{
string text = itemId.Replace('_', ' ').ToLowerInvariant();
if (text.Length <= 0)
{
return itemId;
}
return char.ToUpperInvariant(text[0]) + text.Substring(1);
}
}
public enum SendMode
{
Anywhere,
NearForge
}
public enum HoldAction
{
WholeStack,
AllResources
}
[BepInPlugin("catedralemchamas.stonewards.forgestack", "ForgeStack", "1.1.1")]
public class Plugin : BaseUnityPlugin
{
internal static ManualLogSource Log;
internal static ConfigEntry<SendMode> Mode;
internal static ConfigEntry<bool> InstantWhenHost;
internal static ConfigEntry<KeyCode> Key;
internal static ConfigEntry<float> HoldSeconds;
internal static ConfigEntry<HoldAction> HoldActionSetting;
internal static ConfigEntry<bool> TapSendsOne;
internal static ConfigEntry<bool> SweepWhileHolding;
internal static ConfigEntry<bool> ShowFeedback;
internal static ConfigEntry<float> MaxDistance;
internal static ConfigEntry<int> UnitsPerSend;
internal static ConfigEntry<float> SendInterval;
private ConfigHotReload _hotReload;
private Harmony _harmony;
private void Awake()
{
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Expected O, but got Unknown
//IL_0157: Unknown result type (might be due to invalid IL or missing references)
//IL_0161: Expected O, but got Unknown
//IL_0189: Unknown result type (might be due to invalid IL or missing references)
//IL_0193: Expected O, but got Unknown
//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
//IL_01d0: Expected O, but got Unknown
//IL_01db: Unknown result type (might be due to invalid IL or missing references)
//IL_01e5: Expected O, but got Unknown
//IL_0271: Unknown result type (might be due to invalid IL or missing references)
Log = ((BaseUnityPlugin)this).Logger;
Mode = ((BaseUnityPlugin)this).Config.Bind<SendMode>("General", "Mode", SendMode.Anywhere, "Anywhere = from anywhere in the run / NearForge = only looking at the Forge. PT: Anywhere = de qualquer lugar da partida / NearForge = só olhando para a Forja.");
InstantWhenHost = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "InstantWhenHost", true, "Hosting: the whole stack is credited at once, stopping at each Forge level-up. / PT: Sendo host: a pilha inteira é creditada de uma vez, parando a cada nível da Forja.");
Key = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "Key", (KeyCode)103, "Key: tap = 1 unit, hold = whole stack. / PT: Tecla: toque = 1 unidade, segurar = pilha inteira.");
HoldSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "HoldSeconds", 0.4f, new ConfigDescription("Seconds to hold the key for the hold action. / PT: Segundos segurando a tecla para enviar tudo.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 3f), Array.Empty<object>()));
HoldActionSetting = ((BaseUnityPlugin)this).Config.Bind<HoldAction>("General", "HoldAction", HoldAction.WholeStack, "WholeStack = selected stack / AllResources = every stack the Forge accepts. PT: WholeStack = pilha selecionada / AllResources = todas as pilhas aceitas pela Forja.");
TapSendsOne = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "TapSendsOne", true, "Tapping the key sends 1 unit. / PT: Um toque rápido envia 1 unidade.");
SweepWhileHolding = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SweepWhileHolding", true, "While holding, every slot you select is sent whole. / PT: Segurando a tecla, cada espaço selecionado vai inteiro.");
ShowFeedback = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "ShowFeedback", true, "On-screen text and hold progress bar. / PT: Texto na tela e barra de progresso ao segurar.");
MaxDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Anywhere", "MaxDistance", 0f, new ConfigDescription("Anywhere mode only: max distance to the Forge in meters (0 = unlimited). / PT: Só no modo Anywhere: distância máxima até a Forja em metros (0 = sem limite).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1000f), Array.Empty<object>()));
UnitsPerSend = ((BaseUnityPlugin)this).Config.Bind<int>("Advanced", "UnitsPerSend", 8, new ConfigDescription("As a client only: target units per send (the real batch follows the free space in the Forge animation). / PT: Só como cliente: alvo de unidades por envio (o lote real acompanha a folga da animação da Forja).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>()));
SendInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Advanced", "SendInterval", 0.1f, new ConfigDescription("As a client only: seconds between sends. / PT: Só como cliente: segundos entre envios.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1f), Array.Empty<object>()));
try
{
_harmony = new Harmony("catedralemchamas.stonewards.forgestack");
_harmony.PatchAll();
}
catch (Exception ex)
{
_harmony = null;
Log.LogWarning((object)("ForgeStack: não foi possível aplicar o patch da animação da Forja; a entrega direta vai creditar sem animação. " + ex.Message));
}
((Component)this).gameObject.AddComponent<ForgeStackController>();
_hotReload = new ConfigHotReload(((BaseUnityPlugin)this).Config, Log);
Log.LogInfo((object)(string.Format("{0} v{1} carregado. Modo {2}, tecla {3}, ", "ForgeStack", "1.1.1", Mode.Value, Key.Value) + "entrega direta como host " + (InstantWhenHost.Value ? "ligada" : "desligada") + "."));
}
private void Update()
{
_hotReload?.Poll(Time.unscaledTime);
}
private void OnDestroy()
{
_hotReload?.Dispose();
_hotReload = null;
try
{
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
catch
{
}
_harmony = null;
}
}
internal sealed class SendQueue
{
private sealed class Job
{
public int Slot;
public string ItemId;
public int Remaining;
}
private struct RecentSend
{
public float Time;
public string ItemId;
public int Units;
public int Heat;
}
private const int PoolMargin = 4;
private const float ForgeTweenSeconds = 0.4f;
private const int InstantUnitsPerFrame = 128;
private const float InstantRetrySeconds = 0.25f;
private readonly List<Job> _jobs = new List<Job>();
private readonly List<RecentSend> _recent = new List<RecentSend>();
private float _nextSendAt;
private float _levelUpWaitUntil;
public Action<string, int> Sent;
public Action<string> NotCreditable;
public Action<string> Refused;
public bool HasJobs => _jobs.Count > 0;
public int RemainingUnits
{
get
{
int num = 0;
foreach (Job job in _jobs)
{
num += job.Remaining;
}
return num;
}
}
public bool HasJob(int slot)
{
foreach (Job job in _jobs)
{
if (job.Slot == slot)
{
return true;
}
}
return false;
}
public void Enqueue(int slot, string itemId, int units, bool additive)
{
if (slot < 0 || units <= 0 || string.IsNullOrEmpty(itemId))
{
return;
}
foreach (Job job in _jobs)
{
if (job.Slot == slot)
{
if (job.ItemId == itemId)
{
job.Remaining = (additive ? (job.Remaining + units) : Math.Max(job.Remaining, units));
return;
}
job.Remaining = 0;
}
}
_jobs.RemoveAll((Job j) => j.Remaining <= 0);
_jobs.Add(new Job
{
Slot = slot,
ItemId = itemId,
Remaining = units
});
}
public void CancelAll()
{
_jobs.Clear();
}
public void CancelSlot(int slot)
{
_jobs.RemoveAll((Job j) => j.Slot == slot);
}
public void ResetAll()
{
_jobs.Clear();
_recent.Clear();
_nextSendAt = 0f;
_levelUpWaitUntil = 0f;
ForgeServer.Reset();
}
public void Tick(FirstPersonController player, Forge forge, SlotLedger ledger, float now)
{
float num = ForgeGame.RoundTripTime();
float num2 = 0.9f + num * 1.5f;
PruneRecent(now, num2);
if (_jobs.Count != 0 && !(now < _nextSendAt) && !(now < _levelUpWaitUntil))
{
if (ForgeServer.CanDeliver(forge))
{
TickInstant(player, forge, now);
}
else
{
TickNetwork(player, forge, ledger, now, num, num2);
}
}
}
private void TickInstant(FirstPersonController player, Forge forge, float now)
{
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
int num = 128;
int num2 = 0;
while (num2 < _jobs.Count && num > 0)
{
Job job = _jobs[num2];
if (!IsJobStillValid(player, forge, job, out var entry))
{
_jobs.RemoveAt(num2);
continue;
}
int num3 = Math.Min(job.Remaining, Math.Min(entry.count, num));
if (num3 <= 0)
{
_jobs.RemoveAt(num2);
continue;
}
int credited;
DeliveryStop deliveryStop = ForgeServer.Deliver(player, forge, job.Slot, job.ItemId, num3, out credited);
if (credited > 0)
{
job.Remaining -= credited;
num -= credited;
Sent?.Invoke(job.ItemId, credited);
}
bool flag = job.Remaining <= 0;
bool flag2 = false;
switch (deliveryStop)
{
case DeliveryStop.SlotChanged:
flag = true;
break;
case DeliveryStop.LevelUp:
flag2 = true;
break;
case DeliveryStop.Blocked:
_nextSendAt = now + 0.25f;
flag2 = true;
break;
case DeliveryStop.MaxLevel:
_jobs.Clear();
Refused?.Invoke("Forja no nível máximo");
Plugin.Log.LogWarning((object)"ForgeStack: Forja no nível máximo; entrega cancelada (o jogo descartaria os recursos).");
return;
case DeliveryStop.NoValue:
flag = true;
NotCreditable?.Invoke(job.ItemId);
Plugin.Log.LogWarning((object)("ForgeStack: a Forja aceita " + job.ItemId + ", mas ele vale 0 no gerenciador da Forja; nada enviado."));
break;
case DeliveryStop.Unavailable:
flag2 = true;
break;
default:
_jobs.Clear();
_nextSendAt = now + 0.25f;
Refused?.Invoke("Erro ao entregar na Forja: envio cancelado");
return;
case DeliveryStop.Done:
break;
}
if (flag)
{
_jobs.RemoveAt(num2);
}
else
{
num2++;
}
if (!flag2)
{
continue;
}
break;
}
}
private void TickNetwork(FirstPersonController player, Forge forge, SlotLedger ledger, float now, float rtt, float creditWindow)
{
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: 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)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_010f: Unknown result type (might be due to invalid IL or missing references)
//IL_016f: Unknown result type (might be due to invalid IL or missing references)
//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
//IL_01da: Unknown result type (might be due to invalid IL or missing references)
//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
//IL_0204: Unknown result type (might be due to invalid IL or missing references)
//IL_022c: Unknown result type (might be due to invalid IL or missing references)
//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
SyncList<InventoryEntry> inventoryEntries = player.InventorySystem.InventoryEntries;
for (int i = 0; i < _jobs.Count; i++)
{
Job job = _jobs[i];
if (job.Slot >= inventoryEntries.Count)
{
_jobs.RemoveAt(i--);
continue;
}
InventoryEntry val = inventoryEntries[job.Slot];
if (((InventoryEntry)(ref val)).IsEmpty || val.itemID != job.ItemId || !ForgeGame.IsPlaceable(forge, val.itemID))
{
_jobs.RemoveAt(i--);
continue;
}
int num = ledger.Unconfirmed(job.Slot);
int num2 = val.count - num;
if (num2 <= 0)
{
if (num <= 0)
{
_jobs.RemoveAt(i--);
}
continue;
}
int num3 = ForgeGame.FreePoolObjects(forge, val.itemID);
if (num3 < 0)
{
_jobs.RemoveAt(i--);
NotCreditable?.Invoke(val.itemID);
continue;
}
int num4 = num3 - RecentUnits(val.itemID, now, rtt + 0.15f) - 4;
if (num4 <= 0)
{
continue;
}
int val2 = Math.Max(1, Plugin.UnitsPerSend.Value);
int val3 = Math.Min(job.Remaining, Math.Min(num2, Math.Max(val2, num4)));
val3 = Math.Min(val3, num4);
bool flag = false;
int num5 = ForgeGame.ResourceValue(forge, val.itemID);
int networkcurrentMaxCharge = forge.NetworkcurrentMaxCharge;
if (num5 > 0 && networkcurrentMaxCharge > 0)
{
int num6 = forge.NetworkcurrentCharge + RecentHeat();
int num7 = networkcurrentMaxCharge - num6;
int num8 = ((num7 <= 0) ? 1 : ((num7 + num5 - 1) / num5));
if (val3 >= num8)
{
val3 = num8;
flag = true;
}
}
if (val3 > 0)
{
ForgeGame.GetAnimationOrigin(player, forge, out var position, out var rotation);
player.CmdTryPlaceItemInItemInteractable(player, val.itemID, job.Slot, val3, forge.NetworkIdentity, position, rotation);
ledger.RecordSend(job.Slot, val.itemID, val.count, val3, now);
_recent.Add(new RecentSend
{
Time = now,
ItemId = val.itemID,
Units = val3,
Heat = val3 * num5
});
job.Remaining -= val3;
if (job.Remaining <= 0)
{
_jobs.RemoveAt(i);
}
_nextSendAt = now + Plugin.SendInterval.Value;
if (flag)
{
_levelUpWaitUntil = now + creditWindow + 0.3f;
}
Sent?.Invoke(val.itemID, val3);
break;
}
}
}
private static bool IsJobStillValid(FirstPersonController player, Forge forge, Job job, out InventoryEntry entry)
{
//IL_0001: 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_003c: Unknown result type (might be due to invalid IL or missing references)
entry = default(InventoryEntry);
SyncList<InventoryEntry> inventoryEntries = player.InventorySystem.InventoryEntries;
if (inventoryEntries == null || job.Slot < 0 || job.Slot >= inventoryEntries.Count)
{
return false;
}
entry = inventoryEntries[job.Slot];
if (!((InventoryEntry)(ref entry)).IsEmpty && entry.itemID == job.ItemId)
{
return ForgeGame.IsPlaceable(forge, entry.itemID);
}
return false;
}
private void PruneRecent(float now, float window)
{
_recent.RemoveAll((RecentSend r) => now - r.Time > window);
}
private int RecentUnits(string itemId, float now, float window)
{
int num = 0;
foreach (RecentSend item in _recent)
{
if (item.ItemId == itemId && now - item.Time <= window)
{
num += item.Units;
}
}
return num;
}
private int RecentHeat()
{
int num = 0;
foreach (RecentSend item in _recent)
{
num += item.Heat;
}
return num;
}
}
internal sealed class SlotLedger
{
private sealed class Pending
{
public string ItemId;
public int BaseCount;
public int Unconfirmed;
public float LastSendTime;
}
private readonly Dictionary<int, Pending> _pending = new Dictionary<int, Pending>();
private readonly List<int> _toRemove = new List<int>();
public Action<int> TimedOut;
public bool IsEmpty => _pending.Count == 0;
public int Unconfirmed(int slot)
{
if (!_pending.TryGetValue(slot, out var value))
{
return 0;
}
return value.Unconfirmed;
}
public void RecordSend(int slot, string itemId, int countBeforeSend, int units, float now)
{
if (_pending.TryGetValue(slot, out var value) && value.ItemId == itemId)
{
value.Unconfirmed += units;
value.LastSendTime = now;
return;
}
_pending[slot] = new Pending
{
ItemId = itemId,
BaseCount = countBeforeSend,
Unconfirmed = units,
LastSendTime = now
};
}
public void Refresh(SyncList<InventoryEntry> entries, float now)
{
//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_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
if (_pending.Count == 0)
{
return;
}
float num = ConfirmTimeout();
_toRemove.Clear();
foreach (KeyValuePair<int, Pending> item in _pending)
{
int key = item.Key;
Pending value = item.Value;
if (entries == null || key < 0 || key >= entries.Count)
{
_toRemove.Add(key);
continue;
}
InventoryEntry val = entries[key];
if (((InventoryEntry)(ref val)).IsEmpty || val.itemID != value.ItemId)
{
_toRemove.Add(key);
continue;
}
if (val.count <= value.BaseCount - value.Unconfirmed)
{
_toRemove.Add(key);
continue;
}
if (val.count > value.BaseCount)
{
value.BaseCount = val.count;
}
if (now - value.LastSendTime > num)
{
_toRemove.Add(key);
TimedOut?.Invoke(key);
}
}
foreach (int item2 in _toRemove)
{
_pending.Remove(item2);
}
}
public void Clear()
{
_pending.Clear();
}
private static float ConfirmTimeout()
{
float num = 0f;
try
{
num = (float)NetworkTime.rtt;
}
catch
{
}
return Math.Max(5f, num * 10f + 2f);
}
}
internal static class MyPluginInfo
{
public const string PLUGIN_GUID = "catedralemchamas.stonewards.forgestack";
public const string PLUGIN_NAME = "ForgeStack";
public const string PLUGIN_VERSION = "1.1.1";
public const string PLUGIN_AUTHOR = "CatedralEmChamas";
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}