using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using HowToFish.ItemRetriever.Config;
using HowToFish.ItemRetriever.Models;
using HowToFish.ItemRetriever.Systems;
using HowToFish.ItemRetriever.Utils;
using UnityEngine;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("ItemRetriever")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ItemRetriever")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("D181CDA7-EF07-4BBC-B975-2B80FC6BBFAE")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace HowToFish.ItemRetriever
{
[BepInPlugin("odinplus.itemretriever", "Item Retriever", "1.0.1")]
public sealed class Plugin : BaseUnityPlugin
{
public const string PluginGuid = "odinplus.itemretriever";
public const string PluginName = "Item Retriever";
public const string PluginVersion = "1.0.1";
private Harmony _harmony;
private GameBridge _bridge;
private ItemFinder _finder;
private RetrieverLogic _logic;
private NetworkSync _network;
private IDisposable _consoleRegistration;
private float _nextConsoleAttempt;
private float _cooldownUntil;
private bool _loggedReady;
internal static Plugin Instance { get; private set; }
internal static ManualLogSource Log { get; private set; }
private void Awake()
{
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Expected O, but got Unknown
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
Instance = this;
Log = ((BaseUnityPlugin)this).Logger;
RetrieverConfig.Bind(((BaseUnityPlugin)this).Config);
((BaseUnityPlugin)this).Config.Save();
_bridge = new GameBridge(((BaseUnityPlugin)this).Logger);
_network = new NetworkSync(((BaseUnityPlugin)this).Logger, _bridge);
_finder = new ItemFinder(((BaseUnityPlugin)this).Logger, _bridge);
_logic = new RetrieverLogic(((BaseUnityPlugin)this).Logger, _bridge, _finder, _network);
_harmony = new Harmony("odinplus.itemretriever");
_harmony.PatchAll(Assembly.GetExecutingAssembly());
TryRegisterConsoleCommand();
((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} {1} loaded. Hotkey: {2}.", "Item Retriever", "1.0.1", RetrieverConfig.RetrieveKey.Value));
}
private void Update()
{
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
if (_consoleRegistration == null && Time.unscaledTime >= _nextConsoleAttempt)
{
_nextConsoleAttempt = Time.unscaledTime + 2f;
TryRegisterConsoleCommand();
}
if (RetrieverConfig.Enabled.Value)
{
if (!_loggedReady && _bridge.GetLocalPlayer() != null)
{
_loggedReady = true;
((BaseUnityPlugin)this).Logger.LogInfo((object)"Local player found. Item Retriever is ready.");
}
if (!ShouldIgnoreHotkey() && Input.GetKeyDown(RetrieverConfig.RetrieveKey.Value))
{
RunRetrieve("hotkey");
}
}
}
private void OnDestroy()
{
_consoleRegistration?.Dispose();
_consoleRegistration = null;
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
_harmony = null;
if (Instance == this)
{
Instance = null;
}
}
internal RetrieveResult RunRetrieve(string source)
{
if (!RetrieverConfig.Enabled.Value)
{
return Fail("Item Retriever is disabled in config.");
}
if (Time.unscaledTime < _cooldownUntil)
{
float num = _cooldownUntil - Time.unscaledTime;
return Fail($"On cooldown ({num:0.0}s left).");
}
object localPlayer = _bridge.GetLocalPlayer();
if (localPlayer == null)
{
return Fail("No local player yet. Load into an island first.");
}
if (RetrieverConfig.HostOnly.Value && !_network.IsServer)
{
return Fail("Only the lobby host can retrieve items.");
}
if (!_network.CanRetrieve)
{
return Fail("This client does not have authority to move world items. Ask the host, or disable HostOnly if you own the items.");
}
RetrieveResult retrieveResult = _logic.TryRetrieve(localPlayer, source);
if (retrieveResult.Success)
{
float num2 = Mathf.Max(0f, RetrieverConfig.CooldownSeconds.Value);
if (num2 > 0f)
{
_cooldownUntil = Time.unscaledTime + num2;
}
}
Feedback(retrieveResult);
return retrieveResult;
}
private bool ShouldIgnoreHotkey()
{
if (RetrieverConfig.IgnoreWhenChatOpen.Value && _bridge.IsChatOrConsoleBlocking())
{
return true;
}
try
{
object localPlayer = _bridge.GetLocalPlayer();
if (localPlayer != null && _bridge.IsPlayerBlockingInputs(localPlayer))
{
return true;
}
}
catch
{
}
return false;
}
private void Feedback(RetrieveResult result)
{
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
string text = result.Message ?? (result.Success ? "Items retrieved." : "Nothing to retrieve.");
if (RetrieverConfig.LogToConsole.Value)
{
if (result.Success)
{
((BaseUnityPlugin)this).Logger.LogInfo((object)text);
}
else
{
((BaseUnityPlugin)this).Logger.LogWarning((object)text);
}
}
if (RetrieverConfig.ShowChatMessage.Value)
{
_bridge.TrySendLocalChat(text);
}
if (result.Success && RetrieverConfig.ScreenShake.Value)
{
_bridge.TryShake(0.25f, 8, new Vector2(0.12f, 0.12f));
}
WriteModConsole(text, result.Success ? "info" : "warn");
}
private RetrieveResult Fail(string message)
{
RetrieveResult result = RetrieveResult.Failed(message);
Feedback(result);
return result;
}
private void TryRegisterConsoleCommand()
{
if (_consoleRegistration != null)
{
return;
}
try
{
MethodInfo methodInfo = Type.GetType("HowToFish.ModConsole.ModConsoleApi, HowToFish.ModConsole", throwOnError: false)?.GetMethod("RegisterCommand", BindingFlags.Static | BindingFlags.Public, null, new Type[6]
{
typeof(string),
typeof(string),
typeof(string),
typeof(string),
typeof(Func<string[], string>),
typeof(string[])
}, null);
if (!(methodInfo == null))
{
Func<string[], string> func = ExecuteConsoleCommand;
_consoleRegistration = methodInfo.Invoke(null, new object[6]
{
"odinplus.itemretriever",
"retrieve",
"Pull lost weapons and items back to you.",
"retrieve [status|now]",
func,
new string[3] { "retriever", "getitem", "bringitems" }
}) as IDisposable;
if (_consoleRegistration != null)
{
((BaseUnityPlugin)this).Logger.LogInfo((object)"Registered retrieve command with Mod Console.");
}
}
}
catch (Exception ex)
{
((BaseUnityPlugin)this).Logger.LogDebug((object)("Mod Console not available yet: " + ex.Message));
}
}
private string ExecuteConsoleCommand(string[] args)
{
//IL_0059: 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)
string text = ((args != null && args.Length != 0) ? args[0].Trim() : "now");
if (text.Equals("status", StringComparison.OrdinalIgnoreCase) || text.Equals("help", StringComparison.OrdinalIgnoreCase))
{
object localPlayer = _bridge.GetLocalPlayer();
int num = ((localPlayer != null) ? _finder.CountCandidates(_bridge.GetPlayerPosition(localPlayer)) : 0);
float num2 = Mathf.Max(0f, _cooldownUntil - Time.unscaledTime);
return string.Format("Item Retriever {0} | enabled={1} | ", "1.0.1", RetrieverConfig.Enabled.Value) + $"host={_network.IsServer} | canRetrieve={_network.CanRetrieve} | " + $"candidates={num} | cooldown={num2:0.0}s | key={RetrieverConfig.RetrieveKey.Value}";
}
RetrieveResult retrieveResult = RunRetrieve("console");
return retrieveResult.Message;
}
private static void WriteModConsole(string text, string level)
{
try
{
(Type.GetType("HowToFish.ModConsole.ModConsoleApi, HowToFish.ModConsole", throwOnError: false)?.GetMethod("WriteLine", BindingFlags.Static | BindingFlags.Public, null, new Type[2]
{
typeof(string),
typeof(string)
}, null))?.Invoke(null, new object[2] { text, level });
}
catch
{
}
}
}
}
namespace HowToFish.ItemRetriever.Utils
{
internal static class ReflectionUtil
{
public const BindingFlags All = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
public static Type FindType(params string[] names)
{
foreach (string typeName in names)
{
Type type = Type.GetType(typeName, throwOnError: false);
if (type != null)
{
return type;
}
}
return null;
}
public static FieldInfo FindField(Type type, params string[] names)
{
if (type == null)
{
return null;
}
foreach (string name in names)
{
FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (field != null)
{
return field;
}
}
FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
foreach (FieldInfo fieldInfo in fields)
{
foreach (string value in names)
{
if (fieldInfo.Name.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0)
{
return fieldInfo;
}
}
}
return (type.BaseType != null && type.BaseType != typeof(object)) ? FindField(type.BaseType, names) : null;
}
public static PropertyInfo FindProperty(Type type, params string[] names)
{
if (type == null)
{
return null;
}
foreach (string name in names)
{
PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (property != null)
{
return property;
}
}
PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
foreach (PropertyInfo propertyInfo in properties)
{
foreach (string value in names)
{
if (propertyInfo.Name.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0)
{
return propertyInfo;
}
}
}
return (type.BaseType != null && type.BaseType != typeof(object)) ? FindProperty(type.BaseType, names) : null;
}
public static MethodInfo FindMethod(Type type, string name, int parameterCount)
{
if (type == null)
{
return null;
}
MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
foreach (MethodInfo methodInfo in methods)
{
if (methodInfo.Name == name && methodInfo.GetParameters().Length == parameterCount)
{
return methodInfo;
}
}
return (type.BaseType != null && type.BaseType != typeof(object)) ? FindMethod(type.BaseType, name, parameterCount) : null;
}
public static object GetMember(object instance, MemberInfo member)
{
try
{
if (member is FieldInfo fieldInfo)
{
return fieldInfo.GetValue(fieldInfo.IsStatic ? null : instance);
}
if (member is PropertyInfo { CanRead: not false } propertyInfo)
{
MethodInfo getMethod = propertyInfo.GetGetMethod(nonPublic: true);
bool flag = getMethod != null && getMethod.IsStatic;
return propertyInfo.GetValue(flag ? null : instance, null);
}
}
catch
{
return null;
}
return null;
}
public static bool SetMember(object instance, MemberInfo member, object value)
{
try
{
if (member is FieldInfo fieldInfo)
{
fieldInfo.SetValue(fieldInfo.IsStatic ? null : instance, ConvertTo(value, fieldInfo.FieldType));
return true;
}
if (member is PropertyInfo { CanWrite: not false } propertyInfo)
{
MethodInfo setMethod = propertyInfo.GetSetMethod(nonPublic: true);
bool flag = setMethod != null && setMethod.IsStatic;
propertyInfo.SetValue(flag ? null : instance, ConvertTo(value, propertyInfo.PropertyType), null);
return true;
}
}
catch
{
return false;
}
return false;
}
public static bool TryReadInt(object instance, MemberInfo member, out int value)
{
value = 0;
object member2 = GetMember(instance, member);
if (member2 == null)
{
return false;
}
try
{
value = Convert.ToInt32(member2, CultureInfo.InvariantCulture);
return true;
}
catch
{
return false;
}
}
public static bool TryReadFloat(object instance, MemberInfo member, out float value)
{
value = 0f;
object member2 = GetMember(instance, member);
if (member2 == null)
{
return false;
}
try
{
value = Convert.ToSingle(member2, CultureInfo.InvariantCulture);
return true;
}
catch
{
return false;
}
}
public static bool IsAlive(object value)
{
if (value == null)
{
return false;
}
Object val = (Object)((value is Object) ? value : null);
if (val != null)
{
return Object.op_Implicit(val);
}
return true;
}
public static GameObject AsGameObject(object value)
{
GameObject val = (GameObject)((value is GameObject) ? value : null);
if (val != null)
{
return val;
}
Component val2 = (Component)((value is Component) ? value : null);
if (val2 != null)
{
return val2.gameObject;
}
return null;
}
public static IEnumerable<string> SplitList(string raw)
{
if (string.IsNullOrEmpty(raw))
{
yield break;
}
string[] parts = raw.Split(new char[3] { ',', ';', '|' }, StringSplitOptions.RemoveEmptyEntries);
string[] array = parts;
foreach (string part in array)
{
string trimmed = part.Trim();
if (trimmed.Length > 0)
{
yield return trimmed;
}
}
}
public static bool NameMatches(string haystack, IEnumerable<string> needles)
{
if (string.IsNullOrEmpty(haystack))
{
return false;
}
foreach (string needle in needles)
{
if (haystack.IndexOf(needle, StringComparison.OrdinalIgnoreCase) >= 0)
{
return true;
}
}
return false;
}
private static object ConvertTo(object value, Type target)
{
if (value == null)
{
return null;
}
if (target.IsInstanceOfType(value))
{
return value;
}
if (target.IsEnum)
{
return (value is string value2) ? Enum.Parse(target, value2, ignoreCase: true) : Enum.ToObject(target, Convert.ToInt64(value, CultureInfo.InvariantCulture));
}
if (target == typeof(int))
{
return Convert.ToInt32(value, CultureInfo.InvariantCulture);
}
if (target == typeof(float))
{
return Convert.ToSingle(value, CultureInfo.InvariantCulture);
}
if (target == typeof(double))
{
return Convert.ToDouble(value, CultureInfo.InvariantCulture);
}
return Convert.ChangeType(value, target, CultureInfo.InvariantCulture);
}
}
}
namespace HowToFish.ItemRetriever.Systems
{
public sealed class GameBridge
{
private readonly ManualLogSource _log;
private float _nextRefresh;
private bool _isCacheInitialized;
private Type _playerType;
private FieldInfo _localPlayerField;
private PropertyInfo _blockInputsProperty;
private PropertyInfo _holdingProperty;
private PropertyInfo _screenShakeProperty;
private PropertyInfo _heldItemProperty;
private MethodInfo _shakeMethod;
private Type _gameInfoType;
private Type _waterManagerType;
private MethodInfo _isUnderWaterMethod;
private Type _instanceFinderType;
private PropertyInfo _networkManagerProperty;
private PropertyInfo _isServerStartedProperty;
private PropertyInfo _isClientStartedProperty;
private Type _chatManagerType;
private MethodInfo _chatSendMethod;
private FieldInfo _chatInstanceField;
private MemberInfo _moneyMember;
private object _moneyHost;
private bool _moneyResolved;
private Type _networkObjectType;
private PropertyInfo _isOwnerProperty;
private PropertyInfo _isServerInitializedProperty;
public bool IsServer
{
get
{
EnsureCache();
object networkManager = GetNetworkManager();
if (networkManager == null)
{
return true;
}
CacheNetwork(networkManager.GetType());
return ReadBool(_isServerStartedProperty, networkManager);
}
}
public bool IsClient
{
get
{
EnsureCache();
object networkManager = GetNetworkManager();
if (networkManager == null)
{
return false;
}
CacheNetwork(networkManager.GetType());
return ReadBool(_isClientStartedProperty, networkManager);
}
}
public GameBridge(ManualLogSource log)
{
_log = log;
}
public object GetLocalPlayer()
{
EnsureCache();
try
{
object obj = _localPlayerField?.GetValue(null);
return ReflectionUtil.IsAlive(obj) ? obj : null;
}
catch
{
return null;
}
}
public Transform GetPlayerTransform(object player)
{
GameObject val = ReflectionUtil.AsGameObject(player);
return Object.op_Implicit((Object)(object)val) ? val.transform : null;
}
public Transform GetPlayerCamTransform(object player)
{
if (player == null)
{
return null;
}
try
{
PropertyInfo property = player.GetType().GetProperty("CamObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (property != null)
{
object value = property.GetValue(player, null);
Transform val = (Transform)((value is Transform) ? value : null);
if (val != null && Object.op_Implicit((Object)(object)val))
{
return val;
}
GameObject val2 = (GameObject)((value is GameObject) ? value : null);
if (val2 != null && Object.op_Implicit((Object)(object)val2))
{
return val2.transform;
}
Component val3 = (Component)((value is Component) ? value : null);
if (val3 != null && Object.op_Implicit((Object)(object)val3))
{
return val3.transform;
}
}
FieldInfo field = player.GetType().GetField("CamObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (field != null)
{
object value2 = field.GetValue(player);
Transform val4 = (Transform)((value2 is Transform) ? value2 : null);
if (val4 != null && Object.op_Implicit((Object)(object)val4))
{
return val4;
}
GameObject val5 = (GameObject)((value2 is GameObject) ? value2 : null);
if (val5 != null && Object.op_Implicit((Object)(object)val5))
{
return val5.transform;
}
Component val6 = (Component)((value2 is Component) ? value2 : null);
if (val6 != null && Object.op_Implicit((Object)(object)val6))
{
return val6.transform;
}
}
}
catch
{
}
return GetPlayerTransform(player);
}
public Vector3 GetPlayerPosition(object player)
{
//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_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: 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_0039: Unknown result type (might be due to invalid IL or missing references)
Transform playerCamTransform = GetPlayerCamTransform(player);
if (Object.op_Implicit((Object)(object)playerCamTransform))
{
return playerCamTransform.position;
}
Transform playerTransform = GetPlayerTransform(player);
return Object.op_Implicit((Object)(object)playerTransform) ? playerTransform.position : Vector3.zero;
}
public Vector3 GetPlayerForward(object player)
{
//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_0069: 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_005f: 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_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_0092: 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_009b: 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)
Transform playerCamTransform = GetPlayerCamTransform(player);
if (Object.op_Implicit((Object)(object)playerCamTransform))
{
Vector3 forward = playerCamTransform.forward;
forward.y = 0f;
if (((Vector3)(ref forward)).sqrMagnitude > 0.001f)
{
return ((Vector3)(ref forward)).normalized;
}
}
Transform playerTransform = GetPlayerTransform(player);
if (!Object.op_Implicit((Object)(object)playerTransform))
{
return Vector3.forward;
}
Vector3 forward2 = playerTransform.forward;
forward2.y = 0f;
return (((Vector3)(ref forward2)).sqrMagnitude > 0.001f) ? ((Vector3)(ref forward2)).normalized : Vector3.forward;
}
public object GetHeldItem(object player)
{
EnsureCache();
try
{
object obj = _holdingProperty?.GetValue(player, null);
return (obj == null) ? null : _heldItemProperty?.GetValue(obj, null);
}
catch
{
return null;
}
}
public bool IsPlayerBlockingInputs(object player)
{
EnsureCache();
try
{
bool flag = default(bool);
int num;
if (_blockInputsProperty != null)
{
object value = _blockInputsProperty.GetValue(player, null);
if (value is bool)
{
flag = (bool)value;
num = 1;
}
else
{
num = 0;
}
}
else
{
num = 0;
}
return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
}
catch
{
return false;
}
}
public bool IsUnderWater(Vector3 position)
{
//IL_0046: 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)
EnsureCache();
try
{
object obj = _isUnderWaterMethod?.Invoke(null, new object[1] { position });
bool flag = default(bool);
int num;
if (obj is bool)
{
flag = (bool)obj;
num = 1;
}
else
{
num = 0;
}
return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
}
catch
{
return position.y < -1f;
}
}
public bool IsLikelyLava(Vector3 position)
{
//IL_0001: 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 (position.y > 2f)
{
return false;
}
Collider[] array = Physics.OverlapSphere(position, 1.2f, -1, (QueryTriggerInteraction)1);
Collider[] array2 = array;
foreach (Collider val in array2)
{
if (Object.op_Implicit((Object)(object)val))
{
string name = ((Object)((Component)val).gameObject).name;
if (name.IndexOf("lava", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("magma", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("volcano", StringComparison.OrdinalIgnoreCase) >= 0)
{
return true;
}
}
}
return false;
}
public bool HasLineOfSight(Vector3 from, Vector3 to)
{
//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_0003: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: 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_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_0039: Unknown result type (might be due to invalid IL or missing references)
Vector3 val = to - from;
float magnitude = ((Vector3)(ref val)).magnitude;
if (magnitude < 0.25f)
{
return true;
}
return !Physics.Raycast(from + Vector3.up * 0.4f, ((Vector3)(ref val)).normalized, magnitude - 0.2f, -5, (QueryTriggerInteraction)1);
}
public bool IsNetworkObjectOwner(GameObject gameObject)
{
EnsureCache();
if (!Object.op_Implicit((Object)(object)gameObject) || _networkObjectType == null)
{
return false;
}
Component component = gameObject.GetComponent(_networkObjectType);
if (!Object.op_Implicit((Object)(object)component))
{
return false;
}
try
{
object obj = _isOwnerProperty?.GetValue(component, null);
bool flag = default(bool);
int num;
if (obj is bool)
{
flag = (bool)obj;
num = 1;
}
else
{
num = 0;
}
return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
}
catch
{
return false;
}
}
public bool IsNetworkObjectServerInit(GameObject gameObject)
{
EnsureCache();
if (!Object.op_Implicit((Object)(object)gameObject) || _networkObjectType == null || _isServerInitializedProperty == null)
{
return IsServer;
}
Component component = gameObject.GetComponent(_networkObjectType);
if (!Object.op_Implicit((Object)(object)component))
{
return IsServer;
}
try
{
object value = _isServerInitializedProperty.GetValue(component, null);
bool flag = default(bool);
int num;
if (value is bool)
{
flag = (bool)value;
num = 1;
}
else
{
num = 0;
}
return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
}
catch
{
return IsServer;
}
}
public bool TryGetMoney(object player, out int money)
{
money = 0;
EnsureMoney(player);
return ReflectionUtil.TryReadInt(_moneyHost ?? player, _moneyMember, out money);
}
public bool TrySetMoney(object player, int money)
{
EnsureMoney(player);
return _moneyMember != null && ReflectionUtil.SetMember(_moneyHost ?? player, _moneyMember, money);
}
public bool TryCharge(object player, int amount, out int charged, out string error)
{
charged = 0;
error = null;
if (amount <= 0)
{
return true;
}
if (!TryGetMoney(player, out var money))
{
error = "Could not resolve wallet field.";
_log.LogWarning((object)"Money member not resolved yet. Cost skipped.");
return true;
}
if (money < amount)
{
error = $"Need ${amount}, you have ${money}.";
return false;
}
if (!TrySetMoney(player, money - amount))
{
error = "Failed to update balance.";
return false;
}
charged = amount;
return true;
}
public void TryShake(float intensity, int count, Vector2 range)
{
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
EnsureCache();
object localPlayer = GetLocalPlayer();
if (localPlayer == null || _shakeMethod == null)
{
return;
}
try
{
object obj = _screenShakeProperty?.GetValue(localPlayer, null);
if (obj != null)
{
_shakeMethod.Invoke(obj, new object[3] { intensity, count, range });
}
}
catch
{
}
}
public void TrySendLocalChat(string message)
{
EnsureCache();
if (string.IsNullOrEmpty(message))
{
return;
}
try
{
object obj = _chatInstanceField?.GetValue(null);
if (obj != null && _chatSendMethod != null)
{
ParameterInfo[] parameters = _chatSendMethod.GetParameters();
if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string))
{
_chatSendMethod.Invoke(obj, new object[1] { message });
return;
}
}
}
catch
{
}
_log.LogInfo((object)message);
}
public bool IsChatOrConsoleBlocking()
{
try
{
object obj = (Type.GetType("HowToFish.ModConsole.ModConsoleApi, HowToFish.ModConsole", throwOnError: false)?.GetProperty("IsOpen", BindingFlags.Static | BindingFlags.Public))?.GetValue(null, null);
bool flag = default(bool);
int num;
if (obj is bool)
{
flag = (bool)obj;
num = 1;
}
else
{
num = 0;
}
if (((uint)num & (flag ? 1u : 0u)) != 0)
{
return true;
}
}
catch
{
}
return false;
}
public IEnumerable<GameObject> FindSceneObjects()
{
//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)
List<GameObject> list = new List<GameObject>();
for (int i = 0; i < SceneManager.sceneCount; i++)
{
Scene sceneAt = SceneManager.GetSceneAt(i);
if (((Scene)(ref sceneAt)).isLoaded)
{
list.AddRange(((Scene)(ref sceneAt)).GetRootGameObjects());
}
}
List<GameObject> list2 = new List<GameObject>();
foreach (GameObject item in list)
{
Transform[] componentsInChildren = item.GetComponentsInChildren<Transform>(true);
foreach (Transform val in componentsInChildren)
{
list2.Add(((Component)val).gameObject);
}
}
return list2;
}
private object GetNetworkManager()
{
try
{
return _networkManagerProperty?.GetValue(null, null);
}
catch
{
return null;
}
}
private void EnsureMoney(object player)
{
if (_moneyResolved)
{
return;
}
EnsureCache();
string[] names = new string[11]
{
"Money", "money", "_money", "Cash", "cash", "_cash", "Gold", "Coins", "Wallet", "Balance",
"PlayerMoney"
};
List<object> list = new List<object>();
if (player != null)
{
list.Add(player);
}
if (_gameInfoType != null)
{
list.Add(_gameInfoType);
}
foreach (object item in list)
{
Type type = ((item is Type type2) ? type2 : item.GetType());
object obj = ((item is Type) ? null : item);
MemberInfo memberInfo = (MemberInfo)(((object)ReflectionUtil.FindProperty(type, names)) ?? ((object)ReflectionUtil.FindField(type, names)));
if (memberInfo == null || !ReflectionUtil.TryReadInt(obj, memberInfo, out var _))
{
continue;
}
_moneyMember = memberInfo;
_moneyHost = obj;
_moneyResolved = true;
_log.LogInfo((object)("Money bound to " + type.Name + "." + memberInfo.Name));
break;
}
}
private void EnsureCache()
{
if (Time.unscaledTime < _nextRefresh && _isCacheInitialized)
{
return;
}
_nextRefresh = Time.unscaledTime + 2f;
_playerType = _playerType ?? ReflectionUtil.FindType("Player, Assembly-CSharp");
_localPlayerField = _localPlayerField ?? ReflectionUtil.FindField(_playerType, "LocalPlayer");
_blockInputsProperty = _blockInputsProperty ?? ReflectionUtil.FindProperty(_playerType, "BlockInputs");
_holdingProperty = _holdingProperty ?? ReflectionUtil.FindProperty(_playerType, "Holding");
_screenShakeProperty = _screenShakeProperty ?? ReflectionUtil.FindProperty(_playerType, "ScreenShake");
Type type = ReflectionUtil.FindType("PlayerHolding, Assembly-CSharp");
_heldItemProperty = _heldItemProperty ?? ReflectionUtil.FindProperty(type, "HeldItem");
Type type2 = ReflectionUtil.FindType("PlayerScreenShake, Assembly-CSharp");
_shakeMethod = _shakeMethod ?? type2?.GetMethod("Shake", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
_gameInfoType = _gameInfoType ?? ReflectionUtil.FindType("GameInfo, Assembly-CSharp");
_waterManagerType = _waterManagerType ?? ReflectionUtil.FindType("WaterManager, Assembly-CSharp");
_isUnderWaterMethod = _isUnderWaterMethod ?? _waterManagerType?.GetMethod("IsUnderWater", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(Vector3) }, null);
_instanceFinderType = _instanceFinderType ?? ReflectionUtil.FindType("FishNet.InstanceFinder, FishNet.Runtime");
_networkManagerProperty = _networkManagerProperty ?? _instanceFinderType?.GetProperty("NetworkManager", BindingFlags.Static | BindingFlags.Public);
_networkObjectType = _networkObjectType ?? ReflectionUtil.FindType("FishNet.Object.NetworkObject, FishNet.Runtime");
_isOwnerProperty = _isOwnerProperty ?? _networkObjectType?.GetProperty("IsOwner", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
_isServerInitializedProperty = _isServerInitializedProperty ?? _networkObjectType?.GetProperty("IsServerInitialized", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
_chatManagerType = _chatManagerType ?? ReflectionUtil.FindType("ChatManager, Assembly-CSharp");
_chatInstanceField = _chatInstanceField ?? ReflectionUtil.FindField(_chatManagerType, "_instance", "Instance", "instance");
if (_chatManagerType != null && _chatSendMethod == null)
{
string[] array = new string[6] { "SendMessage", "AddMessage", "PostMessage", "Write", "Say", "LocalMessage" };
foreach (string name in array)
{
MethodInfo methodInfo = ReflectionUtil.FindMethod(_chatManagerType, name, 1);
if (methodInfo != null)
{
_chatSendMethod = methodInfo;
break;
}
}
}
_isCacheInitialized = _playerType != null && _chatManagerType != null;
}
private void CacheNetwork(Type type)
{
_isServerStartedProperty = _isServerStartedProperty ?? type.GetProperty("IsServerStarted", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
_isClientStartedProperty = _isClientStartedProperty ?? type.GetProperty("IsClientStarted", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
}
private static bool ReadBool(PropertyInfo property, object instance)
{
try
{
bool flag = default(bool);
int num;
if (property != null)
{
object value = property.GetValue(instance, null);
if (value is bool)
{
flag = (bool)value;
num = 1;
}
else
{
num = 0;
}
}
else
{
num = 0;
}
return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
}
catch
{
return false;
}
}
}
public sealed class ItemFinder
{
private static readonly string[] ItemHints = new string[5] { "Pickup", "InteractableItem", "DroppedItem", "InventoryItem", "HoldableItem" };
private static readonly string[] FishHints = new string[6] { "Fish", "Shark", "Crab", "Whale", "Leech", "Piranha" };
private static readonly string[] BaitHints = new string[3] { "Bait", "Lure", "Hook" };
private static readonly string[] BoatHints = new string[4] { "Boat", "Propeller", "Hull", "Rudder" };
private static readonly string[] WeaponHints = new string[8] { "Weapon", "Gun", "Rifle", "Pistol", "Shotgun", "Sniper", "Knife", "Melee" };
private static readonly string[] ToolHints = new string[9] { "Tool", "Hammer", "Axe", "Rod", "FishingRod", "FishingRodCrab", "Rod", "Pole", "FishingPole" };
private static readonly string[] RodHints = new string[9] { "Rod", "FishingRod", "Fishing Rod", "Fishing Rod(Clone)", "Crab Fishing Rod", "Crab Fishing Rod(Clone)", "FishRod", "Pole", "FishingPole" };
private static readonly string[] DurabilityNames = new string[4] { "Durability", "Condition", "CurrentDurability", "_durability" };
private static readonly string[] MaxDurabilityNames = new string[3] { "MaxDurability", "MaxHealth", "_maxDurability" };
private readonly ManualLogSource _log;
private readonly GameBridge _bridge;
public ItemFinder(ManualLogSource log, GameBridge bridge)
{
_log = log;
_bridge = bridge;
}
public int CountCandidates(Vector3 origin)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
return Collect(origin, _bridge.GetLocalPlayer()).Count;
}
public List<LostItem> Find(Vector3 origin, object player)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
return Collect(origin, player);
}
private List<LostItem> Collect(Vector3 origin, object player)
{
//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
//IL_017b: Unknown result type (might be due to invalid IL or missing references)
//IL_025e: Unknown result type (might be due to invalid IL or missing references)
List<LostItem> list = new List<LostItem>();
HashSet<int> seenRootIds = new HashSet<int>();
object obj = (RetrieverConfig.IgnoreHeldItem.Value ? _bridge.GetHeldItem(player) : null);
object obj2;
if (obj == null)
{
obj2 = null;
}
else
{
obj2 = ((obj is Item) ? obj : null);
if (obj2 == null)
{
object obj3 = ((obj is Component) ? obj : null);
obj2 = ((obj3 != null) ? ((Component)obj3).GetComponentInParent<Item>() : null);
}
}
Item val = (Item)obj2;
GameObject val2 = (((Object)(object)val != (Object)null) ? ((Component)val).gameObject : null);
int heldId = (((Object)(object)val2 != (Object)null) ? GetObjectId(val2) : 0);
float num = Mathf.Max(0f, RetrieverConfig.MinRange.Value);
float value = RetrieverConfig.MaxRange.Value;
int num2 = Mathf.Max(1, RetrieverConfig.MaxItemsPerUse.Value);
int num3 = 0;
int num4 = 0;
if ((Object)(object)ItemManager.Instance != (Object)null && ItemManager.Items != null)
{
foreach (KeyValuePair<Transform, Item> item in ItemManager.Items)
{
Item value2 = item.Value;
if ((Object)(object)value2 == (Object)null)
{
continue;
}
num3++;
if ((Object)(object)value2.Holder != (Object)null || (Object)(object)value2.SyncedHolder != (Object)null || (Object)(object)value2.BirdHolder != (Object)null)
{
continue;
}
GameObject gameObjectFromItem = GetGameObjectFromItem(value2);
if (!((Object)(object)gameObjectFromItem == (Object)null))
{
GameObject itemRoot = GetItemRoot(gameObjectFromItem);
if (!((Object)(object)itemRoot == (Object)null))
{
ProcessCandidate(itemRoot, origin, heldId, val2, num, value, seenRootIds, list);
}
}
}
}
if (ItemManager._itemsUnderwater != null)
{
try
{
foreach (Item item2 in ItemManager._itemsUnderwater)
{
if ((Object)(object)item2 == (Object)null)
{
continue;
}
num4++;
if ((Object)(object)item2.Holder != (Object)null || (Object)(object)item2.SyncedHolder != (Object)null || (Object)(object)item2.BirdHolder != (Object)null)
{
continue;
}
GameObject gameObjectFromItem2 = GetGameObjectFromItem(item2);
if (!((Object)(object)gameObjectFromItem2 == (Object)null))
{
GameObject itemRoot2 = GetItemRoot(gameObjectFromItem2);
if (!((Object)(object)itemRoot2 == (Object)null))
{
ProcessCandidate(itemRoot2, origin, heldId, val2, num, value, seenRootIds, list);
}
}
}
}
catch (Exception ex)
{
_log.LogDebug((object)("Underwater scan failed: " + ex.Message));
}
}
if (list.Count == 0)
{
_log.LogInfo((object)($"No candidates. Scanned Items={num3}, Underwater={num4}, " + $"minRange={num:F1}, maxRange={value:F1}, origin={origin}"));
}
list.Sort((LostItem a, LostItem b) => a.Distance.CompareTo(b.Distance));
if (list.Count > num2)
{
list.RemoveRange(num2, list.Count - num2);
}
return list;
}
private void ProcessCandidate(GameObject rootObject, Vector3 origin, int heldId, GameObject heldRoot, float minRange, float maxRange, HashSet<int> seenRootIds, List<LostItem> results)
{
//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_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: 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_0095: 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_00df: Unknown result type (might be due to invalid IL or missing references)
//IL_0110: Unknown result type (might be due to invalid IL or missing references)
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: 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)
int objectId = GetObjectId(rootObject);
if (!seenRootIds.Add(objectId) || (heldId != 0 && (objectId == heldId || IsChildOf(rootObject, heldRoot))) || !LooksLikeRetrievable(rootObject, out var category))
{
return;
}
Transform transform = rootObject.transform;
Vector3 position = transform.position;
if (position.y < RetrieverConfig.MinWorldY.Value || position.y > RetrieverConfig.MaxWorldY.Value)
{
return;
}
float num = Vector3.Distance(origin, position);
if (num < minRange || (maxRange > 0.01f && num > maxRange))
{
return;
}
bool underWater = _bridge.IsUnderWater(position);
bool flag = _bridge.IsLikelyLava(position);
if (!PassesLocation(underWater, flag) || (RetrieverConfig.RequireLineOfSight.Value && !_bridge.HasLineOfSight(origin + Vector3.up, position)))
{
return;
}
bool flag2 = _bridge.IsNetworkObjectOwner(rootObject);
if (!RetrieverConfig.RetrieveOnlyOwnedItems.Value || flag2)
{
LostItem lostItem = new LostItem
{
Source = rootObject,
GameObject = rootObject,
Transform = transform,
Rigidbody = (rootObject.GetComponent<Rigidbody>() ?? rootObject.GetComponentInParent<Rigidbody>()),
Name = ((Object)rootObject).name,
Category = category,
Distance = num,
UnderWater = underWater,
LikelyLava = flag,
Owned = flag2
};
FillDurability(lostItem);
if (!lostItem.HasDurability || !(lostItem.Durability <= 0.01f) || !RetrieverConfig.SkipBrokenItems.Value)
{
results.Add(lostItem);
}
}
}
private static int GetObjectId(GameObject obj)
{
if ((Object)(object)obj == (Object)null)
{
return 0;
}
Component component = obj.GetComponent<Component>();
if ((Object)(object)component != (Object)null)
{
return ((Object)component).GetInstanceID();
}
return ((Object)obj).GetInstanceID();
}
private static GameObject GetGameObjectFromItem(Item item)
{
if ((Object)(object)item == (Object)null)
{
return null;
}
return ((Object)(object)item != (Object)null) ? ((Component)item).gameObject : null;
}
private static GameObject GetItemRoot(GameObject gameObject)
{
if ((Object)(object)gameObject == (Object)null)
{
return null;
}
Item componentInParent = gameObject.GetComponentInParent<Item>();
if ((Object)(object)componentInParent != (Object)null)
{
return ((Component)componentInParent).gameObject;
}
return null;
}
private static bool PassesLocation(bool underWater, bool lava)
{
if (RetrieverConfig.AllowFromAnywhere.Value)
{
if (underWater && !RetrieverConfig.AllowFromOcean.Value)
{
return false;
}
if (lava && !RetrieverConfig.AllowFromLava.Value)
{
return false;
}
return true;
}
return (underWater && RetrieverConfig.AllowFromOcean.Value) || (lava && RetrieverConfig.AllowFromLava.Value);
}
private static bool LooksLikeRetrievable(GameObject gameObject, out string category)
{
category = "Other";
if ((Object)(object)gameObject == (Object)null)
{
return false;
}
string name = ((Object)gameObject).name;
string haystack = BuildTypeBlob(gameObject);
List<string> needles = ReflectionUtil.SplitList(RetrieverConfig.BlacklistNames.Value).ToList();
if (ReflectionUtil.NameMatches(name, needles) || ReflectionUtil.NameMatches(haystack, needles))
{
return false;
}
if (RetrieverConfig.IgnoreBoatParts.Value && (ReflectionUtil.NameMatches(name, BoatHints) || ReflectionUtil.NameMatches(haystack, BoatHints)))
{
return false;
}
if (RetrieverConfig.IgnoreBait.Value && (ReflectionUtil.NameMatches(name, BaitHints) || ReflectionUtil.NameMatches(haystack, BaitHints)))
{
return false;
}
Item val = gameObject.GetComponent<Item>() ?? gameObject.GetComponentInParent<Item>();
if ((Object)(object)val == (Object)null)
{
return false;
}
if ((Object)(object)val.FishingRod != (Object)null)
{
category = "Rods";
return CategoryAllowed(category);
}
bool flag = ReflectionUtil.NameMatches(name, FishHints) || ReflectionUtil.NameMatches(haystack, FishHints);
bool flag2 = ReflectionUtil.NameMatches(name, RodHints) || ReflectionUtil.NameMatches(haystack, RodHints);
bool flag3 = ReflectionUtil.NameMatches(name, WeaponHints) || ReflectionUtil.NameMatches(haystack, WeaponHints);
bool flag4 = ReflectionUtil.NameMatches(name, ToolHints) || ReflectionUtil.NameMatches(haystack, ToolHints);
if (flag)
{
if (RetrieverConfig.IgnoreFish.Value)
{
return false;
}
category = "Fish";
}
else if (flag3)
{
category = "Weapons";
}
else if (flag2)
{
category = "Rods";
}
else if (flag4)
{
category = "Tools";
}
else
{
category = "Other";
}
if ((Object)(object)gameObject.GetComponentInChildren<Camera>() != (Object)null || (Object)(object)gameObject.GetComponentInChildren<Light>() != (Object)null || (Object)(object)gameObject.GetComponentInChildren<AudioListener>() != (Object)null)
{
return false;
}
return CategoryAllowed(category);
}
private static bool CategoryAllowed(string category)
{
bool flag = false;
List<string> list = ReflectionUtil.SplitList(RetrieverConfig.AllowedItemTypes.Value).ToList();
for (int i = 0; i < list.Count; i++)
{
string text = list[i];
flag = true;
if (text.Equals("All", StringComparison.OrdinalIgnoreCase) || text.Equals(category, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return !flag;
}
private static string BuildTypeBlob(GameObject gameObject)
{
Component[] componentsInChildren = gameObject.GetComponentsInChildren<Component>(true);
StringBuilder stringBuilder = new StringBuilder(((Object)gameObject).name);
foreach (Component val in componentsInChildren)
{
if ((Object)(object)val != (Object)null)
{
stringBuilder.Append(' ').Append(((object)val).GetType().Name);
}
}
return stringBuilder.ToString();
}
private static bool IsChildOf(GameObject candidate, GameObject parent)
{
if ((Object)(object)candidate == (Object)null || (Object)(object)parent == (Object)null)
{
return false;
}
return candidate.transform.IsChildOf(parent.transform);
}
private static void FillDurability(LostItem item)
{
Item val = item.GameObject.GetComponent<Item>() ?? item.GameObject.GetComponentInParent<Item>();
if ((Object)(object)val == (Object)null)
{
return;
}
Type type = ((object)val).GetType();
MemberInfo memberInfo = (MemberInfo)(((object)ReflectionUtil.FindProperty(type, DurabilityNames)) ?? ((object)ReflectionUtil.FindField(type, DurabilityNames)));
if (!(memberInfo == null) && ReflectionUtil.TryReadFloat(val, memberInfo, out var value))
{
item.HasDurability = true;
item.Durability = value;
MemberInfo memberInfo2 = (MemberInfo)(((object)ReflectionUtil.FindProperty(type, MaxDurabilityNames)) ?? ((object)ReflectionUtil.FindField(type, MaxDurabilityNames)));
if (memberInfo2 != null && ReflectionUtil.TryReadFloat(val, memberInfo2, out var value2) && value2 > 0f)
{
item.MaxDurability = value2;
}
else
{
item.MaxDurability = Mathf.Max(value, 100f);
}
}
}
}
public sealed class NetworkSync
{
private readonly ManualLogSource _log;
private readonly GameBridge _bridge;
private Type _networkTransformType;
private MethodInfo _teleportMethod;
public bool IsServer => _bridge.IsServer;
public bool CanRetrieve
{
get
{
if (RetrieverConfig.HostOnly.Value)
{
return _bridge.IsServer;
}
return true;
}
}
public NetworkSync(ManualLogSource log, GameBridge bridge)
{
_log = log;
_bridge = bridge;
}
public bool CanMove(GameObject gameObject)
{
if (!Object.op_Implicit((Object)(object)gameObject))
{
return false;
}
if (_bridge.IsServer)
{
return true;
}
Item val = gameObject.GetComponent<Item>() ?? gameObject.GetComponentInParent<Item>();
if ((Object)(object)val != (Object)null)
{
return true;
}
return _bridge.IsNetworkObjectOwner(gameObject);
}
public void TeleportItem(GameObject gameObject, Vector3 targetPosition, Quaternion targetRotation)
{
//IL_0063: 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_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: 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_00a6: 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_00b0: Unknown result type (might be due to invalid IL or missing references)
//IL_00b9: 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)
//IL_0046: 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)
if (!Object.op_Implicit((Object)(object)gameObject))
{
return;
}
Rigidbody val = gameObject.GetComponent<Rigidbody>() ?? gameObject.GetComponentInParent<Rigidbody>();
if ((Object)(object)val != (Object)null)
{
if (!val.isKinematic)
{
try
{
val.linearVelocity = Vector3.zero;
val.angularVelocity = Vector3.zero;
}
catch
{
val.velocity = Vector3.zero;
val.angularVelocity = Vector3.zero;
}
}
val.position = targetPosition;
val.rotation = targetRotation;
val.WakeUp();
}
Transform transform = gameObject.transform;
transform.position = targetPosition;
transform.rotation = targetRotation;
SyncNetworkTransform(gameObject, targetPosition, targetRotation);
TryStartSimulateLocal(gameObject, targetPosition, targetRotation);
}
private void TryStartSimulateLocal(GameObject gameObject, Vector3 pos, Quaternion rot)
{
//IL_00df: 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)
try
{
Item val = gameObject.GetComponent<Item>() ?? gameObject.GetComponentInParent<Item>();
if ((Object)(object)val == (Object)null)
{
return;
}
MemberInfo memberInfo = (MemberInfo)(((object)((object)val).GetType().GetProperty("RigidbodySync", BindingFlags.Instance | BindingFlags.Public)) ?? ((object)((object)val).GetType().GetField("RigidbodySync", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)));
if (memberInfo == null)
{
return;
}
object obj = ((memberInfo is PropertyInfo propertyInfo) ? propertyInfo.GetValue(val) : ((FieldInfo)memberInfo).GetValue(val));
if (obj != null)
{
MethodInfo method = obj.GetType().GetMethod("StartSimulateLocal", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2]
{
typeof(Vector3),
typeof(Quaternion)
}, null);
if (method != null)
{
method.Invoke(obj, new object[2] { pos, rot });
_log.LogInfo((object)("-> RigidbodySync.StartSimulateLocal called on '" + ((Object)gameObject).name + "'"));
}
}
}
catch (Exception ex)
{
_log.LogDebug((object)("RigidbodySync.StartSimulateLocal failed: " + ex.Message));
}
}
private void SyncNetworkTransform(GameObject gameObject, Vector3 position, Quaternion rotation)
{
//IL_006a: 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)
EnsureCache();
if (_networkTransformType == null)
{
return;
}
Component val = gameObject.GetComponent(_networkTransformType) ?? gameObject.GetComponentInParent(_networkTransformType);
if (!Object.op_Implicit((Object)(object)val))
{
return;
}
try
{
if (_teleportMethod != null)
{
_teleportMethod.Invoke(val, new object[2] { position, rotation });
}
}
catch (Exception ex)
{
_log.LogDebug((object)("NetworkTransform teleport failed: " + ex.Message));
}
}
private void EnsureCache()
{
if (!(_networkTransformType != null))
{
_networkTransformType = ReflectionUtil.FindType("FishNet.Component.Transforming.NetworkTransform, FishNet.Runtime");
if (_networkTransformType != null)
{
_teleportMethod = _networkTransformType.GetMethod("Teleport", new Type[2]
{
typeof(Vector3),
typeof(Quaternion)
});
}
}
}
}
public sealed class RetrieverLogic
{
private readonly ManualLogSource _log;
private readonly GameBridge _bridge;
private readonly ItemFinder _finder;
private readonly NetworkSync _network;
public RetrieverLogic(ManualLogSource log, GameBridge bridge, ItemFinder finder, NetworkSync network)
{
_log = log;
_bridge = bridge;
_finder = finder;
_network = network;
}
public RetrieveResult TryRetrieve(object player, string source)
{
//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)
//IL_0045: 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_01bb: Unknown result type (might be due to invalid IL or missing references)
//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
//IL_01eb: 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_01f5: Unknown result type (might be due to invalid IL or missing references)
//IL_0558: Unknown result type (might be due to invalid IL or missing references)
//IL_043d: Unknown result type (might be due to invalid IL or missing references)
//IL_0447: Unknown result type (might be due to invalid IL or missing references)
//IL_044c: Unknown result type (might be due to invalid IL or missing references)
//IL_044e: Unknown result type (might be due to invalid IL or missing references)
//IL_0450: Unknown result type (might be due to invalid IL or missing references)
//IL_045c: Unknown result type (might be due to invalid IL or missing references)
//IL_0463: Unknown result type (might be due to invalid IL or missing references)
//IL_0468: Unknown result type (might be due to invalid IL or missing references)
//IL_046d: Unknown result type (might be due to invalid IL or missing references)
//IL_0472: Unknown result type (might be due to invalid IL or missing references)
Transform playerTransform = _bridge.GetPlayerTransform(player);
if ((Object)(object)playerTransform == (Object)null)
{
return RetrieveResult.Failed("Player transform missing.");
}
Vector3 playerPosition = _bridge.GetPlayerPosition(player);
_log.LogInfo((object)$"Retrieve origin (cam): {playerPosition}");
List<LostItem> list = _finder.Find(playerPosition, player);
if (list.Count == 0)
{
if (RetrieverConfig.ChargeEvenIfNothingFound.Value && RetrieverConfig.MoneyCost.Value > 0)
{
if (!TryPay(player, RetrieverConfig.MoneyCost.Value, 0f, 0, out var charged, out var error))
{
return RetrieveResult.Failed(error);
}
return RetrieveResult.Ok("No items found. Charged the flat fee anyway.", 0, 0, 0, charged);
}
return RetrieveResult.Failed("No lost items found. They may have despawned, or filters excluded them.");
}
list = DeduplicateRodsKeepFarthest(list);
float num = 0f;
for (int i = 0; i < list.Count; i++)
{
if (list[i].Distance > num)
{
num = list[i].Distance;
}
}
int num2 = ComputeCost(num, list.Count);
if (RetrieverConfig.FailIfCannotAfford.Value && num2 > 0 && _bridge.TryGetMoney(player, out var money) && money < num2)
{
return RetrieveResult.Failed($"Need ${num2} to retrieve {list.Count} item(s). You have ${money}.");
}
Vector3 val = playerPosition + _bridge.GetPlayerForward(player) * RetrieverConfig.DropInFrontDistance.Value + Vector3.up * RetrieverConfig.DropHeight.Value;
int num3 = 0;
int num4 = 0;
int num5 = 0;
HashSet<GameObject> hashSet = new HashSet<GameObject>();
for (int j = 0; j < list.Count; j++)
{
LostItem lostItem = list[j];
GameObject targetRootObject = GetTargetRootObject(lostItem.GameObject);
if ((Object)(object)targetRootObject == (Object)null || hashSet.Contains(targetRootObject))
{
num4++;
continue;
}
_log.LogInfo((object)$"Evaluating candidate item: '{lostItem.Name}' -> Root: '{((Object)targetRootObject).name}' (Category: {lostItem.Category}, Distance: {lostItem.Distance:F1}m)");
if (IsAttachedToPlayerHierarchy(targetRootObject, playerTransform))
{
_log.LogInfo((object)("-> Skipped '" + ((Object)targetRootObject).name + "' because it is attached to the local player."));
num4++;
continue;
}
Item val2 = targetRootObject.GetComponent<Item>() ?? targetRootObject.GetComponentInParent<Item>();
if ((Object)(object)val2 != (Object)null && ((Object)(object)val2.Holder != (Object)null || (Object)(object)val2.SyncedHolder != (Object)null))
{
_log.LogInfo((object)("-> Skipped '" + ((Object)targetRootObject).name + "' because it is actively held."));
num4++;
continue;
}
if (!_network.CanMove(targetRootObject))
{
_log.LogInfo((object)("-> Skipped '" + ((Object)targetRootObject).name + "' due to network authority/CanMove."));
num4++;
continue;
}
if (!ApplyDurability(lostItem, out var broke))
{
num4++;
continue;
}
if (broke && RetrieverConfig.DestroyIfBroken.Value)
{
if ((Object)(object)val2 != (Object)null && (Object)(object)ItemManager.Instance != (Object)null)
{
ItemManager._itemsUnderwater.Remove(val2);
}
Object.Destroy((Object)(object)targetRootObject);
num5++;
hashSet.Add(targetRootObject);
continue;
}
if ((Object)(object)val2 != (Object)null && (Object)(object)ItemManager.Instance != (Object)null)
{
ItemManager._itemsUnderwater.Remove(val2);
}
Vector2 val3 = Random.insideUnitCircle * 0.2f;
Vector3 dropTarget = val + new Vector3(val3.x, 0f, val3.y);
MoveOrFlyRootItem(targetRootObject, dropTarget);
hashSet.Add(targetRootObject);
_log.LogInfo((object)("-> Successfully initiated retrieval for root item '" + ((Object)targetRootObject).name + "'"));
num3++;
}
if (num3 == 0 && num5 == 0)
{
return RetrieveResult.Failed($"Found {list.Count} candidate(s) but none could be moved.");
}
if (!TryPay(player, RetrieverConfig.MoneyCost.Value, num, num3, out var charged2, out var error2) && RetrieverConfig.FailIfCannotAfford.Value)
{
_log.LogWarning((object)("Items already moved but payment failed: " + error2));
}
if (RetrieverConfig.PlaySound.Value)
{
PlayWhoosh(val);
}
string message = $"Retrieved {num3} item(s) via {source}" + ((num5 > 0) ? $", destroyed {num5}" : string.Empty) + ((num4 > 0) ? $", skipped {num4}" : string.Empty) + ((charged2 > 0) ? $", charged ${charged2}" : string.Empty) + ".";
return RetrieveResult.Ok(message, num3, num4, num5, charged2);
}
private List<LostItem> DeduplicateRodsKeepFarthest(List<LostItem> items)
{
if (items == null || items.Count <= 1)
{
return items;
}
Dictionary<string, LostItem> dictionary = new Dictionary<string, LostItem>(StringComparer.OrdinalIgnoreCase);
List<LostItem> list = new List<LostItem>();
for (int i = 0; i < items.Count; i++)
{
LostItem lostItem = items[i];
if (!string.Equals(lostItem.Category, "Rods", StringComparison.OrdinalIgnoreCase) && (lostItem.Name == null || lostItem.Name.IndexOf("Rod", StringComparison.OrdinalIgnoreCase) < 0))
{
list.Add(lostItem);
continue;
}
string key = NormalizeItemName(lostItem.Name);
if (!dictionary.TryGetValue(key, out var value) || lostItem.Distance > value.Distance)
{
if (value != null)
{
_log.LogInfo((object)$"-> Skipping nearer duplicate rod '{value.Name}' at {value.Distance:F1}m (keeping {lostItem.Distance:F1}m)");
}
dictionary[key] = lostItem;
}
else
{
_log.LogInfo((object)$"-> Skipping nearer duplicate rod '{lostItem.Name}' at {lostItem.Distance:F1}m (keeping {value.Distance:F1}m)");
}
}
List<LostItem> list2 = new List<LostItem>(list.Count + dictionary.Count);
list2.AddRange(list);
foreach (KeyValuePair<string, LostItem> item in dictionary)
{
list2.Add(item.Value);
}
list2.Sort((LostItem a, LostItem b) => a.Distance.CompareTo(b.Distance));
return list2;
}
private static string NormalizeItemName(string name)
{
if (string.IsNullOrEmpty(name))
{
return string.Empty;
}
string text = name.Trim();
if (text.EndsWith("(Clone)", StringComparison.OrdinalIgnoreCase))
{
text = text.Substring(0, text.Length - 7).Trim();
}
return text;
}
private static GameObject GetTargetRootObject(GameObject candidate)
{
if ((Object)(object)candidate == (Object)null)
{
return null;
}
Item componentInParent = candidate.GetComponentInParent<Item>();
if ((Object)(object)componentInParent != (Object)null)
{
return ((Component)((Component)componentInParent).transform).gameObject;
}
Rigidbody componentInParent2 = candidate.GetComponentInParent<Rigidbody>();
if ((Object)(object)componentInParent2 != (Object)null)
{
return ((Component)componentInParent2).gameObject;
}
return ((Component)candidate.transform.root).gameObject;
}
private static bool IsAttachedToPlayerHierarchy(GameObject obj, Transform playerTransform)
{
if ((Object)(object)obj == (Object)null || (Object)(object)playerTransform == (Object)null)
{
return false;
}
return obj.transform.IsChildOf(playerTransform);
}
private void MoveOrFlyRootItem(GameObject rootObj, Vector3 dropTarget)
{
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: 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_0018: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)Plugin.Instance != (Object)null)
{
((MonoBehaviour)Plugin.Instance).StartCoroutine(FlyToTargetRoutine(rootObj, dropTarget, 0.55f));
return;
}
_network.TeleportItem(rootObj, dropTarget, rootObj.transform.rotation);
ForceVisible(rootObj);
LogGroundDrop(rootObj, dropTarget);
}
private IEnumerator FlyToTargetRoutine(GameObject itemRoot, Vector3 dropPoint, float duration)
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)itemRoot == (Object)null)
{
yield break;
}
Rigidbody rb = itemRoot.GetComponent<Rigidbody>() ?? itemRoot.GetComponentInParent<Rigidbody>();
bool wasKinematic = false;
if ((Object)(object)rb != (Object)null)
{
wasKinematic = rb.isKinematic;
rb.isKinematic = true;
}
ForceVisible(itemRoot);
Vector3 startPos = itemRoot.transform.position;
float elapsed = 0f;
while (elapsed < duration)
{
if ((Object)(object)itemRoot == (Object)null)
{
yield break;
}
elapsed += Time.deltaTime;
float t = Mathf.Clamp01(elapsed / duration);
float easeT = 1f - Mathf.Pow(1f - t, 3f);
Vector3 arcOffset = Vector3.up * (Mathf.Sin(t * MathF.PI) * 1.2f);
itemRoot.transform.position = Vector3.Lerp(startPos, dropPoint, easeT) + arcOffset;
yield return null;
}
if ((Object)(object)itemRoot == (Object)null)
{
yield break;
}
if ((Object)(object)rb != (Object)null)
{
rb.isKinematic = wasKinematic;
}
Quaternion finalRot = itemRoot.transform.rotation;
_network.TeleportItem(itemRoot, dropPoint, finalRot);
ForceVisible(itemRoot);
_log.LogInfo((object)$"-> Teleported '{((Object)itemRoot).name}' to {dropPoint}");
yield return null;
if ((Object)(object)itemRoot == (Object)null)
{
_log.LogWarning((object)"-> Item destroyed after teleport (game cleanup?).");
yield break;
}
float drift = Vector3.Distance(itemRoot.transform.position, dropPoint);
_log.LogInfo((object)$"-> After settle: pos={itemRoot.transform.position}, drift={drift:F1}m");
if (drift > 3f)
{
_log.LogWarning((object)$"-> Drift {drift:F1}m — re-applying teleport + SimulateLocal.");
_network.TeleportItem(itemRoot, dropPoint, finalRot);
ForceVisible(itemRoot);
}
LogGroundDrop(itemRoot, dropPoint);
}
private void LogGroundDrop(GameObject itemRoot, Vector3 dropPoint)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)itemRoot == (Object)null))
{
_log.LogInfo((object)$"-> '{((Object)itemRoot).name}' is on the ground in front of you at {dropPoint}. Press E to pick it up.");
}
}
private static void ForceVisible(GameObject root)
{
if ((Object)(object)root == (Object)null)
{
return;
}
if (!root.activeSelf)
{
root.SetActive(true);
}
MeshRenderer[] componentsInChildren = root.GetComponentsInChildren<MeshRenderer>(true);
foreach (MeshRenderer val in componentsInChildren)
{
if ((Object)(object)val != (Object)null)
{
((Renderer)val).enabled = true;
}
}
}
private static int ComputeCost(float farthest, int count)
{
float num = (float)RetrieverConfig.MoneyCost.Value + RetrieverConfig.CostPerDistance.Value * farthest + (float)(RetrieverConfig.CostPerItem.Value * count);
return Mathf.Max(0, Mathf.RoundToInt(num));
}
private bool TryPay(object player, int flat, float farthest, int count, out int charged, out string error)
{
int amount = ComputeCost(farthest, count);
if (flat <= 0 && RetrieverConfig.CostPerDistance.Value <= 0f && RetrieverConfig.CostPerItem.Value <= 0)
{
amount = 0;
}
return _bridge.TryCharge(player, amount, out charged, out error);
}
private static bool ApplyDurability(LostItem item, out bool broke)
{
broke = false;
if (!item.HasDurability)
{
return true;
}
float num = Mathf.Clamp(RetrieverConfig.DurabilityLossPercent.Value, 0f, 100f);
float num2 = item.Durability;
if (num > 0f)
{
num2 -= item.Durability * (num / 100f);
}
num2 -= Mathf.Max(0f, RetrieverConfig.DurabilityLossFlat.Value);
num2 = Mathf.Max(0f, num2);
broke = num2 <= 0.01f;
item.Durability = num2;
WriteDurability(item, num2);
return true;
}
private static void WriteDurability(LostItem item, float value)
{
string[] names = new string[5] { "Durability", "Condition", "Health", "CurrentDurability", "_durability" };
Component[] components = item.GameObject.GetComponents<Component>();
foreach (Component val in components)
{
if (!((Object)(object)val == (Object)null))
{
MemberInfo memberInfo = (MemberInfo)(((object)ReflectionUtil.FindProperty(((object)val).GetType(), names)) ?? ((object)ReflectionUtil.FindField(((object)val).GetType(), names)));
if (memberInfo != null && ReflectionUtil.SetMember(val, memberInfo, value))
{
break;
}
}
}
}
private static void PlayWhoosh(Vector3 position)
{
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
try
{
AudioClip val = AudioClip.Create("retriever-whoosh", 8000, 1, 8000, false);
float[] array = new float[8000];
for (int i = 0; i < array.Length; i++)
{
float num = (float)i / 8000f;
array[i] = Mathf.Sin(MathF.PI * 2f * Mathf.Lerp(900f, 180f, num) * num) * (1f - num) * 0.2f;
}
val.SetData(array, 0);
AudioSource.PlayClipAtPoint(val, position, 0.6f);
}
catch
{
}
}
}
}
namespace HowToFish.ItemRetriever.Models
{
public sealed class LostItem
{
public object Source { get; set; }
public GameObject GameObject { get; set; }
public Transform Transform { get; set; }
public Rigidbody Rigidbody { get; set; }
public string Name { get; set; }
public string Category { get; set; }
public float Distance { get; set; }
public bool UnderWater { get; set; }
public bool LikelyLava { get; set; }
public bool Owned { get; set; }
public float Durability { get; set; }
public float MaxDurability { get; set; }
public bool HasDurability { get; set; }
public GameObject RootGameObject => ((Object)(object)Rigidbody != (Object)null) ? ((Component)Rigidbody).gameObject : (Object.op_Implicit((Object)(object)GameObject) ? ((Component)GameObject.transform.root).gameObject : null);
}
public sealed class RetrieveResult
{
public bool Success { get; private set; }
public string Message { get; private set; }
public int Moved { get; private set; }
public int Skipped { get; private set; }
public int Destroyed { get; private set; }
public int Charged { get; private set; }
public int TotalProcessed => Moved + Skipped + Destroyed;
public static RetrieveResult Failed(string message)
{
return new RetrieveResult
{
Success = false,
Message = (message ?? string.Empty),
Moved = 0,
Skipped = 0,
Destroyed = 0,
Charged = 0
};
}
public static RetrieveResult Ok(string message, int moved, int skipped, int destroyed, int charged)
{
return new RetrieveResult
{
Success = true,
Message = (message ?? string.Empty),
Moved = moved,
Skipped = skipped,
Destroyed = destroyed,
Charged = charged
};
}
}
}
namespace HowToFish.ItemRetriever.Config
{
public static class RetrieverConfig
{
public static ConfigEntry<bool> Enabled { get; private set; }
public static ConfigEntry<KeyCode> RetrieveKey { get; private set; }
public static ConfigEntry<bool> IgnoreWhenChatOpen { get; private set; }
public static ConfigEntry<float> MaxRange { get; private set; }
public static ConfigEntry<float> MinRange { get; private set; }
public static ConfigEntry<int> MaxItemsPerUse { get; private set; }
public static ConfigEntry<float> DropInFrontDistance { get; private set; }
public static ConfigEntry<float> DropHeight { get; private set; }
public static ConfigEntry<float> CooldownSeconds { get; private set; }
public static ConfigEntry<int> MoneyCost { get; private set; }
public static ConfigEntry<float> CostPerDistance { get; private set; }
public static ConfigEntry<int> CostPerItem { get; private set; }
public static ConfigEntry<bool> FailIfCannotAfford { get; private set; }
public static ConfigEntry<bool> ChargeEvenIfNothingFound { get; private set; }
public static ConfigEntry<float> DurabilityLossPercent { get; private set; }
public static ConfigEntry<float> DurabilityLossFlat { get; private set; }
public static ConfigEntry<bool> SkipBrokenItems { get; private set; }
public static ConfigEntry<bool> DestroyIfBroken { get; private set; }
public static ConfigEntry<bool> HostOnly { get; private set; }
public static ConfigEntry<bool> RetrieveOnlyOwnedItems { get; private set; }
public static ConfigEntry<bool> RequireLineOfSight { get; private set; }
public static ConfigEntry<bool> AllowFromOcean { get; private set; }
public static ConfigEntry<bool> AllowFromLava { get; private set; }
public static ConfigEntry<bool> AllowFromAnywhere { get; private set; }
public static ConfigEntry<float> MinWorldY { get; private set; }
public static ConfigEntry<float> MaxWorldY { get; private set; }
public static ConfigEntry<string> AllowedItemTypes { get; private set; }
public static ConfigEntry<string> BlacklistNames { get; private set; }
public static ConfigEntry<bool> IgnoreFish { get; private set; }
public static ConfigEntry<bool> IgnoreBait { get; private set; }
public static ConfigEntry<bool> IgnoreBoatParts { get; private set; }
public static ConfigEntry<bool> IgnoreHeldItem { get; private set; }
public static ConfigEntry<bool> PlaySound { get; private set; }
public static ConfigEntry<bool> ShowChatMessage { get; private set; }
public static ConfigEntry<bool> ScreenShake { get; private set; }
public static ConfigEntry<bool> LogToConsole { get; private set; }
public static ConfigEntry<bool> ZeroVelocityOnRetrieve { get; private set; }
public static void Bind(ConfigFile config)
{
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
//IL_00c5: Expected O, but got Unknown
//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
//IL_01ee: Expected O, but got Unknown
Enabled = config.Bind<bool>("General", "Enabled", true, "Master switch for Item Retriever.");
RetrieveKey = config.Bind<KeyCode>("Controls", "RetrieveKey", (KeyCode)289, "Press to pull lost items back in front of you.");
IgnoreWhenChatOpen = config.Bind<bool>("Controls", "IgnoreWhenChatOpen", true, "Ignore the hotkey while chat, console, or BlockInputs is active.");
MaxRange = config.Bind<float>("Range", "MaxRange", 8f, "Maximum distance in meters. 0 = unlimited.");
MinRange = config.Bind<float>("Range", "MinRange", 0f, "Ignore items already this close. Stops you scooping the pile at your feet.");
MaxItemsPerUse = config.Bind<int>("Range", "MaxItemsPerUse", 25, new ConfigDescription("Hard cap per press.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 200), Array.Empty<object>()));
DropInFrontDistance = config.Bind<float>("Range", "DropInFrontDistance", 1.6f, "How far in front of the player retrieved items appear.");
DropHeight = config.Bind<float>("Range", "DropHeight", 0.85f, "Extra height so items do not spawn inside the ground.");
CooldownSeconds = config.Bind<float>("Range", "CooldownSeconds", 8f, "Seconds before you can retrieve again. 0 = no cooldown.");
MoneyCost = config.Bind<int>("Cost", "MoneyCost", 0, "Flat money charged per retrieve, before distance/item extras. 0 = free.");
CostPerDistance = config.Bind<float>("Cost", "CostPerDistance", 0f, "Extra money per meter of the farthest retrieved item.");
CostPerItem = config.Bind<int>("Cost", "CostPerItem", 0, "Extra money charged per item actually moved.");
FailIfCannotAfford = config.Bind<bool>("Cost", "FailIfCannotAfford", true, "If true, do nothing when you cannot pay the full cost.");
ChargeEvenIfNothingFound = config.Bind<bool>("Cost", "ChargeEvenIfNothingFound", false, "Charge the flat fee even when no items were found.");
DurabilityLossPercent = config.Bind<float>("Durability", "DurabilityLossPercent", 0f, new ConfigDescription("Percent of current durability removed on retrieve (0-100).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
DurabilityLossFlat = config.Bind<float>("Durability", "DurabilityLossFlat", 0f, "Flat durability removed after the percent cut.");
SkipBrokenItems = config.Bind<bool>("Durability", "SkipBrokenItems", true, "Do not retrieve items that already have 0 durability.");
DestroyIfBroken = config.Bind<bool>("Durability", "DestroyIfBroken", false, "If durability hits 0 during retrieve, destroy the item instead of returning it.");
HostOnly = config.Bind<bool>("Multiplayer", "HostOnly", true, "Only the lobby host may retrieve. Safest with FishNet authority.");
RetrieveOnlyOwnedItems = config.Bind<bool>("Multiplayer", "RetrieveOnlyOwnedItems", false, "Only move items this player owns / originally dropped.");
RequireLineOfSight = config.Bind<bool>("Restrictions", "RequireLineOfSight", false, "Skip items with terrain between you and them.");
AllowFromOcean = config.Bind<bool>("Restrictions", "AllowFromOcean", true, "Retrieve items that are underwater.");
AllowFromLava = config.Bind<bool>("Restrictions", "AllowFromLava", true, "Retrieve items that sit very low / in lava-like volumes.");
AllowFromAnywhere = config.Bind<bool>("Restrictions", "AllowFromAnywhere", true, "If true, land items far away are also retrieved. If false, only ocean/lava.");
MinWorldY = config.Bind<float>("Restrictions", "MinWorldY", -500f, "Ignore items below this world Y.");
MaxWorldY = config.Bind<float>("Restrictions", "MaxWorldY", 500f, "Ignore items above this world Y.");
AllowedItemTypes = config.Bind<string>("Filters", "AllowedItemTypes", "All", "Comma list: All, Weapons, Tools, Rods, Fish, Other. Case-insensitive.");
BlacklistNames = config.Bind<string>("Filters", "BlacklistNames", "Bait,Boat,Player,Camera,Water,Seagull,Bird,Clam,Rock,Prop,Terrain", "Comma list of name fragments to skip.");
IgnoreFish = config.Bind<bool>("Filters", "IgnoreFish", true, "Skip living / flopping fish so you do not vacuum the whole ocean.");
IgnoreBait = config.Bind<bool>("Filters", "IgnoreBait", true, "Skip fishing bait objects.");
IgnoreBoatParts = config.Bind<bool>("Filters", "IgnoreBoatParts", true, "Skip the boat and attached parts.");
IgnoreHeldItem = config.Bind<bool>("Filters", "IgnoreHeldItem", true, "Never teleport the item currently in your hands.");
PlaySound = config.Bind<bool>("Feedback", "PlaySound", true, "Play a short whoosh when something is retrieved.");
ShowChatMessage = config.Bind<bool>("Feedback", "ShowChatMessage", true, "Print a local chat / hint line with the result.");
ScreenShake = config.Bind<bool>("Feedback", "ScreenShake", false, "Tiny camera shake on a successful retrieve.");
LogToConsole = config.Bind<bool>("Feedback", "LogToConsole", true, "Write results to the BepInEx log.");
ZeroVelocityOnRetrieve = config.Bind<bool>("Feedback", "ZeroVelocityOnRetrieve", true, "Kill rigidbody velocity so items do not immediately yeet again.");
}
}
}