using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using AzNean.SotfCommon;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Microsoft.CodeAnalysis;
using Sons.Inventory;
using TheForest.Items.Inventory;
using TheForest.Items.Special;
using TheForest.Items.Utils;
using TheForest.Utils;
using ThrowAnything.Logic;
using ThrowAnything.Patches;
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("ThrowAnything")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.3.0")]
[assembly: AssemblyInformationalVersion("0.1.3+25cbfd528443c0ae893d9407fc052029f68b30ae")]
[assembly: AssemblyProduct("ThrowAnything")]
[assembly: AssemblyTitle("ThrowAnything")]
[assembly: AssemblyVersion("0.1.3.0")]
[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 AzNean.SotfCommon
{
internal static class ModLog
{
private static ManualLogSource _log;
private static ConfigEntry<bool> _full;
private static readonly HashSet<string> _once = new HashSet<string>();
private static readonly Dictionary<(int, string), int> _state = new Dictionary<(int, string), int>();
internal static bool Full => _full.Value;
internal static void Init(ManualLogSource log, ConfigEntry<bool> full)
{
_log = log;
_full = full;
}
internal static void Trace(string message)
{
if (_full.Value)
{
_log.LogInfo((object)message);
}
}
internal static bool Changed(int id, string what, int state)
{
if (!_full.Value || (_state.TryGetValue((id, what), out var value) && value == state))
{
return false;
}
_state[(id, what)] = state;
return true;
}
internal static void Once(string key, string message, LogLevel level = (LogLevel)16)
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
if (_once.Add(key))
{
_log.Log(level, (object)message);
}
}
}
}
namespace ThrowAnything
{
[BepInPlugin("aznan.sotf.throwanything", "ThrowAnything", "0.1.3")]
public class Plugin : BasePlugin
{
internal const string Version = "0.1.3";
internal const float HeldSpawnWaitSeconds = 3f;
internal static ManualLogSource Logger;
internal static ConfigEntry<bool> Enabled;
internal static ConfigEntry<bool> WholeStack;
internal static ConfigEntry<bool> EquipPrevious;
internal static ConfigEntry<bool> FullLogging;
internal static ConfigEntry<KeyCode> ThrowKey;
internal static ConfigEntry<KeyCode> ModifierKey;
internal static ConfigEntry<float> ThrowSpeed;
internal static ConfigEntry<float> HeldForceMultiplier;
internal static ConfigEntry<float> MessageSeconds;
internal static ConfigEntry<string> ThrownMessage;
internal static ConfigEntry<string> NothingMessage;
public override void Load()
{
//IL_019d: Unknown result type (might be due to invalid IL or missing references)
//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
//IL_01cb: Expected O, but got Unknown
//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
//IL_01e9: Expected O, but got Unknown
Logger = ((BasePlugin)this).Log;
Texts.SelfCheck();
Enabled = ((BasePlugin)this).Config.Bind<bool>("General", "Enabled", true, "True = the throw key throws what you hold. False = the key does nothing.");
ThrowKey = ((BasePlugin)this).Config.Bind<KeyCode>("Throw", "ThrowKey", (KeyCode)103, "Key that throws what you hold in your hands. Default G (with Alt, see ModifierKey).");
ModifierKey = ((BasePlugin)this).Config.Bind<KeyCode>("Throw", "ModifierKey", (KeyCode)308, "Key to hold together with ThrowKey. Default LeftAlt (Alt+G). None = ThrowKey alone.");
ThrowSpeed = ((BasePlugin)this).Config.Bind<float>("Throw", "ThrowSpeed", 12f, "Speed of an item thrown from the right hand (axe, stone, bottle...), in metres per second, where you look. Default 12. Advised: 5 to 25. 0 = dropped at your feet, as the game drops it.");
HeldForceMultiplier = ((BasePlugin)this).Config.Bind<float>("Throw", "CarriedForceMultiplier", 2f, "Logs, planks and stones carried in your arms: how hard they are thrown, times the game's own drop push. Default 2. Advised: 1 to 4. 1 or less than 0 = the game's drop.");
WholeStack = ((BasePlugin)this).Config.Bind<bool>("Throw", "ThrowWholeCarriedStack", false, "True = one press throws everything carried in your arms (all the logs, planks or stones). False = one item per press. Default false. An item in the right hand is always thrown alone.");
EquipPrevious = ((BasePlugin)this).Config.Bind<bool>("Throw", "EquipPreviousItem", true, "True = after throwing the item in your right hand, the item you held before comes back to your hand, as when the game drops it. False = empty hand. Default true.");
ThrownMessage = ((BasePlugin)this).Config.Bind<string>("Texts", "ThrownMessage", "", "On-screen message after a throw; {0} = how many items. Empty = automatic, in the game's language.");
NothingMessage = ((BasePlugin)this).Config.Bind<string>("Texts", "NothingToThrowMessage", "", "On-screen message when the key is pressed with nothing to throw. Empty = automatic, in the game's language.");
MessageSeconds = ((BasePlugin)this).Config.Bind<float>("Texts", "MessageSeconds", 2f, "Seconds the on-screen message stays. Default 2. Advised: 1 to 6. 0 or less = no message.");
FullLogging = ((BasePlugin)this).Config.Bind<bool>("Debug", "FullLogging", false, "True = the BepInEx log gets every step useful to diagnose a problem (what was held, the game's drop forces, the speed given to the item). False = only loading, version, one line per throw and errors.");
ModLog.Init(Logger, FullLogging);
new Harmony("aznan.sotf.throwanything").PatchAll(typeof(Thrower).Assembly);
ClassInjector.RegisterTypeInIl2Cpp<KeyWatcher>();
GameObject val = new GameObject("ThrowAnything");
Object.DontDestroyOnLoad((Object)val);
((Object)val).hideFlags = (HideFlags)61;
val.AddComponent<KeyWatcher>();
ManualLogSource logger = Logger;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(22, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("ThrowAnything ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("0.1.3");
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" loaded.");
}
logger.LogInfo(val2);
}
}
}
namespace ThrowAnything.Patches
{
internal static class Thrower
{
[HarmonyPatch(typeof(ItemUtils), "CalculateDropPositionAndRotation")]
private static class AimVelocity
{
private static void Postfix(ref Vector3 mpVelocity)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
if (_throwingHand)
{
mpVelocity = _velocity;
}
}
}
[HarmonyPatch(typeof(PlayerInventory), "DropItemInternal")]
private static class LaunchSpawned
{
private static void Postfix(ref GameObject resultingItem)
{
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
if (_throwingHand)
{
Rigidbody val = (((Object)(object)resultingItem == (Object)null) ? null : resultingItem.GetComponentInChildren<Rigidbody>());
if ((Object)(object)val == (Object)null)
{
ModLog.Trace("Throw: no local pickup to push (guest: the host spawns it with the velocity sent).");
return;
}
val.isKinematic = false;
val.velocity = _velocity;
ModLog.Trace($"Throw: pickup {((Object)resultingItem).name} pushed at {((Vector3)(ref _velocity)).magnitude:0.0} m/s.");
}
}
}
[HarmonyPatch(typeof(HeldOnlyItemController), "SpawnHeldItemDrop")]
private static class StrongerHeldDrop
{
private static void Prefix(HeldOnlyItemController __instance, out (bool on, float force, float up) __state)
{
__state = default((bool, float, float));
if (_pendingHeld <= 0)
{
return;
}
if (Time.time > _pendingUntil)
{
ModLog.Trace($"Throw: {_pendingHeld} carried item(s) never spawned by the game within {3f} s: this drop keeps the game's push.");
_pendingHeld = 0;
return;
}
_pendingHeld--;
float value = Plugin.HeldForceMultiplier.Value;
if (value <= 0f)
{
ModLog.Trace("Throw: carried item dropped with the game's push (CarriedForceMultiplier is 0 or less).");
return;
}
__state = (on: true, force: __instance._logDropForce, up: __instance._logDropUpForce);
__instance._logDropForce *= value;
__instance._logDropUpForce *= value;
ModLog.Trace($"Throw: carried item pushed x{value}: force {__state.force:0.0} -> {__instance._logDropForce:0.0}, up {__state.up:0.0} -> {__instance._logDropUpForce:0.0}.");
}
private static void Postfix(HeldOnlyItemController __instance, (bool on, float force, float up) __state)
{
if (__state.on)
{
__instance._logDropForce = __state.force;
__instance._logDropUpForce = __state.up;
}
}
}
private static bool _throwingHand;
private static int _pendingHeld;
private static float _pendingUntil;
private static Vector3 _velocity;
internal static void Throw()
{
//IL_0196: Unknown result type (might be due to invalid IL or missing references)
//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
//IL_0257: Unknown result type (might be due to invalid IL or missing references)
//IL_025e: Expected O, but got Unknown
//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
//IL_01f0: Expected O, but got Unknown
PlayerInventory inventory = LocalPlayer.Inventory;
if ((Object)(object)inventory == (Object)null || !LocalPlayer.IsInWorld)
{
ModLog.Trace("Throw key: " + (((Object)(object)inventory == (Object)null) ? "not in a game" : "not in the plain world view (backpack, menu, sleep)") + ": nothing thrown.");
return;
}
IHeldOnlyItemController heldOnlyItemController = inventory.HeldOnlyItemController;
HeldOnlyItemController val = ((heldOnlyItemController != null) ? ((Il2CppObjectBase)heldOnlyItemController).TryCast<HeldOnlyItemController>() : null);
int num = 0;
string text = "";
bool flag = default(bool);
if ((Object)(object)val != (Object)null && val._heldCount > 0)
{
int num2 = (_pendingHeld = ((!Plugin.WholeStack.Value) ? 1 : val._heldCount));
_pendingUntil = Time.time + 3f;
ModLog.Trace($"Throw: {num2} of {val._heldCount} carried item(s) id {val._heldItemId}, game forces {val._logDropForce:0.0} / up {val._logDropUpForce:0.0}.");
if (Plugin.WholeStack.Value)
{
val.DropAll();
}
else
{
val.PutDown(false, true, true, (GameObject)null, -1, -1f);
}
num = num2;
}
else if (!inventory.IsRightHandEmpty() && !inventory.BlockDrop)
{
ItemInstance rightHandItem = inventory.RightHandItem;
_velocity = LocalPlayer.MainCamTr.forward * Plugin.ThrowSpeed.Value;
_throwingHand = true;
try
{
inventory.DropRightHandItem(Plugin.EquipPrevious.Value);
}
finally
{
_throwingHand = false;
}
num = ((inventory.RightHandItem != rightHandItem) ? 1 : 0);
if (num == 0)
{
ManualLogSource logger = Plugin.Logger;
BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(62, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Throw: the game kept item ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int?>((rightHandItem != null) ? new int?(rightHandItem._itemID) : ((int?)null));
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" in the hand (it cannot be dropped).");
}
logger.LogWarning(val2);
}
}
else
{
text = (inventory.IsRightHandEmpty() ? ": nothing carried and nothing in the right hand" : ": the game blocks dropping right now");
}
ManualLogSource logger2 = Plugin.Logger;
BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(23, 3, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Throw: ");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(num);
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" item(s) thrown");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(text);
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(BoltNetwork.isClient ? " (multiplayer guest: sent to the host as the game's own drop)" : "");
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(".");
}
logger2.LogInfo(val3);
Show(num);
}
private static void Show(int thrown)
{
//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
//IL_00c2: Expected O, but got Unknown
if (Plugin.MessageSeconds.Value <= 0f)
{
ModLog.Trace("Throw: no on-screen message (Texts/MessageSeconds is 0 or less).");
return;
}
string text = ((thrown > 0) ? Plugin.ThrownMessage.Value : Plugin.NothingMessage.Value);
if (string.IsNullOrEmpty(text))
{
Locale selectedLocale = LocalizationSettings.SelectedLocale;
text = Texts.Get((selectedLocale != null) ? selectedLocale.Identifier.Code : null, (thrown > 0) ? "Thrown" : "NothingHeld");
}
HudGui instance = HudGui._instance;
if ((Object)(object)instance == (Object)null)
{
ModLog.Once("nohud", "Throw: the game's message line (HudGui) was not found: no on-screen message.", (LogLevel)4);
return;
}
try
{
instance.DisplayGeneralMessage(text.Replace("{0}", thrown.ToString()), Plugin.MessageSeconds.Value, (ItemUiData)null);
}
catch (Exception ex)
{
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(33, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Throw: game message line failed: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
}
logger.LogWarning(val);
}
}
}
public class KeyWatcher : MonoBehaviour
{
public KeyWatcher(IntPtr ptr)
: base(ptr)
{
}
private void Update()
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
//IL_00ca: Expected O, but got Unknown
//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_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
if (!Input.GetKeyDown(Plugin.ThrowKey.Value))
{
return;
}
KeyCode value = Plugin.ModifierKey.Value;
if ((int)value != 0 && !Input.GetKey(value))
{
ModLog.Trace($"{Plugin.ThrowKey.Value} pressed without {value}: not a throw.");
return;
}
if (!Plugin.Enabled.Value)
{
ModLog.Trace($"{Plugin.ThrowKey.Value} pressed: mod turned off (General/Enabled), nothing thrown.");
return;
}
try
{
Thrower.Throw();
}
catch (Exception ex)
{
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(14, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Throw failed: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
}
logger.LogError(val);
}
}
}
}
namespace ThrowAnything.Logic
{
public static class Texts
{
public const string Thrown = "Thrown";
public const string NothingHeld = "NothingHeld";
private static readonly Dictionary<string, Dictionary<string, string>> ByLanguage = new Dictionary<string, Dictionary<string, string>>
{
["en"] = new Dictionary<string, string>
{
["Thrown"] = "{0} item(s) thrown",
["NothingHeld"] = "Nothing in your hands to throw"
},
["fr"] = new Dictionary<string, string>
{
["Thrown"] = "{0} objet(s) jeté(s)",
["NothingHeld"] = "Rien en main à jeter"
},
["zh"] = new Dictionary<string, string>
{
["Thrown"] = "已投掷 {0} 件物品",
["NothingHeld"] = "手中没有可投掷的物品"
},
["zh-hant"] = new Dictionary<string, string>
{
["Thrown"] = "已投擲 {0} 件物品",
["NothingHeld"] = "手中沒有可投擲的物品"
},
["cs"] = new Dictionary<string, string>
{
["Thrown"] = "Vyhozeno předmětů: {0}",
["NothingHeld"] = "V rukou nemáte nic k hození"
},
["fi"] = new Dictionary<string, string>
{
["Thrown"] = "{0} esine(ttä) heitetty",
["NothingHeld"] = "Käsissäsi ei ole mitään heitettävää"
},
["de"] = new Dictionary<string, string>
{
["Thrown"] = "{0} Gegenstand/Gegenstände geworfen",
["NothingHeld"] = "Nichts zum Werfen in den Händen"
},
["it"] = new Dictionary<string, string>
{
["Thrown"] = "{0} oggetto/i lanciato/i",
["NothingHeld"] = "Niente da lanciare tra le mani"
},
["ja"] = new Dictionary<string, string>
{
["Thrown"] = "アイテムを {0} 個投げた",
["NothingHeld"] = "投げるものを手に持っていません"
},
["ko"] = new Dictionary<string, string>
{
["Thrown"] = "아이템 {0}개 투척됨",
["NothingHeld"] = "손에 던질 물건이 없습니다"
},
["pl"] = new Dictionary<string, string>
{
["Thrown"] = "Rzucono przedmiotów: {0}",
["NothingHeld"] = "Nie masz w dłoniach nic do rzucenia"
},
["pt"] = new Dictionary<string, string>
{
["Thrown"] = "{0} item(ns) arremessado(s)",
["NothingHeld"] = "Nada para arremessar nas mãos"
},
["ru"] = new Dictionary<string, string>
{
["Thrown"] = "Брошено предметов: {0}",
["NothingHeld"] = "В руках нет ничего подходящего для броска"
},
["es"] = new Dictionary<string, string>
{
["Thrown"] = "{0} objeto(s) lanzado(s)",
["NothingHeld"] = "No tienes nada que lanzar en las manos"
},
["sv"] = new Dictionary<string, string>
{
["Thrown"] = "{0} föremål kastat/kastade",
["NothingHeld"] = "Inget i händerna att kasta"
},
["tr"] = new Dictionary<string, string>
{
["Thrown"] = "{0} eşya fırlatıldı",
["NothingHeld"] = "Ellerinde fırlatacak bir şey yok"
}
};
public static string Get(string localeCode, string key)
{
string text = (localeCode ?? "en").ToLowerInvariant();
string key2 = (ByLanguage.ContainsKey(text) ? text : text.Split('-')[0]);
if (!ByLanguage.TryGetValue(key2, out var value) || !value.TryGetValue(key, out var value2))
{
return ByLanguage["en"][key];
}
return value2;
}
public static void SelfCheck()
{
if (Get("fr-FR", "Thrown") != ByLanguage["fr"]["Thrown"] || Get("xx", "NothingHeld") != ByLanguage["en"]["NothingHeld"] || Get(null, "Thrown") != ByLanguage["en"]["Thrown"])
{
throw new InvalidOperationException("Texts lookup is wrong.");
}
}
}
}