using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using ComputerysModdingUtilities;
using FishNet.Object;
using HarmonyLib;
using MinimalViewmodelsReborn;
using MinimalViewmodelsReborn.Patches;
using ModMenu.Api;
using ModMenu.Behaviours.OptionList.Dummies;
using ModMenu.Behaviours.OptionList.ValueControllers;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ViewmodelTweaks")]
[assembly: AssemblyDescription("Its own viewmodel position, FOV and arms setting for any weapon you pick, on top of Minimal Viewmodels Reborn. Dorsth was here.")]
[assembly: StraftatMod(true)]
[assembly: AssemblyVersion("1.1.2.0")]
namespace ViewmodelTweaks;
public enum Weapon
{
None,
Katana,
Flamberge,
AAA12,
AK_K,
AR15,
Bayshore,
BeamLoad,
Bender,
BlankState,
Bukanee,
Crisis,
DF_Torrent,
DualLauncher,
Elephant,
FG42,
Gamma,
GammaGen2,
GlaiveGun,
Glock,
Gun,
Gust,
HandCanon,
Havoc,
Hill_H15,
HK_Caws,
HK_G11,
Impetus,
Kanye,
Keso,
Kusma,
M2000,
Mac10,
Minigun,
Mortini,
Oklahoma,
Phoenix,
Prophet,
QCW05,
Revolver,
RocketLauncher,
SawedOff,
Serac,
Shotgun,
Silenzzio,
SmithCarbine,
SMG,
Tromblonj,
Warden,
Webley,
Yangtse
}
internal sealed class Slot
{
internal ConfigEntry<Weapon> Weapon;
internal ConfigEntry<float> Fov;
internal ConfigEntry<float> X;
internal ConfigEntry<float> Y;
internal ConfigEntry<float> Z;
internal ConfigEntry<bool> NoArms;
internal bool Used => Weapon.Value != ViewmodelTweaks.Weapon.None;
internal IEnumerable<ConfigEntryBase> Entries => (IEnumerable<ConfigEntryBase>)(object)new ConfigEntryBase[6]
{
(ConfigEntryBase)Weapon,
(ConfigEntryBase)Fov,
(ConfigEntryBase)X,
(ConfigEntryBase)Y,
(ConfigEntryBase)Z,
(ConfigEntryBase)NoArms
};
}
[BepInPlugin("dorsth.straftat.viewmodeltweaks", "ViewmodelTweaks", "1.1.2")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class ViewmodelTweaksPlugin : BaseUnityPlugin
{
public const string Guid = "dorsth.straftat.viewmodeltweaks";
public const string Name = "ViewmodelTweaks";
public const string Version = "1.1.2";
internal const int MaxSlots = 10;
internal static ManualLogSource Log;
internal static ConfigFile Cfg;
internal static readonly List<Slot> Slots = new List<Slot>();
private static readonly FieldInfo ArmsField = AccessTools.Field(typeof(ViewmodelModifier), "m_armRenderers");
private static bool _dirty = true;
private static Slot _shown;
private static PlayerPickup _me;
private static float _lookAt;
private static GameObject _lastObj;
private static Slot _lastSlot;
private static bool _lastDirty = true;
private void Awake()
{
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
//IL_00b4: Expected O, but got Unknown
//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ee: Expected O, but got Unknown
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
//IL_0128: Expected O, but got Unknown
//IL_0158: Unknown result type (might be due to invalid IL or missing references)
//IL_0162: Expected O, but got Unknown
//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
//IL_01e6: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Cfg = ((BaseUnityPlugin)this).Config;
FromSwordStance();
NoSword();
for (int i = 1; i <= 10; i++)
{
string text = "Weapon " + i;
Slots.Add(new Slot
{
Weapon = ((BaseUnityPlugin)this).Config.Bind<Weapon>(text, "Weapon", Weapon.None, "The weapon these settings are for. None: not used."),
NoArms = ((BaseUnityPlugin)this).Config.Bind<bool>(text, "Invisible Arms", false, "Hides your arms while holding it."),
Fov = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Viewmodel FOV", 75f, new ConfigDescription("FOV of the viewmodel while holding it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(30f, 120f), Array.Empty<object>())),
X = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Viewmodel X Offset", 0f, new ConfigDescription("Left (negative) or right (positive).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-5f, 5f), Array.Empty<object>())),
Y = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Viewmodel Y Offset", -0.1f, new ConfigDescription("Down (negative) or up (positive).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-5f, 5f), Array.Empty<object>())),
Z = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Viewmodel Z Offset", 0f, new ConfigDescription("Back (negative) or forward (positive).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-5f, 5f), Array.Empty<object>()))
});
}
FromOneVersion();
((BaseUnityPlugin)this).Config.SettingChanged += delegate
{
_dirty = true;
};
try
{
new Harmony("dorsth.straftat.viewmodeltweaks").Patch((MethodBase)AccessTools.Method(typeof(ViewmodelModifier), "Apply", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(ViewmodelTweaksPlugin), "AppliedPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
catch (Exception ex)
{
Log.LogWarning((object)("Couldn't follow Minimal Viewmodels' changes: " + ex.Message));
}
if (Chainloader.PluginInfos.ContainsKey("kestrel.straftat.modmenu"))
{
try
{
Menu.Register();
}
catch (Exception ex2)
{
Log.LogWarning((object)("Mod Menu page left as a plain list: " + ex2.Message));
}
}
Log.LogMessage((object)"Dorsth was here");
((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
}
private void FromSwordStance()
{
try
{
string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Config.ConfigFilePath), "dorsth.straftat.swordstance.cfg");
if (!File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath) && File.Exists(text))
{
File.Copy(text, ((BaseUnityPlugin)this).Config.ConfigFilePath);
((BaseUnityPlugin)this).Config.Reload();
Log.LogInfo((object)"Settings taken over from SwordStance.");
}
}
catch (Exception ex)
{
Log.LogWarning((object)("Couldn't take over SwordStance's settings: " + ex.Message));
}
}
private void NoSword()
{
try
{
string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath;
if (!File.Exists(configFilePath))
{
return;
}
string[] array = File.ReadAllLines(configFilePath);
bool flag = array.Any((string l) => l.Trim() == "Weapon = Flamberge");
bool flag2 = false;
for (int num = 0; num < array.Length; num++)
{
if (!(array[num].Trim() != "Weapon = Sword"))
{
array[num] = (flag ? "Weapon = None" : "Weapon = Flamberge");
flag = true;
flag2 = true;
}
}
if (flag2)
{
File.WriteAllLines(configFilePath, array);
((BaseUnityPlugin)this).Config.Reload();
Log.LogInfo((object)"Sword is the flamberge now.");
}
}
catch (Exception ex)
{
Log.LogWarning((object)("Couldn't move Sword over to the flamberge: " + ex.Message));
}
}
private void FromOneVersion()
{
ConfigEntry<string> val = ((BaseUnityPlugin)this).Config.Bind<string>("Sword Stance", "Weapons", "", "Not used since 1.1.0: weapons are added one by one now.");
if (string.IsNullOrWhiteSpace(val.Value) || Slots.Any((Slot x) => x.Used))
{
Hide((ConfigEntryBase)val);
return;
}
ConfigEntry<float> val2 = ((BaseUnityPlugin)this).Config.Bind<float>("Sword Stance", "Viewmodel FOV", 75f, "Not used since 1.1.0.");
ConfigEntry<float> val3 = ((BaseUnityPlugin)this).Config.Bind<float>("Sword Stance", "Viewmodel X Offset", 0f, "Not used since 1.1.0.");
ConfigEntry<float> val4 = ((BaseUnityPlugin)this).Config.Bind<float>("Sword Stance", "Viewmodel Y Offset", -0.1f, "Not used since 1.1.0.");
ConfigEntry<float> val5 = ((BaseUnityPlugin)this).Config.Bind<float>("Sword Stance", "Viewmodel Z Offset", 0f, "Not used since 1.1.0.");
ConfigEntry<bool> val6 = ((BaseUnityPlugin)this).Config.Bind<bool>("Sword Stance", "Invisible Arms", false, "Not used since 1.1.0.");
int num = 0;
string[] array = val.Value.Split(',');
foreach (string text in array)
{
Weapon w = Weapons.FromName(text.Trim());
if (w != Weapon.None && num < Slots.Count && !Slots.Any((Slot s) => s.Weapon.Value == w))
{
Slot slot = Slots[num++];
slot.Weapon.Value = w;
slot.Fov.Value = val2.Value;
slot.X.Value = val3.Value;
slot.Y.Value = val4.Value;
slot.Z.Value = val5.Value;
slot.NoArms.Value = val6.Value;
}
}
val.Value = "";
Hide((ConfigEntryBase)val, (ConfigEntryBase)val2, (ConfigEntryBase)val3, (ConfigEntryBase)val4, (ConfigEntryBase)val5, (ConfigEntryBase)val6);
}
private static void Hide(params ConfigEntryBase[] entries)
{
if (Chainloader.PluginInfos.ContainsKey("kestrel.straftat.modmenu"))
{
Menu.HideOld(entries);
}
}
private static void AppliedPostfix()
{
_dirty = true;
_shown = null;
}
private void LateUpdate()
{
try
{
Slot slot = Held();
if (slot == _shown && !_dirty)
{
return;
}
_dirty = false;
if (slot != null)
{
Show(slot);
}
else if (_shown != null)
{
_shown = null;
ViewmodelModifier.Apply();
_dirty = false;
}
}
catch (Exception ex)
{
Log.LogWarning((object)ex.Message);
_dirty = false;
}
Menu.Keep();
}
private static void Show(Slot s)
{
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
Camera weaponCam = ViewmodelModifier.WeaponCam;
if ((Object)(object)weaponCam == (Object)null || Plugin.InvisibleViewmodels.Value)
{
return;
}
((Component)weaponCam).transform.localPosition = -new Vector3(s.X.Value, s.Y.Value, s.Z.Value);
Matrix4x4 val = Matrix4x4.Perspective(s.Fov.Value, (float)Screen.width / (float)Screen.height, 0.1f, 100f);
if (Plugin.MirrorViewmodel.Value)
{
val *= Matrix4x4.Scale(new Vector3(-1f, 1f, 1f));
}
weaponCam.projectionMatrix = val;
if (ArmsField != null && ArmsField.GetValue(null) is SkinnedMeshRenderer[] array)
{
SkinnedMeshRenderer[] array2 = array;
foreach (SkinnedMeshRenderer val2 in array2)
{
if ((Object)(object)val2 != (Object)null)
{
((Renderer)val2).enabled = !s.NoArms.Value;
}
}
}
_shown = s;
}
private static Slot Held()
{
if ((Object)(object)_me == (Object)null)
{
if (Time.unscaledTime < _lookAt)
{
return null;
}
_lookAt = Time.unscaledTime + 1f;
PlayerPickup[] array = Object.FindObjectsOfType<PlayerPickup>();
foreach (PlayerPickup val in array)
{
if ((Object)(object)val != (Object)null && ((NetworkBehaviour)val).IsOwner)
{
_me = val;
break;
}
}
if ((Object)(object)_me == (Object)null)
{
return null;
}
}
return For(_me.objInHand) ?? For(_me.objInLeftHand);
}
private static Slot For(GameObject held)
{
if ((Object)(object)held == (Object)null)
{
return null;
}
if ((Object)(object)held == (Object)(object)_lastObj && !_lastDirty)
{
return _lastSlot;
}
Weapon w = Weapons.Of(held);
Slot? obj = ((w == Weapon.None) ? null : Slots.FirstOrDefault((Slot s) => s.Weapon.Value == w));
_lastObj = held;
_lastSlot = obj;
_lastDirty = false;
return obj;
}
internal static void Changed()
{
_dirty = true;
_lastDirty = true;
}
}
internal static class Weapons
{
private static readonly Dictionary<string, Weapon> Aliases = new Dictionary<string, Weapon>(StringComparer.OrdinalIgnoreCase)
{
{
"sword",
Weapon.Flamberge
},
{
"pistol",
Weapon.Gun
},
{
"ak",
Weapon.AK_K
},
{
"ak-k",
Weapon.AK_K
},
{
"ar",
Weapon.AR15
},
{
"torrent",
Weapon.DF_Torrent
},
{
"golden impetus",
Weapon.Impetus
},
{
"smith carbine",
Weapon.SmithCarbine
},
{
"sawed off",
Weapon.SawedOff
},
{
"beam load",
Weapon.BeamLoad
},
{
"hand canon",
Weapon.HandCanon
},
{
"blank state",
Weapon.BlankState
},
{
"dual launcher",
Weapon.DualLauncher
},
{
"glaive gun",
Weapon.GlaiveGun
},
{
"rocket launcher",
Weapon.RocketLauncher
},
{
"gamma gen 2",
Weapon.GammaGen2
},
{
"hk caws",
Weapon.HK_Caws
},
{
"hill h15",
Weapon.Hill_H15
}
};
internal static string Label(Weapon w)
{
return w switch
{
Weapon.Gun => "pistol",
Weapon.AK_K => "AK-K",
_ => w.ToString().Replace('_', ' '),
};
}
internal static Weapon FromName(string n)
{
if (string.IsNullOrEmpty(n))
{
return Weapon.None;
}
n = n.Replace("(Clone)", "").Trim();
if (Aliases.TryGetValue(n, out var value))
{
return value;
}
string b = n.Replace("-", "_").Replace(" ", "");
foreach (Weapon value2 in Enum.GetValues(typeof(Weapon)))
{
if (value2 != Weapon.None && string.Equals(value2.ToString(), b, StringComparison.OrdinalIgnoreCase))
{
return value2;
}
}
return Weapon.None;
}
internal static Weapon Of(GameObject held)
{
Weapon weapon = FromName(((Object)held).name);
if (weapon != Weapon.None)
{
return weapon;
}
ItemBehaviour component = held.GetComponent<ItemBehaviour>();
if (!((Object)(object)component != (Object)null))
{
return Weapon.None;
}
return FromName(component.weaponName);
}
}
internal static class Menu
{
internal static readonly List<KeyValuePair<Slot, List<GameObject>>> Rows = new List<KeyValuePair<Slot, List<GameObject>>>();
internal static GameObject AddRow;
internal static void Register()
{
Page.Register();
}
internal static void HideOld(ConfigEntryBase[] entries)
{
Page.HideOld(entries);
}
internal static void Keep()
{
if (Rows.Count == 0)
{
return;
}
GameObject val = Rows[0].Value.FirstOrDefault();
if ((Object)(object)val == (Object)null || !Object.op_Implicit((Object)(object)val.transform.parent) || !((Component)val.transform.parent).gameObject.activeInHierarchy)
{
return;
}
foreach (KeyValuePair<Slot, List<GameObject>> row in Rows)
{
if (row.Key.Used)
{
continue;
}
foreach (GameObject item in row.Value)
{
if ((Object)(object)item != (Object)null && item.activeSelf)
{
item.SetActive(false);
}
}
}
if ((Object)(object)AddRow != (Object)null && AddRow.activeSelf == ViewmodelTweaksPlugin.Slots.All((Slot s) => s.Used))
{
AddRow.SetActive(!AddRow.activeSelf);
}
}
internal static void Refresh()
{
foreach (KeyValuePair<Slot, List<GameObject>> row in Rows)
{
foreach (GameObject item in row.Value)
{
if ((Object)(object)item != (Object)null && item.activeSelf != row.Key.Used)
{
item.SetActive(row.Key.Used);
}
}
}
if ((Object)(object)AddRow != (Object)null)
{
AddRow.SetActive(!ViewmodelTweaksPlugin.Slots.All((Slot s) => s.Used));
}
}
}
internal static class Page
{
private static FieldInfo info;
private static FieldInfo guid;
private static readonly Dictionary<Slot, Action> Adders = new Dictionary<Slot, Action>();
internal static void Register()
{
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: Expected O, but got Unknown
ModMenuCustomisation.HideEntries(ViewmodelTweaksPlugin.Slots.SelectMany((Slot s) => s.Entries));
ModMenuCustomisation.SetPluginDescription("Its own viewmodel FOV, position and arms for any weapon you add. Every other weapon keeps Minimal Viewmodels' settings.");
ModMenuCustomisation.RegisterContentBuilder((Action<OptionListContext>)Build);
Type type = AccessTools.TypeByName("ModMenu.Mods.Mod");
info = AccessTools.Field(type, "info");
guid = AccessTools.Field(info.FieldType, "guid");
new Harmony("dorsth.straftat.viewmodeltweaks.menu").Patch((MethodBase)AccessTools.PropertyGetter(type, "HasAnyConfigs"), (HarmonyMethod)null, new HarmonyMethod(typeof(Page), "HasOptions", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
private static void HasOptions(object __instance, ref bool __result)
{
if (!__result && (string)guid.GetValue(info.GetValue(__instance)) == "dorsth.straftat.viewmodeltweaks")
{
__result = true;
}
}
internal static void HideOld(ConfigEntryBase[] entries)
{
ModMenuCustomisation.HideEntries((IEnumerable<ConfigEntryBase>)entries);
}
private static void Build(OptionListContext c)
{
Menu.Rows.Clear();
foreach (Slot slot3 in ViewmodelTweaksPlugin.Slots)
{
Slot slot = slot3;
List<GameObject> list = new List<GameObject>();
List<BoxedValueController> refresh = new List<BoxedValueController>();
TextDummy head = c.AppendHeader(Weapons.Label(slot.Weapon.Value));
list.Add(((Component)head).gameObject);
DropdownValueController val = c.AppendDropdown<Weapon>("Weapon", (Func<Weapon>)(() => slot.Weapon.Value), (Action<Weapon>)delegate(Weapon v)
{
slot.Weapon.Value = v;
if (v != Weapon.None)
{
head.Text = Weapons.Label(v);
}
ViewmodelTweaksPlugin.Changed();
Menu.Refresh();
});
list.Add(((Component)val).gameObject);
refresh.Add((BoxedValueController)(object)val);
refresh.Add(Slider(c, list, "Viewmodel FOV", slot.Fov, 30f, 120f));
refresh.Add(Slider(c, list, "Viewmodel X Offset", slot.X, -5f, 5f));
refresh.Add(Slider(c, list, "Viewmodel Y Offset", slot.Y, -5f, 5f));
refresh.Add(Slider(c, list, "Viewmodel Z Offset", slot.Z, -5f, 5f));
BoolValueController val2 = c.AppendCheckbox("Invisible Arms", (Func<bool>)(() => slot.NoArms.Value), (Action<bool>)delegate(bool v)
{
slot.NoArms.Value = v;
ViewmodelTweaksPlugin.Changed();
});
list.Add(((Component)val2).gameObject);
refresh.Add((BoxedValueController)(object)val2);
ButtonDummy val3 = c.AppendButton("", "remove", (Action)delegate
{
slot.Weapon.Value = Weapon.None;
ViewmodelTweaksPlugin.Changed();
Menu.Refresh();
});
list.Add(((Component)val3).gameObject);
Menu.Rows.Add(new KeyValuePair<Slot, List<GameObject>>(slot, list));
Adders[slot] = delegate
{
Weapon weapon = Enum.GetValues(typeof(Weapon)).Cast<Weapon>().FirstOrDefault((Weapon w) => w != Weapon.None && ViewmodelTweaksPlugin.Slots.All((Slot o) => o.Weapon.Value != w));
if (weapon == Weapon.None)
{
return;
}
ConfigEntryBase[] array = (ConfigEntryBase[])(object)new ConfigEntryBase[5]
{
(ConfigEntryBase)slot.Fov,
(ConfigEntryBase)slot.X,
(ConfigEntryBase)slot.Y,
(ConfigEntryBase)slot.Z,
(ConfigEntryBase)slot.NoArms
};
foreach (ConfigEntryBase obj in array)
{
obj.BoxedValue = obj.DefaultValue;
}
slot.Weapon.Value = weapon;
head.Text = Weapons.Label(weapon);
foreach (BoxedValueController item in refresh)
{
item.UpdateAppearance();
}
};
}
Menu.AddRow = ((Component)c.AppendButton("Add a weapon", "+", (Action)delegate
{
Slot slot2 = ViewmodelTweaksPlugin.Slots.FirstOrDefault((Slot s) => !s.Used);
if (slot2 != null)
{
Adders[slot2]();
ViewmodelTweaksPlugin.Changed();
Menu.Refresh();
}
})).gameObject;
Menu.Refresh();
}
private static BoxedValueController Slider(OptionListContext c, List<GameObject> rows, string name, ConfigEntry<float> entry, float min, float max)
{
NumericSliderValueController val = c.AppendNumericSlider<float>(name, (Func<float>)(() => entry.Value), (Action<float>)delegate(float v)
{
entry.Value = v;
ViewmodelTweaksPlugin.Changed();
}, min, max);
rows.Add(((Component)val).gameObject);
return (BoxedValueController)(object)val;
}
}