Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of MoreCrossbowsFIX v1.2.14
MoreCrossbows.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Common; using HarmonyLib; using Jotunn; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyFileVersion("1.2.11")] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: ComVisible(false)] [assembly: AssemblyTrademark("")] [assembly: AssemblyCopyright("Copyright probablykory © 2024")] [assembly: AssemblyProduct("MoreCrossbows")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyDescription("https://thunderstore.io/c/valheim/p/probablykory/MoreCrossbows/")] [assembly: AssemblyTitle("MoreCrossbows")] [assembly: AssemblyCompany("probablykory")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.2.11.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Common { internal class AcceptableValueConfigNote : AcceptableValueBase { public virtual string Note { get; } public AcceptableValueConfigNote(string note) : base(typeof(string)) { if (string.IsNullOrEmpty(note)) { throw new ArgumentException("A string with atleast 1 character is needed", "Note"); } Note = note; } public override object Clamp(object value) { return value; } public override bool IsValid(object value) { return !string.IsNullOrEmpty(value as string); } public override string ToDescriptionString() { return "# Note: " + Note; } } internal static class ConfigHelper { public static ConfigurationManagerAttributes GetAdminOnlyFlag() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown return new ConfigurationManagerAttributes { IsAdminOnly = true }; } public static ConfigurationManagerAttributes GetTags(Action<ConfigEntryBase> action) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown return new ConfigurationManagerAttributes { CustomDrawer = action }; } public static ConfigurationManagerAttributes GetTags() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown return new ConfigurationManagerAttributes(); } public static ConfigEntry<T> Config<T>(this IPlugin instance, string group, string name, T value, ConfigDescription description) { return instance.Config.Bind<T>(group, name, value, description); } public static ConfigEntry<T> Config<T>(this IPlugin instance, string group, string name, T value, string description) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown return instance.Config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { GetAdminOnlyFlag() })); } } internal class ConfigWatcher { private BaseUnityPlugin configurationManager; private IPlugin plugin; public ConfigWatcher(IPlugin plugin) { if (plugin == null) { throw new ArgumentNullException("plugin"); } this.plugin = plugin; CheckForConfigManager(); } private void InitializeWatcher() { string fileName = Path.GetFileName(plugin.Config.ConfigFilePath); new Watcher(Path.GetDirectoryName(plugin.Config.ConfigFilePath), fileName).FileChanged += OnFileChanged; Get.Plugin.LogDebugOnly("File system watcher initialized."); } private void CheckForConfigManager() { PluginInfo value; if (GUIManager.IsHeadless()) { InitializeWatcher(); } else if (Chainloader.PluginInfos.TryGetValue("com.bepis.bepinex.configurationmanager", out value) && Object.op_Implicit((Object)(object)value.Instance)) { configurationManager = value.Instance; Get.Plugin.LogDebugOnly("Configuration manager found, hooking DisplayingWindowChanged"); EventInfo eventInfo = ((object)configurationManager).GetType().GetEvent("DisplayingWindowChanged"); if (eventInfo != null) { Action<object, object> action = OnConfigManagerDisplayingWindowChanged; Delegate handler = Delegate.CreateDelegate(eventInfo.EventHandlerType, action.Target, action.Method); eventInfo.AddEventHandler(configurationManager, handler); } } else { InitializeWatcher(); } } private void OnFileChanged(object sender, FileSystemEventArgs e) { string configFilePath = plugin.Config.ConfigFilePath; if (!File.Exists(configFilePath)) { return; } try { plugin.Config.SaveOnConfigSet = false; plugin.Config.Reload(); plugin.Config.SaveOnConfigSet = true; } catch { Get.Plugin.LogError("There was an issue with your " + Path.GetFileName(configFilePath) + " file."); Get.Plugin.LogError("Please check the format and spelling."); } } private void OnConfigManagerDisplayingWindowChanged(object sender, object e) { if (!(bool)((object)configurationManager).GetType().GetProperty("DisplayingWindow").GetValue(configurationManager, null)) { plugin.Config.SaveOnConfigSet = false; plugin.Config.Reload(); plugin.Config.SaveOnConfigSet = true; } } } internal sealed class CustomSyncedValue<T> : CustomSyncedValueBase { public T Value { get { return (T)base.BoxedValue; } set { base.BoxedValue = value; if (base.BoxedValue != null) { SendPackage(); } } } public CustomSyncedValue(string name, T value = default(T)) : base(name, typeof(T), value) { } public void AssignLocalValue(T value) { if (base.IsSourceOfTruth && SynchronizationManager.Instance.PlayerIsAdmin) { Value = value; } else { LocalBaseValue = value; } } } internal class CustomSyncedValueBase { private class Patches { [HarmonyPatch(typeof(ZNet), "Shutdown")] [HarmonyPostfix] private static void ZNet_Shutdown() { if (ZNetExtension.IsClientInstance(ZNet.instance)) { foreach (CustomSyncedValueBase syncedValue in SyncedValues) { syncedValue.OnResetFromServer(); } return; } foreach (CustomSyncedValueBase syncedValue2 in SyncedValues) { syncedValue2.OnServerShutdown(); } } } public readonly string Name; public readonly Type Type; private object boxedValue; public object LocalBaseValue; private CustomRPC customRPC; private static readonly HashSet<CustomSyncedValueBase> SyncedValues = new HashSet<CustomSyncedValueBase>(); private static Harmony harmony = null; public bool IsSourceOfTruth { get; private set; } = true; public object BoxedValue { get { return boxedValue; } set { boxedValue = value; this.ValueChanged?.Invoke(this, value); } } public event Action<object, object> ValueChanged; protected CustomSyncedValueBase(string name, Type type, object initialValue) { //IL_00a4: 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_00ba: Expected O, but got Unknown //IL_00ba: Expected O, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown Name = name; Type = type; SyncedValues.Add(this); if (harmony == null) { harmony = (Harmony)AccessTools.Field(typeof(Main), "Harmony").GetValue(null); harmony.PatchAll(typeof(Patches)); Get.Plugin.LogDebugOnly("Jotunn's harmony instance obtained, CustomSyncedValueBase+Patches applied."); } boxedValue = initialValue; customRPC = NetworkManager.Instance.AddRPC(Name + "_CustomSyncedValue_RPC", new CoroutineHandler(OnServerReceive), new CoroutineHandler(OnClientReceive)); SynchronizationManager.Instance.AddInitialSynchronization(customRPC, (Func<ZPackage>)GetPackage); } public void SendPackage() { if ((Object)(object)ZNet.instance == (Object)null) { Get.Plugin.LogDebugOnly("SendPackage called but am not connected."); } if (!SynchronizationManager.Instance.PlayerIsAdmin) { Get.Plugin.LogDebugOnly("SendPackage called but Player is not admin."); } if ((Object)(object)ZNet.instance != (Object)null && SynchronizationManager.Instance.PlayerIsAdmin) { ZPackage package = GetPackage(); if (ZNetExtension.IsClientInstance(ZNet.instance)) { customRPC.SendPackage(0L, package); return; } List<ZNetPeer> list = (List<ZNetPeer>)(typeof(ZNet).GetField("m_peers", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(ZNet.instance)); customRPC.SendPackage(list, package); } } private ZPackage GetPackage() { return new PackageEntry { key = Name, type = Type, value = boxedValue }.ToPackage(); } private IEnumerator OnServerReceive(long sender, ZPackage package) { Get.Plugin.LogDebugOnly($"Server received RPC: {sender} {package}"); yield return null; ParsedEntries parsedEntries = package.ReadEntries(); if (parsedEntries.Count > 0 && parsedEntries.TryGetValue(Name, out var packageEntry)) { BoxedValue = (LocalBaseValue = packageEntry.value); Get.Plugin.LogDebugOnly($"Set local and boxed: {packageEntry.value}"); List<ZNetPeer> peersList = (List<ZNetPeer>)(typeof(ZNet).GetField("m_peers", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(ZNet.instance)); if (peersList != null) { customRPC.SendPackage(peersList.Where((ZNetPeer x) => x.m_uid != sender).ToList(), package); } } else { OnReceiveError(parsedEntries); } } private IEnumerator OnClientReceive(long sender, ZPackage package) { Get.Plugin.LogDebugOnly($"Client received RPC: {sender} {package}"); yield return null; ParsedEntries parsedEntries = package.ReadEntries(); if (parsedEntries.Count > 0 && parsedEntries.TryGetValue(Name, out var packageEntry)) { IsSourceOfTruth = false; if (LocalBaseValue == null) { LocalBaseValue = BoxedValue; } BoxedValue = packageEntry.value; Get.Plugin.LogDebugOnly($"Set source of truth: {IsSourceOfTruth}, {Environment.NewLine}local: {LocalBaseValue} {Environment.NewLine}boxed: {BoxedValue}"); } else { OnReceiveError(parsedEntries); } } private void OnReceiveError(ParsedEntries entries) { Get.Plugin.LogWarning(Name + "_CustomSyncedValue_RPC recieved package without expected key: " + Name); string text = ""; foreach (KeyValuePair<string, PackageEntry> entry in entries) { string text2 = text; string format = "{0} - {1} - {2} {3}"; object[] array = new object[4] { entry.Key, entry.Value.type, null, null }; int num = 2; array[num] = entry.Value.value?.ToString(); array[3] = Environment.NewLine; text = text2 + string.Format(format, array); } Get.Plugin.LogWarning("Result: " + Environment.NewLine + text); } private void OnResetFromServer() { BoxedValue = LocalBaseValue; IsSourceOfTruth = true; LocalBaseValue = null; } private void OnServerShutdown() { } } internal static class Get { private static IPlugin _plugin; public static IPlugin Plugin { get { if (_plugin != null) { return _plugin; } foreach (PluginInfo value in Chainloader.PluginInfos.Values) { if (value.Instance is IPlugin plugin) { _plugin = plugin; return _plugin; } } return null; } set { _plugin = value; } } } internal class InvalidDeserializationTypeException : Exception { public string expected; public string received; public string field = ""; } internal interface IPlugin { IPlugin Instance { get; } ConfigFile Config { get; } bool Debug { get; } ManualLogSource Logger { get; } } internal static class LoggingExtensions { private static readonly Dictionary<string, ManualLogSource> logSources = new Dictionary<string, ManualLogSource>(); internal static ManualLogSource GetLogger(this IPlugin mod) { if (mod.Debug) { Type declaringType = new StackFrame(2).GetMethod().DeclaringType; if (!logSources.TryGetValue(declaringType.FullName, out var value)) { value = Logger.CreateLogSource(declaringType.FullName); logSources.Add(declaringType.FullName, value); } return value; } return mod.Logger; } public static void LogDebugOnly(this IPlugin mod, object data) { if (mod.Debug) { mod.GetLogger().LogDebug(data); } } public static void LogDebug(this IPlugin mod, object data) { if (mod.Debug) { mod.GetLogger().LogDebug(data); } else { mod.Logger.LogDebug(data); } } public static void LogInfo(this IPlugin mod, object data) { if (mod.Debug) { mod.GetLogger().LogInfo(data); } else { mod.Logger.LogInfo(data); } } public static void LogMessage(this IPlugin mod, object data) { if (mod.Debug) { mod.GetLogger().LogMessage(data); } else { mod.Logger.LogMessage(data); } } public static void LogWarning(this IPlugin mod, object data) { if (mod.Debug) { mod.GetLogger().LogWarning(data); } else { mod.Logger.LogWarning(data); } } public static void LogError(this IPlugin mod, object data) { if (mod.Debug) { mod.GetLogger().LogError(data); } else { mod.Logger.LogError(data); } } public static void LogFatal(this IPlugin mod, object data) { if (mod.Debug) { mod.GetLogger().LogFatal(data); } else { mod.Logger.LogFatal(data); } } } internal class PackageEntry { public string key; public Type type; public object value; } internal static class PackageUtils { public static string GetPackageTypeString(Type type) { return type.AssemblyQualifiedName; } public static void AddValue(this ZPackage package, object value) { Type type = value?.GetType(); if (value is Enum) { value = ((IConvertible)value).ToType(Enum.GetUnderlyingType(value.GetType()), CultureInfo.InvariantCulture); } else { if (value is ICollection collection) { package.Write(collection.Count); { foreach (object item in collection) { package.AddValue(item); } return; } } if (type != null && type.IsValueType && !type.IsPrimitive) { FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); package.Write(fields.Length); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { package.Write(GetPackageTypeString(fieldInfo.FieldType)); package.AddValue(fieldInfo.GetValue(value)); } return; } } ZRpc.Serialize(new object[1] { value }, ref package); } public static void AddEntry(this ZPackage package, PackageEntry entry) { package.Write(entry.key); package.Write((entry.value == null) ? "" : GetPackageTypeString(entry.type)); package.AddValue(entry.value); } public static ZPackage ToPackage(this PackageEntry packageEntry) { return new List<PackageEntry> { packageEntry }.ToPackage(); } public static ZPackage ToPackage(this IEnumerable<PackageEntry> packageEntries) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(packageEntries?.Count() ?? 0); foreach (PackageEntry item in packageEntries ?? Array.Empty<PackageEntry>()) { val.AddEntry(item); } return val; } public static object ReadValueWithType(this ZPackage package, Type type) { if (type != null && type.IsValueType && !type.IsPrimitive && !type.IsEnum) { FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); int num = package.ReadInt(); if (num != fields.Length) { throw new InvalidDeserializationTypeException { received = $"(field count: {num})", expected = $"(field count: {fields.Length})" }; } object uninitializedObject = FormatterServices.GetUninitializedObject(type); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { string text = package.ReadString(); if (text != GetPackageTypeString(fieldInfo.FieldType)) { throw new InvalidDeserializationTypeException { received = text, expected = GetPackageTypeString(fieldInfo.FieldType), field = fieldInfo.Name }; } fieldInfo.SetValue(uninitializedObject, package.ReadValueWithType(fieldInfo.FieldType)); } return uninitializedObject; } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<, >)) { int num2 = package.ReadInt(); IDictionary dictionary = (IDictionary)Activator.CreateInstance(type); Type type2 = typeof(KeyValuePair<, >).MakeGenericType(type.GenericTypeArguments); FieldInfo field = type2.GetField("key", BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo field2 = type2.GetField("value", BindingFlags.Instance | BindingFlags.NonPublic); for (int j = 0; j < num2; j++) { object obj = package.ReadValueWithType(type2); dictionary.Add(field.GetValue(obj), field2.GetValue(obj)); } return dictionary; } if (type != typeof(List<string>) && type.IsGenericType) { Type type3 = typeof(ICollection<>).MakeGenericType(type.GenericTypeArguments[0]); if (type3 != null && type3.IsAssignableFrom(type)) { int num3 = package.ReadInt(); object obj2 = Activator.CreateInstance(type); MethodInfo method = type3.GetMethod("Add"); for (int k = 0; k < num3; k++) { method.Invoke(obj2, new object[1] { package.ReadValueWithType(type.GenericTypeArguments[0]) }); } return obj2; } } ParameterInfo parameterInfo = (ParameterInfo)FormatterServices.GetUninitializedObject(typeof(ParameterInfo)); AccessTools.DeclaredField(typeof(ParameterInfo), "ClassImpl").SetValue(parameterInfo, type); List<object> source = new List<object>(); ZRpc.Deserialize(new ParameterInfo[2] { null, parameterInfo }, package, ref source); return source.FirstOrDefault(); } public static ParsedEntries ReadEntries(this ZPackage package) { ParsedEntries parsedEntries = new ParsedEntries(); int num = package.ReadInt(); for (int i = 0; i < num; i++) { string key = package.ReadString(); string text = package.ReadString(); Type type = Type.GetType(text); if (!(text == "") && !(type != null)) { Get.Plugin.LogWarning("Got invalid type " + text + ", abort reading of received configs"); return new ParsedEntries(); } object obj; try { obj = ((text == "") ? null : package.ReadValueWithType(type)); } catch (InvalidDeserializationTypeException ex) { Get.Plugin.LogWarning("Got unexpected struct internal type " + ex.received + " for field " + ex.field + " struct " + text); continue; } if (obj != null) { parsedEntries[key] = new PackageEntry { key = key, type = type, value = obj }; } } return parsedEntries; } public static void Test() { } } internal class ParsedEntries : Dictionary<string, PackageEntry> { } internal static class RequirementsEntry { public static RequirementConfig[] Deserialize(string reqs) { return ((IEnumerable<string>)reqs.Split(new char[1] { ',' })).Select((Func<string, RequirementConfig>)delegate(string r) { //IL_0013: 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) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown string[] array = r.Split(new char[1] { ':' }); int result; int result2; return new RequirementConfig { Item = array[0], Amount = ((array.Length <= 1 || !int.TryParse(array[1], out result)) ? 1 : result), AmountPerLevel = ((array.Length > 2 && int.TryParse(array[2], out result2)) ? result2 : 0), Recover = true }; }).ToArray(); } public static string Serialize(RequirementConfig[] reqs) { return string.Join(",", reqs.Select((RequirementConfig r) => (r.AmountPerLevel <= 0) ? $"{r.Item}:{r.Amount}" : $"{r.Item}:{r.Amount}:{r.AmountPerLevel}")); } } internal static class SharedDrawers { private static BaseUnityPlugin configManager; private static BaseUnityPlugin GetConfigManager() { if ((Object)(object)configManager == (Object)null && Chainloader.PluginInfos.TryGetValue("com.bepis.bepinex.configurationmanager", out var value) && Object.op_Implicit((Object)(object)value.Instance)) { configManager = value.Instance; } return configManager; } public static int GetRightColumnWidth() { int result = 130; BaseUnityPlugin val = GetConfigManager(); if ((Object)(object)val != (Object)null) { PropertyInfo propertyInfo = (((Object)(object)val != (Object)null) ? ((object)val).GetType().GetProperty("RightColumnWidth", BindingFlags.Instance | BindingFlags.NonPublic) : null); if (propertyInfo != null) { result = (int)propertyInfo.GetValue(val); } } return result; } public static void ReloadConfigDisplay() { BaseUnityPlugin val = GetConfigManager(); if ((Object)(object)val != (Object)null) { Type type = ((object)val).GetType(); object obj; if (type == null) { obj = null; } else { PropertyInfo property = type.GetProperty("DisplayingWindow"); obj = ((property != null) ? property.GetValue(val) : null); } if (obj is int num && num != 0) { ((object)val).GetType().GetMethod("BuildSettingList").Invoke(val, Array.Empty<object>()); } } } public static Action<ConfigEntryBase> DrawReqConfigTable(bool hasUpgrades = false) { return delegate(ConfigEntryBase cfg) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Expected O, but got Unknown //IL_00da: 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_00f5: Expected O, but got Unknown //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Expected O, but got Unknown //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Expected O, but got Unknown //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Expected O, but got Unknown //IL_01e6: 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_0201: Expected O, but got Unknown //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Expected O, but got Unknown List<RequirementConfig> list = new List<RequirementConfig>(); bool flag = false; int rightColumnWidth = GetRightColumnWidth(); GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); foreach (RequirementConfig item in RequirementsEntry.Deserialize((string)cfg.BoxedValue).ToList()) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); string text = GUILayout.TextField(item.Item, new GUIStyle(GUI.skin.textField) { fixedWidth = rightColumnWidth - 33 - (hasUpgrades ? 37 : 0) - 21 - 21 - 12 }, Array.Empty<GUILayoutOption>()); string text2 = (string.IsNullOrEmpty(text) ? item.Item : text); flag = flag || text2 != item.Item; int num = item.Amount; if (int.TryParse(GUILayout.TextField(num.ToString(), new GUIStyle(GUI.skin.textField) { fixedWidth = 33f }, Array.Empty<GUILayoutOption>()), out var result) && result != num) { num = result; flag = true; } int num2 = item.AmountPerLevel; if (hasUpgrades && int.TryParse(GUILayout.TextField(num2.ToString(), new GUIStyle(GUI.skin.textField) { fixedWidth = 33f }, Array.Empty<GUILayoutOption>()), out var result2) && result2 != num2) { num2 = result2; flag = true; } if (GUILayout.Button("x", new GUIStyle(GUI.skin.button) { fixedWidth = 21f }, Array.Empty<GUILayoutOption>())) { flag = true; } else { list.Add(new RequirementConfig { Item = text2, Amount = num, AmountPerLevel = num2 }); } if (GUILayout.Button("+", new GUIStyle(GUI.skin.button) { fixedWidth = 21f }, Array.Empty<GUILayoutOption>())) { flag = true; list.Add(new RequirementConfig { Item = "<Prefab Name>", Amount = 1 }); } GUILayout.EndHorizontal(); } GUILayout.EndVertical(); if (flag) { cfg.BoxedValue = RequirementsEntry.Serialize(list.ToArray()); } }; } } internal class Watcher { private FileSystemWatcher fileSystemWatcher; public bool EnableRaisingEvents { get { return fileSystemWatcher != null && fileSystemWatcher.EnableRaisingEvents; } set { if (fileSystemWatcher != null) { fileSystemWatcher.EnableRaisingEvents = value; } } } public event Action<object, FileSystemEventArgs> FileChanged; public Watcher(string path, string filter) { if (path == null) { throw new ArgumentNullException("path"); } if (filter == null) { throw new ArgumentNullException("filter"); } Get.Plugin.LogDebugOnly("Watcher created for " + path + ", " + filter); fileSystemWatcher = new FileSystemWatcher(path, filter); fileSystemWatcher.Changed += OnCreatedChangedOrRenamed; fileSystemWatcher.Created += OnCreatedChangedOrRenamed; fileSystemWatcher.Renamed += OnCreatedChangedOrRenamed; fileSystemWatcher.IncludeSubdirectories = true; fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; fileSystemWatcher.EnableRaisingEvents = true; } private void OnCreatedChangedOrRenamed(object sender, FileSystemEventArgs args) { Get.Plugin.LogDebugOnly($"OnCreatedChangedOrRenamed triggered {args.Name}, {args.ChangeType}"); this.FileChanged?.Invoke(sender, args); } } } namespace MoreCrossbows { public class AcceptableKeysString : AcceptableValueBase { public virtual string[] AcceptableKeys { get; } public AcceptableKeysString(params string[] acceptableKeys) : base(typeof(string)) { if (acceptableKeys == null) { throw new ArgumentNullException("acceptableValues"); } if (acceptableKeys.Length == 0) { throw new ArgumentException("At least one acceptable key is needed", "AcceptableKeys"); } AcceptableKeys = acceptableKeys; } public override object Clamp(object value) { return value; } public override bool IsValid(object value) { return value is string && !string.IsNullOrEmpty((string)value); } public override string ToDescriptionString() { return "# Acceptable keys: " + string.Join(", ", AcceptableKeys.Select((string x) => x.ToString()).ToArray()); } } public enum AmmunitionType { None, Arrow, Bolt } public class DamagesConfig { public string Prefab; public int Duration; } public static class DamagesDict { public static Dictionary<string, int> Deserialize(string dmgs) { if (string.IsNullOrEmpty(dmgs)) { return null; } return dmgs.Split(new char[1] { ',' }).Select(delegate(string d) { string[] array = d.Split(new char[1] { ':' }); int result; int result2; return (array.Length > 1) ? new KeyValuePair<string, int>(array[0], (!int.TryParse(array[1], out result)) ? 1 : result) : new KeyValuePair<string, int>("Damage", (!int.TryParse(array[0], out result2)) ? 1 : result2); }).ToDictionary((KeyValuePair<string, int> kvp) => kvp.Key, (KeyValuePair<string, int> kvp) => kvp.Value); } public static string Serialize(Dictionary<string, int> dmgs) { return string.Join(",", dmgs.Select(delegate(KeyValuePair<string, int> d) { KeyValuePair<string, int> keyValuePair = d; string key = keyValuePair.Key; keyValuePair = d; return $"{key}:{keyValuePair.Value}"; })); } } public static class DamagesEntry { public static DamagesConfig[] Deserialize(string dmgs) { return dmgs.Split(new char[1] { ',' }).Select(delegate(string r) { string[] array = r.Split(new char[1] { ':' }); int result; return new DamagesConfig { Prefab = array[0], Duration = ((array.Length <= 1 || !int.TryParse(array[1], out result)) ? 1 : result) }; }).ToArray(); } public static string Serialize(DamagesConfig[] dmgs) { return string.Join(",", dmgs.Select((DamagesConfig r) => $"{r.Prefab}:{r.Duration}")); } public static Action<ConfigEntryBase> DrawDamagesConfigTable() { return delegate(ConfigEntryBase cfg) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown //IL_00cc: 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_00e7: Expected O, but got Unknown //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Expected O, but got Unknown //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Expected O, but got Unknown List<DamagesConfig> list = new List<DamagesConfig>(); bool flag = false; int rightColumnWidth = SharedDrawers.GetRightColumnWidth(); GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); foreach (DamagesConfig item in Deserialize((string)cfg.BoxedValue).ToList()) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); string text = GUILayout.TextField(item.Prefab, new GUIStyle(GUI.skin.textField) { fixedWidth = rightColumnWidth - 56 - 21 - 21 - 9 }, Array.Empty<GUILayoutOption>()); string text2 = (string.IsNullOrEmpty(text) ? item.Prefab : text); flag = flag || text2 != item.Prefab; int num = item.Duration; if (int.TryParse(GUILayout.TextField(num.ToString(), new GUIStyle(GUI.skin.textField) { fixedWidth = 56f }, Array.Empty<GUILayoutOption>()), out var result) && result != num) { num = result; flag = true; } if (GUILayout.Button("x", new GUIStyle(GUI.skin.button) { fixedWidth = 21f }, Array.Empty<GUILayoutOption>())) { flag = true; } else { list.Add(new DamagesConfig { Prefab = text2, Duration = num }); } if (GUILayout.Button("+", new GUIStyle(GUI.skin.button) { fixedWidth = 21f }, Array.Empty<GUILayoutOption>())) { flag = true; list.Add(new DamagesConfig { Prefab = "<Damage Type>", Duration = 120 }); } GUILayout.EndHorizontal(); } GUILayout.EndVertical(); if (flag) { cfg.BoxedValue = Serialize(list.ToArray()); } }; } } public static class DamageTypes { public static string Damage => "Damage"; public static string Blunt => "Blunt"; public static string Slash => "Slash"; public static string Pierce => "Pierce"; public static string Chop => "Chop"; public static string Pickaxe => "Pickaxe"; public static string Fire => "Fire"; public static string Frost => "Frost"; public static string Lightning => "Lightning"; public static string Poison => "Poison"; public static string Spirit => "Spirit"; public static string[] GetValues() { return new string[11] { Damage, Blunt, Slash, Pierce, Chop, Pickaxe, Fire, Frost, Lightning, Poison, Spirit }; } } internal class Entries { public static Dictionary<ConfigurationManagerAttributes, Entries> SavedAttributes = new Dictionary<ConfigurationManagerAttributes, Entries>(); private static AcceptableValueList<string> AcceptableTableValues = new AcceptableValueList<string>(CraftingStations.GetAcceptableValueList().AcceptableValues.Concat(new string[1] { "Custom" }).ToArray()); protected bool visible = true; private Action<object, EventArgs> _action; public string Name { get; set; } = string.Empty; public ConfigEntry<string> Table { get; set; } public ConfigEntry<string> TableCustomName { get; set; } public ConfigEntry<int> MinTableLevel { get; set; } public ConfigEntry<int> Amount { get; set; } public ConfigEntry<string> Requirements { get; set; } public static bool IsTableCustom(string table) { string value; return !CraftingStations.GetNames().TryGetValue(table, out value); } public static ConfigurationManagerAttributes GetAttribute(Entries entries, bool isAdminOnly = true, bool isBrowsable = true, Action<ConfigEntryBase> customDrawer = null) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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_0022: Expected O, but got Unknown ConfigurationManagerAttributes val = new ConfigurationManagerAttributes { Browsable = isBrowsable, IsAdminOnly = isAdminOnly, CustomDrawer = customDrawer }; SavedAttributes.Add(val, entries); return val; } public static void UpdateBrowsable() { foreach (KeyValuePair<ConfigurationManagerAttributes, Entries> savedAttribute in SavedAttributes) { savedAttribute.Key.Browsable = savedAttribute.Value.visible; } Get.Plugin.LogDebugOnly("UpdateBrowsable called."); foreach (Entries item in SavedAttributes.Values.Distinct()) { object? obj = ((ConfigEntryBase)item.TableCustomName).Description.Tags.FirstOrDefault((object x) => x is ConfigurationManagerAttributes); ConfigurationManagerAttributes val = (ConfigurationManagerAttributes)((obj is ConfigurationManagerAttributes) ? obj : null); if (val != null) { val.Browsable = IsTableCustom(item.Table.Value) && item.visible; IPlugin plugin = Get.Plugin; string[] array = new string[5] { item.Name, ": ", item.Table.Value, ", browsable: ", null }; int num = 4; bool? browsable = val.Browsable; array[num] = browsable.ToString(); plugin.LogDebugOnly(string.Concat(array)); } } } public static Entries GetFromFeature(IPlugin instance, Feature config, Entries entries = null, bool visible = true) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Expected O, but got Unknown //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Expected O, but got Unknown //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Expected O, but got Unknown //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Expected O, but got Unknown bool hasUpgrades = config.Type == FeatureType.Crossbow; if (entries == null) { entries = new Entries(); } entries.visible = visible; entries.Name = config.Name; entries.Table = instance.Config(entries.Name, "Table", config.Table, new ConfigDescription("Crafting station where " + entries.Name + " is available.", (AcceptableValueBase)(object)AcceptableTableValues, new object[1] { GetAttribute(entries, isAdminOnly: true, visible) })); entries.TableCustomName = instance.Config(entries.Name, "Table (Custom Name)", IsTableCustom(config.Table) ? config.Table : "", new ConfigDescription("If custom, the name of the crafting station where " + entries.Name + " is available.", (AcceptableValueBase)null, new object[1] { GetAttribute(entries, isAdminOnly: true, IsTableCustom(config.Table) && visible) })); entries.MinTableLevel = instance.Config(entries.Name, "Table Level", config.MinTableLevel, new ConfigDescription("Level of crafting station required to craft " + entries.Name + ".", (AcceptableValueBase)null, new object[1] { GetAttribute(entries, entries.visible) })); entries.Amount = instance.Config(entries.Name, "Amount", config.Amount, new ConfigDescription("The amount of " + entries.Name + " created.", (AcceptableValueBase)null, new object[1] { GetAttribute(entries, entries.visible) })); entries.Requirements = instance.Config(entries.Name, "Requirements", config.Requirements, new ConfigDescription("The required items to craft " + entries.Name + ".", (AcceptableValueBase)(object)new AcceptableValueConfigNote("You must use valid spawn item codes."), new object[1] { GetAttribute(entries, entries.visible, isBrowsable: true, SharedDrawers.DrawReqConfigTable(hasUpgrades)) })); ConfigEntry<string> table = entries.Table; EventHandler eventHandler = OnTableSettingChanged; eventHandler = OnTableSettingChanged; table.SettingChanged += eventHandler; return entries; } private static void OnTableSettingChanged(object sender, EventArgs e) { UpdateBrowsable(); SharedDrawers.ReloadConfigDisplay(); } public void SetVisibility(bool visible) { this.visible = visible; UpdateBrowsable(); } protected void OnSettingChanged(object sender, EventArgs e) { if (_action != null) { _action(sender, e); } } public virtual void AddSettingsChangedHandler(Action<object, EventArgs> action) { _action = action; Table.SettingChanged += OnSettingChanged; MinTableLevel.SettingChanged += OnSettingChanged; Amount.SettingChanged += OnSettingChanged; Requirements.SettingChanged += OnSettingChanged; } public virtual void RemoveSettingsChangedHandler() { Table.SettingChanged -= OnSettingChanged; MinTableLevel.SettingChanged -= OnSettingChanged; Amount.SettingChanged -= OnSettingChanged; Requirements.SettingChanged -= OnSettingChanged; _action = null; } } public static class Extensions { private static HashSet<CustomRecipe> hashsetRecipes; private static Dictionary<string, CustomPrefab> prefabsDict; public static bool Remove(this ObjectDB instance, string prefabName) { if (string.IsNullOrEmpty(prefabName)) { return false; } GameObject itemPrefab = instance.GetItemPrefab(prefabName); if ((Object)(object)itemPrefab != (Object)null) { instance.m_items.Remove(itemPrefab); ((Dictionary<int, GameObject>)(typeof(ObjectDB).GetField("m_itemByHash", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(instance)))?.Remove(StringExtensionMethods.GetStableHashCode(((Object)itemPrefab).name)); return true; } return false; } public static Recipe GetRecipe(this List<Recipe> list, Recipe recipe) { int num = ObjectDB.instance.m_recipes.IndexOf(recipe); if (num > -1) { return list[num]; } string name = ((object)recipe).ToString(); return ((IEnumerable<Recipe>)ObjectDB.instance.m_recipes).FirstOrDefault((Func<Recipe, bool>)((Recipe r) => name.Equals(((object)r).ToString()))); } public static bool Update(this CustomRecipe recipe, RecipeConfig newRecipe) { //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Expected O, but got Unknown //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Expected O, but got Unknown if (hashsetRecipes == null) { hashsetRecipes = AccessTools.Field(typeof(ItemManager), "Recipes").GetValue(ItemManager.Instance) as HashSet<CustomRecipe>; Get.Plugin.LogDebugOnly("Recipes Hashset value retrieved: {hashsetRecipes}"); } Recipe recipe2 = ObjectDB.instance.m_recipes.GetRecipe(recipe.Recipe); if (!((Object)(object)recipe2 == (Object)null)) { IPlugin plugin = Get.Plugin; string text = "Updating recipe "; string text2; if (recipe == null) { text2 = null; } else { Recipe recipe3 = recipe.Recipe; text2 = (((Object)(object)recipe3 != (Object)null) ? ((Object)recipe3).name : null); } plugin.LogDebugOnly(text + text2 + " in place."); recipe2.m_amount = newRecipe.Amount; recipe2.m_minStationLevel = newRecipe.MinStationLevel; Recipe val = recipe2; GameObject prefab = PrefabManager.Instance.GetPrefab(newRecipe.CraftingStation); val.m_craftingStation = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<CraftingStation>() : null); Get.Plugin.LogDebugOnly($"... setting cs to {recipe2.m_craftingStation}."); recipe2.m_resources = newRecipe.GetRequirements(); Requirement[] resources = recipe2.m_resources; foreach (Requirement val2 in resources) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(((Object)val2.m_resItem).name.Replace("JVLmock_", "")); if ((Object)(object)itemPrefab != (Object)null) { val2.m_resItem = itemPrefab.GetComponent<ItemDrop>(); } } if (hashsetRecipes != null) { hashsetRecipes.Remove(recipe); hashsetRecipes.Add(new CustomRecipe(recipe2, false, false)); } return true; } if (hashsetRecipes != null && hashsetRecipes.Contains(recipe)) { IPlugin plugin2 = Get.Plugin; string text3 = "Removing and re-adding recipe "; string text4; if (recipe == null) { text4 = null; } else { Recipe recipe4 = recipe.Recipe; text4 = (((Object)(object)recipe4 != (Object)null) ? ((Object)recipe4).name : null); } plugin2.LogDebugOnly(text3 + text4 + " in ItemManager."); ItemManager.Instance.RemoveRecipe(recipe); ItemManager.Instance.AddRecipe(new CustomRecipe(newRecipe)); return true; } IPlugin plugin3 = Get.Plugin; string text5 = "Error updating recipe "; string text6; if (recipe == null) { text6 = null; } else { Recipe recipe5 = recipe.Recipe; text6 = (((Object)(object)recipe5 != (Object)null) ? ((Object)recipe5).name : null); } plugin3.LogError(text5 + text6 + ", did not find existing recipe in ObjectDB or ItemManager"); return false; } public static bool PrefabExists(this PrefabManager instance, string name) { bool result = false; if (string.IsNullOrEmpty(name)) { return result; } if (prefabsDict == null) { PropertyInfo propertyInfo = ((object)PrefabManager.Instance).GetType().GetMembers(BindingFlags.Instance | BindingFlags.NonPublic).FirstOrDefault((MemberInfo m) => m.Name == "Prefabs") as PropertyInfo; if (propertyInfo != null && propertyInfo.GetValue(PrefabManager.Instance) is Dictionary<string, CustomPrefab> dictionary) { prefabsDict = dictionary; } } if (prefabsDict != null) { result = prefabsDict.ContainsKey(name); } return result; } public static void ApplyToAll(this ItemDrop itemDrop, Action<ItemData> callback) { callback(itemDrop.m_itemData); string name = itemDrop.m_itemData.m_shared.m_name; List<Player> source = ((List<Player>)(typeof(Player).GetField("s_players", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null))) ?? new List<Player>(); List<ItemDrop> second = ((List<ItemDrop>)(typeof(ItemDrop).GetField("s_instances", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null))) ?? new List<ItemDrop>(); Inventory[] source2 = (from c in source.Select((Player p) => ((Humanoid)p).GetInventory()).Concat(from c in Object.FindObjectsOfType<Container>() select c.GetInventory()) where c != null select c).ToArray(); foreach (ItemData item in (from i in (from p in ObjectDB.instance.m_items select p.GetComponent<ItemDrop>() into c where Object.op_Implicit((Object)(object)c) && Object.op_Implicit((Object)(object)((Component)c).GetComponent<ZNetView>()) select c).Concat(second) select i.m_itemData).Concat(source2.SelectMany((Inventory i) => i.GetAllItems()))) { if (item.m_shared.m_name == name) { callback(item); } } } public static object Cast(this Type Type, object data) { ParameterExpression parameterExpression = null; return Expression.Lambda(Expression.Block(Expression.Convert(Expression.Convert(parameterExpression, data.GetType()), Type)), parameterExpression).Compile().DynamicInvoke(data); } } internal class Feature { public bool RequiresUpdate { get; protected set; } public bool LoadedInGame { get; protected set; } public bool EnabledByDefault { get; set; } public string Name { get; set; } public string Category { get; set; } public string Description { get; set; } public FeatureType Type { get; set; } public string Table { get; set; } public int MinTableLevel { get; set; } = 1; public string Requirements { get; set; } public int Amount { get; set; } = 1; public List<string> DependencyNames { get; set; } public ConfigEntry<bool> EnabledConfigEntry { get; protected set; } public Entries Entries { get; protected set; } public Feature(string name) { Name = name; LoadedInGame = false; DependencyNames = new List<string>(); } public virtual bool Initialize() { return false; } public virtual bool Load() { return false; } public virtual bool Unload() { return false; } public virtual bool Update() { return false; } public virtual string FetchTableEntryValue() { string text = Entries?.Table?.Value; string a = text; if (string.Equals(a, "Custom") && Entries?.TableCustomName != null) { return Entries.TableCustomName.Value; } return Table; } } internal class FeatureItem : Feature { private CustomItem _customItem; public new ItemEntries Entries { get; protected set; } public string AoePrefabName { get; set; } public string AssetPath { get; set; } public string Damages { get; set; } = string.Empty; public int Knockback { get; set; } public AmmunitionType AmmoType { get; set; } public FeatureItem(string name) : base(name) { } private void OnEntrySettingChanged(object sender, EventArgs e) { Get.Plugin.LogDebugOnly("OnEntrySettingChanged fired on feature " + base.Name); base.RequiresUpdate = true; } private void OnEnabledSettingChanged(object sender, EventArgs e) { Get.Plugin.LogDebugOnly("OnEnabledSettingChanged fired on feature " + base.Name); Entries.SetVisibility(base.EnabledConfigEntry.Value); base.RequiresUpdate = true; SharedDrawers.ReloadConfigDisplay(); } public override string FetchTableEntryValue() { string text = Entries?.Table?.Value; string a = text; if (string.Equals(a, "Custom") && Entries?.TableCustomName != null) { return Entries.TableCustomName.Value; } return base.Table; } public override bool Initialize() { if (!string.IsNullOrEmpty(base.Category) && !string.IsNullOrEmpty(base.Description)) { base.EnabledConfigEntry = MoreCrossbows.Instance.Config(base.Category, "Enable" + base.Name, base.EnabledByDefault, base.Description); base.EnabledConfigEntry.SettingChanged += OnEnabledSettingChanged; Entries = ItemEntries.GetFromFeature(MoreCrossbows.Instance, this, base.EnabledConfigEntry.Value); Entries.AddSettingsChangedHandler(OnEntrySettingChanged); } return true; } public override bool Update() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown base.RequiresUpdate = false; RecipeConfig val = new RecipeConfig(); val.Item = Entries.Name; val.CraftingStation = CraftingStations.GetInternalName(FetchTableEntryValue()); val.RepairStation = CraftingStations.GetInternalName(FetchTableEntryValue()); val.MinStationLevel = ((Entries != null) ? Entries.MinTableLevel.Value : base.MinTableLevel); val.Amount = ((Entries != null) ? Entries.Amount.Value : base.Amount); string text = Entries?.Requirements?.Value; val.Requirements = RequirementsEntry.Deserialize(text ?? base.Requirements); RecipeConfig newRecipe = val; IPlugin plugin = Get.Plugin; string text2 = "Updating recipe for "; CustomItem customItem = _customItem; string text3; if (customItem == null) { text3 = null; } else { ItemDrop itemDrop = customItem.ItemDrop; text3 = (((Object)(object)itemDrop != (Object)null) ? ((Object)itemDrop).name : null); } plugin.LogDebugOnly(text2 + text3); Get.Plugin.LogDebugOnly("... table: " + CraftingStations.GetInternalName(FetchTableEntryValue()) + " level " + ((Entries != null) ? Entries.MinTableLevel.Value : base.MinTableLevel)); Get.Plugin.LogDebugOnly("... reqs: " + ((Entries != null) ? Entries.Requirements.Value : base.Requirements)); _customItem.Recipe.Update(newRecipe); Get.Plugin.LogDebugOnly("Overwriting damages of " + base.Name + " with : " + Entries.Damages.Value); setDamage(DamagesDict.Deserialize(Entries.Damages.Value), AoePrefabName); return true; } public override bool Load() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown Get.Plugin.LogDebugOnly("Loading item " + base.Name); ItemConfig val = new ItemConfig(); val.CraftingStation = CraftingStations.GetInternalName(FetchTableEntryValue()); val.RepairStation = CraftingStations.GetInternalName(FetchTableEntryValue()); val.MinStationLevel = ((Entries != null) ? Entries.MinTableLevel.Value : base.MinTableLevel); val.Amount = ((Entries != null) ? Entries.Amount.Value : base.Amount); string text = Entries?.Requirements?.Value; val.Requirements = RequirementsEntry.Deserialize(text ?? base.Requirements); ItemConfig val2 = val; _customItem = new CustomItem(MoreCrossbows.Instance.assetBundle, AssetPath, true, val2); setDamage(DamagesDict.Deserialize((Entries != null) ? Entries.Damages.Value : Damages), AoePrefabName); _customItem.ItemDrop.m_itemData.m_shared.m_attackForce = Knockback; if (AmmoType == AmmunitionType.Arrow) { _customItem.ItemDrop.m_itemData.m_shared.m_ammoType = "$ammo_arrows"; } else if (AmmoType == AmmunitionType.Bolt) { _customItem.ItemDrop.m_itemData.m_shared.m_ammoType = "$ammo_bolts"; } ItemManager.Instance.AddItem(_customItem); base.RequiresUpdate = false; base.LoadedInGame = true; return true; } public override bool Unload() { Get.Plugin.LogDebugOnly("Unloading item " + base.Name); ItemManager.Instance.RemoveItem(base.Name); ObjectDB.instance.Remove(base.Name); base.LoadedInGame = false; base.RequiresUpdate = false; return true; } private void setDamage(Dictionary<string, int> dmgs, string aoePrefabName) { _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_damage = (dmgs.ContainsKey(DamageTypes.Damage) ? dmgs[DamageTypes.Damage] : 0); _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_blunt = (dmgs.ContainsKey(DamageTypes.Blunt) ? dmgs[DamageTypes.Blunt] : 0); _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_slash = (dmgs.ContainsKey(DamageTypes.Slash) ? dmgs[DamageTypes.Slash] : 0); _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_pierce = (dmgs.ContainsKey(DamageTypes.Pierce) ? dmgs[DamageTypes.Pierce] : 0); _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_chop = (dmgs.ContainsKey(DamageTypes.Chop) ? dmgs[DamageTypes.Chop] : 0); _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_pickaxe = (dmgs.ContainsKey(DamageTypes.Pickaxe) ? dmgs[DamageTypes.Pickaxe] : 0); _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_fire = (dmgs.ContainsKey(DamageTypes.Fire) ? dmgs[DamageTypes.Fire] : 0); _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_frost = (dmgs.ContainsKey(DamageTypes.Frost) ? dmgs[DamageTypes.Frost] : 0); _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_lightning = (dmgs.ContainsKey(DamageTypes.Lightning) ? dmgs[DamageTypes.Lightning] : 0); _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_poison = (dmgs.ContainsKey(DamageTypes.Poison) ? dmgs[DamageTypes.Poison] : 0); _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_spirit = (dmgs.ContainsKey(DamageTypes.Spirit) ? dmgs[DamageTypes.Spirit] : 0); if (string.IsNullOrEmpty(aoePrefabName)) { return; } GameObject prefab = PrefabManager.Instance.GetPrefab(aoePrefabName); if ((Object)(object)prefab != (Object)null) { Get.Plugin.LogDebugOnly("seting aoe dmg of " + ((Object)_customItem.ItemDrop).name); Aoe component = prefab.GetComponent<Aoe>(); if ((Object)(object)component != (Object)null) { float num = _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_frost / 3f; component.m_damage.m_frost = num * 2f; _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_frost = num; component.m_damage.m_fire = _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_fire; component.m_damage.m_lightning = _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_lightning; component.m_damage.m_poison = _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_poison; component.m_damage.m_spirit = _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_spirit; } } } } internal class FeatureRecipe : Feature { public FeatureRecipe(string name) : base(name) { } private void OnEntrySettingChanged(object sender, EventArgs e) { Get.Plugin.LogDebugOnly("OnEntrySettingChanged fired on feature " + base.Name); base.RequiresUpdate = true; } private void OnEnabledSettingChanged(object sender, EventArgs e) { Get.Plugin.LogDebugOnly("OnEnabledSettingChanged fired on feature " + base.Name); base.Entries.SetVisibility(base.EnabledConfigEntry.Value); base.RequiresUpdate = true; SharedDrawers.ReloadConfigDisplay(); } public override bool Initialize() { base.EnabledConfigEntry = MoreCrossbows.Instance.Config(base.Category, "Enable" + base.Name, base.EnabledByDefault, base.Description); base.EnabledConfigEntry.SettingChanged += OnEnabledSettingChanged; base.Entries = Entries.GetFromFeature(MoreCrossbows.Instance, this, null, base.EnabledConfigEntry.Value); base.Entries.AddSettingsChangedHandler(OnEntrySettingChanged); return true; } public override bool Update() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown base.RequiresUpdate = false; RecipeConfig val = new RecipeConfig(); val.Item = base.Entries.Name; val.CraftingStation = CraftingStations.GetInternalName(FetchTableEntryValue()); val.RepairStation = CraftingStations.GetInternalName(FetchTableEntryValue()); val.MinStationLevel = ((base.Entries != null) ? base.Entries.MinTableLevel.Value : base.MinTableLevel); val.Amount = ((base.Entries != null) ? base.Entries.Amount.Value : base.Amount); string text = base.Entries?.Requirements?.Value; val.Requirements = RequirementsEntry.Deserialize(text ?? base.Requirements); RecipeConfig newRecipe = val; CustomRecipe recipe = ItemManager.Instance.GetRecipe("CraftEarly" + base.Name); Get.Plugin.LogDebugOnly("Updating recipe " + base.Entries.Name); IPlugin plugin = Get.Plugin; string text2 = "... reqs: "; plugin.LogDebugOnly((text2 + base.Entries != null) ? base.Entries.Requirements.Value : base.Requirements); recipe.Update(newRecipe); base.RequiresUpdate = false; return true; } public override bool Load() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Expected O, but got Unknown Get.Plugin.LogDebugOnly("Loading recipe for " + base.Name); RecipeConfig val = new RecipeConfig { Name = "CraftEarly" + base.Entries.Name, Item = base.Entries.Name, CraftingStation = CraftingStations.GetInternalName(FetchTableEntryValue()), RepairStation = CraftingStations.GetInternalName(FetchTableEntryValue()), MinStationLevel = base.Entries.MinTableLevel.Value, Amount = base.Entries.Amount.Value, Requirements = RequirementsEntry.Deserialize(base.Entries.Requirements.Value) }; ItemManager.Instance.AddRecipe(new CustomRecipe(val)); base.RequiresUpdate = false; base.LoadedInGame = true; return true; } public override bool Unload() { Get.Plugin.LogDebugOnly("Unloading recipe for " + base.Name); ItemManager.Instance.RemoveRecipe("CraftEarly" + base.Name); base.LoadedInGame = false; base.RequiresUpdate = false; return true; } } public enum FeatureType { Crossbow, Arrow, Bolt } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int), typeof(bool) })] [HarmonyPriority(800)] public static class GetTooltipPatch { public static string Postfix(string __result, ItemData item) { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Invalid comparison between Unknown and I4 //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Invalid comparison between Unknown and I4 if (item == null) { return __result; } StringBuilder stringBuilder = new StringBuilder(256); stringBuilder.Append(__result); if (item.m_shared != null && item.m_shared.m_attack != null && Object.op_Implicit((Object)(object)item.m_shared.m_attack.m_attackProjectile)) { Projectile component = item.m_shared.m_attack.m_attackProjectile.GetComponent<Projectile>(); if ((Object)(object)component != (Object)null && Object.op_Implicit((Object)(object)component.m_spawnOnHit)) { Aoe component2 = component.m_spawnOnHit.GetComponent<Aoe>(); if ((Object)(object)component2 != (Object)null && ((int)item.m_shared.m_itemType == 3 || (int)item.m_shared.m_itemType == 9)) { stringBuilder.Append(TooltipHelper.GetAoeTooltipForItem(item, component2)); } } } return stringBuilder.ToString(); } } internal class ItemEntries : Entries { public ConfigEntry<string> Damages { get; set; } public override void AddSettingsChangedHandler(Action<object, EventArgs> action) { base.AddSettingsChangedHandler(action); Damages.SettingChanged += base.OnSettingChanged; } public override void RemoveSettingsChangedHandler() { base.RemoveSettingsChangedHandler(); Damages.SettingChanged -= base.OnSettingChanged; } public static ItemEntries GetFromFeature(IPlugin instance, FeatureItem config, bool visible = true) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown ItemEntries entries = new ItemEntries(); entries = (ItemEntries)Entries.GetFromFeature(instance, config, entries, visible); entries.Damages = instance.Config(entries.Name, "Damages", config.Damages, new ConfigDescription("The damage done by " + entries.Name + ".", (AcceptableValueBase)(object)new AcceptableKeysString(DamageTypes.GetValues()), new object[1] { Entries.GetAttribute(entries, isAdminOnly: true, entries.visible, DamagesEntry.DrawDamagesConfigTable()) })); return entries; } } public static class JewelcraftingPatches { private static FieldInfo effectPrefabsByTypeInfo; private static Type vecType; public static void Initialize(Harmony harmony, BaseUnityPlugin jewelcrafting) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown if (harmony == null || (Object)(object)jewelcrafting == (Object)null) { throw new ArgumentNullException("Attempted to initialize without harmony, jewelcrafting or both."); } Assembly assembly = ((object)jewelcrafting).GetType().Assembly; MethodInfo method = assembly.GetType("Jewelcrafting.GemEffects.VisualEffects").GetMethod("prefabDict"); MethodInfo method2 = typeof(JewelcraftingPatches).GetMethod("VisualEffectsPrefabDictPostfix", BindingFlags.Static | BindingFlags.NonPublic); if (method != null && method2 != null) { harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { Get.Plugin.LogWarning($"Found Jewelcrafting but unable to patch. method = {method}, postfix = {method2}"); } List<string[]> list = new List<string[]>(); list.Add(new string[3] { "Perfect_Yellow_Socket", VisualEffectCondition.CrossbowIron.ToString(), "jc_echo_ironxbow" }); list.Add(new string[3] { "Perfect_Red_Socket", VisualEffectCondition.CrossbowIron.ToString(), "jc_endlessarrows_ironxbow" }); list.Add(new string[3] { "Perfect_Purple_Socket", VisualEffectCondition.CrossbowIron.ToString(), "jc_masterarcher_ironxbow" }); list.Add(new string[3] { "Perfect_Green_Socket", VisualEffectCondition.CrossbowIron.ToString(), "jc_necromancer_ironxbow" }); list.Add(new string[3] { "Perfect_Yellow_Socket", VisualEffectCondition.CrossbowSilver.ToString(), "jc_echo_silverxbow" }); list.Add(new string[3] { "Perfect_Red_Socket", VisualEffectCondition.CrossbowSilver.ToString(), "jc_endlessarrows_silverxbow" }); list.Add(new string[3] { "Perfect_Purple_Socket", VisualEffectCondition.CrossbowSilver.ToString(), "jc_masterarcher_silverxbow" }); list.Add(new string[3] { "Perfect_Green_Socket", VisualEffectCondition.CrossbowSilver.ToString(), "jc_necromancer_silverxbow" }); list.Add(new string[3] { "Perfect_Yellow_Socket", VisualEffectCondition.CrossbowBlackmetal.ToString(), "jc_echo_blackmetalxbow" }); list.Add(new string[3] { "Perfect_Red_Socket", VisualEffectCondition.CrossbowBlackmetal.ToString(), "jc_endlessarrows_blackmetalxbow" }); list.Add(new string[3] { "Perfect_Purple_Socket", VisualEffectCondition.CrossbowBlackmetal.ToString(), "jc_masterarcher_blackmetalxbow" }); list.Add(new string[3] { "Perfect_Green_Socket", VisualEffectCondition.CrossbowBlackmetal.ToString(), "jc_necromancer_blackmetalxbow" }); List<string[]> toLoad = list; Type type = ((assembly != null) ? assembly.GetType("Jewelcrafting.GemEffects.VisualEffects") : null); if (vecType == null) { vecType = ((assembly != null) ? assembly.GetType("Jewelcrafting.VisualEffectCondition") : null); } Type type2 = type; FieldInfo fieldInfo = ((type2 != null) ? type2.GetField("attachEffectPrefabs", BindingFlags.Static | BindingFlags.Public) : null); if (((fieldInfo != null) ? fieldInfo.GetValue(null) : null) is IDictionary effectPrefabs) { LoadPrefabs(effectPrefabs, toLoad); } else { Get.Plugin.LogDebugOnly("Unable to invoke attachEffectPrefabs, not found."); } } private static void LoadPrefabs(IDictionary effectPrefabs, List<string[]> toLoad) { foreach (string[] item in toLoad) { string text = item[0]; string text2 = item[2]; VisualEffectCondition visualEffectCondition = (VisualEffectCondition)Enum.Parse(typeof(VisualEffectCondition), item[1]); GameObject val = MoreCrossbows.Instance.assetBundle.LoadAsset<GameObject>(text2); if ((Object)(object)val == (Object)null) { Get.Plugin.LogWarning("Prefab " + text2 + " did not load correctly"); continue; } if (!effectPrefabs.Contains(text)) { Get.Plugin.LogWarning("attachEffectPrefabs does not contain " + text + " key; Aborting."); break; } IDictionary dictionary = effectPrefabs[text] as IDictionary; object obj = vecType?.Cast(visualEffectCondition); if (obj == null) { Get.Plugin.LogWarning("Failed to cast VisualEffectCondition to Jewelcrafting type. Skipping."); } else if (dictionary != null && !dictionary.Contains(obj)) { Get.Plugin.LogDebugOnly($"Adding: {visualEffectCondition} {val} to effectPrefabs[{text}]"); dictionary.Add(obj, val); } else { Get.Plugin.LogDebugOnly($"effectPrefabs[{text}] already contains a {visualEffectCondition} key, skipping."); } } } private static void VisualEffectsPrefabDictPostfix(ref Dictionary<string, GameObject[]> __result, SharedData shared) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_0143: Unknown result type (might be due to invalid IL or missing references) if (__result == null || (int)shared.m_skillType != 14) { return; } VisualEffectCondition visualEffectCondition = SkillKey(shared); int num = ((__result != null) ? __result.Count : 0); if (effectPrefabsByTypeInfo == null || vecType == null) { BaseUnityPlugin jewelcrafting = MoreCrossbows.Instance.jewelcrafting; Assembly assembly = (((Object)(object)jewelcrafting != (Object)null) ? ((object)jewelcrafting).GetType().Assembly : null); Type type = ((assembly != null) ? assembly.GetType("Jewelcrafting.GemEffects.VisualEffects") : null); vecType = ((assembly != null) ? assembly.GetType("Jewelcrafting.VisualEffectCondition") : null); effectPrefabsByTypeInfo = ((type != null) ? type.GetField("effectPrefabsByType", BindingFlags.Static | BindingFlags.NonPublic) : null); } FieldInfo fieldInfo = effectPrefabsByTypeInfo; if (((fieldInfo != null) ? fieldInfo.GetValue(null) : null) is IDictionary dictionary) { if (dictionary[vecType.Cast(visualEffectCondition)] is Dictionary<string, GameObject[]> { Count: >0 } dictionary2) { Get.Plugin.LogDebugOnly($"Patched visual effects lookup by skill, type = {shared.m_itemType}, key = {visualEffectCondition}, results = {num}"); __result = dictionary2; } } else { Get.Plugin.LogWarning("Failed to find Jewelcrafting.GemEffects.VisualEffects.effectPrefabsByType via reflection."); } } private static VisualEffectCondition SkillKey(SharedData shared) { //IL_0002: 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_000f: Invalid comparison between Unknown and I4 //IL_002b: 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_0034: Invalid comparison between Unknown and I4 //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Invalid comparison between Unknown and I4 //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected I4, but got Unknown return (VisualEffectCondition)(shared.m_skillType | (((int)shared.m_skillType == 14 && shared.m_name.Contains("$item_crossbow_iron")) ? 4194318 : 0) | (((int)shared.m_skillType == 14 && shared.m_name.Contains("$item_crossbow_silver")) ? 5242894 : 0) | (((int)shared.m_skillType == 14 && shared.m_name.Contains("$item_crossbow_blackmetal")) ? 6291470 : 0)); } } [BepInPlugin("probablykory.MoreCrossbows", "MoreCrossbows", "1.2.14")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] internal class MoreCrossbows : BaseUnityPlugin, IPlugin { public static MoreCrossbows Instance; public const string PluginAuthor = "probablykory"; public const string PluginName = "MoreCrossbows"; public const string PluginVersion = "1.2.11"; public const string PluginGUID = "probablykory.MoreCrossbows"; private static ConfigEntry<bool> isDebugEnabled = null; internal AssetBundle assetBundle; internal Harmony harmony; internal BaseUnityPlugin jewelcrafting; private List<Feature> _features = new List<Feature>(); private static Dictionary<string, string> DefaultEnglishLanguageStrings = new Dictionary<string, string> { { "$area_of_effect", "Area effect" }, { "$every", "every" }, { "$seconds", "seconds" }, { "$per_second", "per second" }, { "$item_crossbow_wood", "Wooden crossbow" }, { "$item_crossbow_wood_description", "A crudely-made but powerful weapon." }, { "$item_crossbow_bronze", "Bronze crossbow" }, { "$item_crossbow_bronze_description", "A powerful weapon, forged in bronze." }, { "$item_crossbow_iron", "Iron crossbow" }, { "$item_crossbow_iron_description", "An accurate, powerful messenger of death." }, { "$item_crossbow_silver", "Silver crossbow" }, { "$item_crossbow_silver_description", "A sleek weapon, crafted from the mountain top." }, { "$item_crossbow_blackmetal", "Blackmetal crossbow" }, { "$item_crossbow_blackmetal_description", "A vicious thing. Handle with care." }, { "$item_bolt_wood", "Wood bolt" }, { "$item_bolt_wood_description", "A brittle crossbow bolt of sharpened wood." }, { "$item_bolt_fire", "Fire bolt" }, { "$item_bolt_fire_description", "A piercing bolt of fire." }, { "$item_bolt_silver", "Silver bolt" }, { "$item_bolt_silver_description", "A bolt to calm restless spirits." }, { "$item_bolt_poison", "Poison bolt" }, { "$item_bolt_poison_description", "A bitter dose for your enemies." }, { "$item_bolt_frost", "Frost bolt" }, { "$item_bolt_frost_description", "A piercing bolt of ice." }, { "$item_bolt_lightning", "Lightning bolt" }, { "$item_bolt_lightning_description", "Noone can know when or where it will strike." }, { "$item_arrow_lightning", "Lightning arrow" }, { "$item_arrow_lightning_description", "Noone can know when or where it will strike." }, { "$item_bolt_surtling", "Surtling bolt" }, { "$item_bolt_surtling_description", "Do not use indoors." }, { "$item_bolt_ooze", "Ooze bolt" }, { "$item_bolt_ooze_description", "The stench is unbearable..." }, { "$item_bolt_bile", "Bile bolt" }, { "$item_bolt_bile_description", "Handle with care." }, { "$item_bolt_ice", "Ice bolt" }, { "$item_bolt_ice_description", "Heart of the frozen mountain." }, { "$item_bolt_flametal", "Flametal bolt" }, { "$item_bolt_flametal_description", "Do not use indoors." } }; IPlugin IPlugin.Instance => Instance; public ManualLogSource Logger { get; private set; } = Logger.CreateLogSource("MoreCrossbows"); public bool Debug => isDebugEnabled == null || isDebugEnabled.Value; private void Awake() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown Get.Plugin = this; Instance = this; harmony = new Harmony("probablykory.MoreCrossbows"); harmony.PatchAll(typeof(GetTooltipPatch)); assetBundle = AssetUtils.LoadAssetBundleFromResources("crossbows"); new ConfigWatcher(this); isDebugEnabled = this.Config("1 - General", "Debugging Enabled", value: false, "If on, mod will output alot more information in the debug log level."); ((BaseUnityPlugin)this).Config.SaveOnConfigSet = true; CheckForJewelcrafting(); InitializeFeatures(); AddDefaultLocalizations(); SynchronizationManager.OnConfigurationSynchronized += OnConfigurationSynchronized; PrefabManager.OnVanillaPrefabsAvailable += OnVanillaPrefabsAvailable; LocalizationManager.OnLocalizationAdded += OnLocalizationAdded; ((BaseUnityPlugin)this).Config.ConfigReloaded += OnConfigReloaded; } private void OnConfigReloaded(object sender, EventArgs e) { } private void OnConfigurationSynchronized(object sender, EventArgs e) { } private void CheckForJewelcrafting() { try { if (Chainloader.PluginInfos.TryGetValue("org.bepinex.plugins.jewelcrafting", out var value) && (Object)(object)((value != null) ? value.Instance : null) != (Object)null) { Logger.LogInfo((object)"Patching customized crossbow gem effects for Jewelcrafting."); jewelcrafting = value.Instance; JewelcraftingPatches.Initialize(harmony, value.Instance); } } catch (Exception ex) { Logger.LogWarning((object)("Jewelcrafting compatibility skipped: " + ex.Message)); } } private void OnConfigurationSynchronized(object sender, ConfigurationSynchronizationEventArgs e) { this.LogDebugOnly("Configuration Sync received."); AddOrRemoveFeatures(); } private void OnVanillaPrefabsAvailable() { this.LogDebugOnly("Vanilla Prefabs Available received."); AddOrRemoveFeatures(); } private void OnDestroy() { this.LogDebugOnly("OnDestroy called."); SynchronizationManager.OnConfigurationSynchronized -= OnConfigurationSynchronized; PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable; } private void RegisterCustomPrefab(AssetBundle bundle, string assetName) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown string text = assetName.Replace(".prefab", ""); if (!string.IsNullOrEmpty(text) && !PrefabManager.Instance.PrefabExists(text)) { CustomPrefab val = new CustomPrefab(bundle, assetName, true); this.LogDebugOnly("Registering " + ((Object)val.Prefab).name); if (val != null && val.IsValid()) { PrefabExtension.FixReferences(val.Prefab, true); PrefabManager.Instance.AddPrefab(val); } } } private void AddOrRemoveFeatures() { bool flag = true; int num = 0; int num2 = 0; int num3 = 0; foreach (Feature feature in _features) { bool flag2; if (feature.EnabledConfigEntry == null) { flag2 = flag; } else { flag2 = feature.EnabledConfigEntry.Value; flag = flag && flag2; } this.LogDebugOnly("DEBUG: allFeaturesEnabled = " + flag); this.LogDebugOnly("DEBUG: Feature " + feature.Name + " is " + (flag2 ? "enabled" : "disabled") + " and " + (feature.LoadedInGame ? "Loaded" : "Unloaded")); if (flag2 != feature.LoadedInGame) { if (flag2) { if (feature.DependencyNames.Count > 0) { foreach (string dependencyName in feature.DependencyNames) { RegisterCustomPrefab(assetBundle, dependencyName); } } feature.Load(); num++; } else { feature.Unload(); num2++; } } else if (feature.LoadedInGame && feature.RequiresUpdate) { feature.Update(); num3++; } } string text = ""; if (num > 0) { text = string.Format("{0} feature{1} loaded", num, (num > 1) ? "s" : ""); text = ((num2 <= 0) ? (text + ".") : (text + " and ")); } if (num2 > 0) { text += string.Format("{0} feature{1} unloaded.", num2, (num2 > 1) ? "s" : ""); } if (num3 > 0) { if (text.Length > 0) { text += " "; } text += string.Format("{0} feature{1} updated.", num3, (num3 > 1) ? "s" : ""); } if (text.Length > 0) { this.LogInfo(text); } Entries.UpdateBrowsable(); } private void AddDefaultLocalizations() { this.LogDebugOnly("AddLocalizations called."); CustomLocalization localization = LocalizationManager.Instance.GetLocalization(); string text = "English"; localization.AddTranslation(ref text, DefaultEnglishLanguageStrings); } private void OnLocalizationAdded() { this.LogDebugOnly("Localization Added received."); string location = ((object)Instance).GetType().Assembly.Location; char directorySeparatorChar = Path.DirectorySeparatorChar; string text = location.Replace(directorySeparatorChar + "MoreCrossbows.dll", ""); if (Paths.PluginPath.Equals(text)) { text = Utility.CombinePaths(new string[2] { Paths.PluginPath, "MoreCrossbows" }); } string text2 = Utility.CombinePaths(new string[4] { text, "Translations", "English", "english.json" }); string directoryName = Path.GetDirectoryName(text2); if (!Directory.Exists(directoryName) || !File.Exists(text2)) { Directory.CreateDirectory(directoryName); string contents = JsonUtility.ToJson((object)DefaultEnglishLanguageStrings); File.WriteAllText(text2, contents); this.LogDebugOnly("Default localizations written to " + text2); } LocalizationManager.OnLocalizationAdded -= OnLocalizationAdded; } private void InitializeFeatures() { _features.Add(new FeatureItem("CrossbowWood") { Category = "2 - Crossbows", Description = "Adds a new Wooden Crossbow weapon", EnabledByDefault = true, AssetPath = "Assets/PrefabInstance/CrossbowWood.prefab", Type = FeatureType.Crossbow, AmmoType = AmmunitionType.Bolt, Table = "Workbench", MinTableLevel = 2, Requirements = "Wood:20:5,Stone:8:2,LeatherScraps:8:2", Damages = "Pierce:27", Knockback = 80, DependencyNames = new List<string> { "sfx_wood_crossbow_fire.prefab" } }); _features.Add(new FeatureItem("CrossbowBronze") { Category = "2 - Crossbows", Description = "Adds a new Bronze Crossbow weapon", EnabledByDefault = true, AssetPath = "Assets/PrefabInstance/CrossbowBronze.prefab", Type = FeatureType.Crossbow, AmmoType = AmmunitionType.Bolt, Table = "Forge", MinTableLevel = 1, Requirements = "Wood:10:5,FineWood:4:2,Bronze:10:5,DeerHide:2:1", Damages = "Pierce:42", Knockback = 100, DependencyNames = new List<string> { "sfx_bronze_crossbow_fire.prefab" } }); _features.Add(new FeatureItem("CrossbowIron") { Category = "2 - Crossbows", Description = "Adds a new Iron Crossbow weapon", EnabledByDefault = true, AssetPath = "Assets/PrefabInstance/CrossbowIron.prefab", Type = FeatureType.Crossbow, AmmoType = AmmunitionType.Bolt, Table = "Forge", MinTableLevel = 2, Requirements = "Wood:10:5,ElderBark:4:2,Iron:20:10,Root:1", Damages = "Pierce:57", Knockback = 120 }); _features.Add(new FeatureItem("CrossbowSilver") { Category = "2 - Crossbows", Description = "Adds a new Silver Crossbow weapon", EnabledByDefault = true, AssetPath = "Assets/PrefabInstance/CrossbowSilver.prefab", Type = FeatureType.Crossbow, AmmoType = AmmunitionType.Bolt, Table = "Forge", MinTableLevel = 3, Requirements = "Wood:10:4,Silver:10:5,Iron:10:5,WolfHairBundle:6", Damages = "Pierce:72", Knockback = 140 }); _features.Add(new FeatureItem("CrossbowBlackmetal") { Category = "2 - Crossbows", Description = "Adds a new Blackmetal Crossbow weapon", EnabledByDefault = true, AssetPath = "Assets/PrefabInstance/CrossbowBlackmetal.prefab", Type = FeatureType.Crossbow, AmmoType = AmmunitionType.Bolt, Table = "Forge", MinTableLevel = 4, Requirements = "FineWood:10:5,BlackMetal:16:8,Iron:8:4,LoxPelt:2:1", Damages = "Pierce:92", Knockback = 160 }); _features.Add(new FeatureItem("BoltWood") { Category = "4 - Bolts", Description = "Adds new wood bolts", EnabledByDefault = true, AssetPath = "Assets/PrefabInstance/BoltWood.prefab", Type = FeatureType.Bolt, Amount = 20, Table = "Workbench", MinTableLevel = 2, Requirements = "Wood:8", Damages = "Pierce:22", DependencyNames = new List<string> { "arbalest_projectile_wood.prefab" } }); _features.Add(new FeatureItem("BoltFire") { Category = "4 - Bolts", Description = "Adds new fire bolts", EnabledByDefault = true, AssetPath = "Assets/PrefabInstance/BoltFire.prefab", Type = FeatureType.Bolt, Amount = 20, Table = "Workbench", MinTableLevel = 2, Requirements = "Wood:8,Resin:8,Feathers:2", Damages = "Pierce:11,Fire:22", DependencyNames = new List<string> { "arbalest_projectile_fire.prefab" } }); _features.Add(new FeatureItem("BoltSilver") { Category = "4 - Bolts", Description = "Adds new silver bolts", EnabledByDefault = true, AssetPath = "Assets/PrefabInstance/BoltSilver.prefab", Type = FeatureType.Bolt, Amount = 20, Table = "Forge", MinTableLevel = 3, Requirements = "Wood:8,Silver:1,Feathers:2", Damages = "Pierce:52,Spirit:20", DependencyNames = new List<string> { "arbalest_projectile_wood.prefab" } }); _features.Add(new FeatureItem("BoltPoison") { Category = "4 - Bolts", Description = "Adds new poison bolts", EnabledByDefault = true, AssetPath = "Assets/PrefabInstance/BoltPoison.prefab", Type = FeatureType.Bolt, Amount = 20, Table = "Workbench", MinTableLevel = 3, Requirements = "Wood:8,Obsidian:4,Feathers:2,Ooze:2", Damages = "Pierce:26,Poison:52", DependencyNames = new List<string> { "arbalest_projectile_poison.prefab" } }); _features.Add(new FeatureItem("BoltFrost") { Category = "4 - Bolts", Description = "Adds new frost bolts", EnabledByDefault = true, AssetPath = "Assets/PrefabInstance/BoltFrost.prefab", Type = FeatureType.Bolt, Amount = 20, Table = "Workbench", MinTableLevel = 4, Requirements = "Wood:8,Obsidian:4,Feathers:2,FreezeGland:1", Damages = "Pierce:26,Frost:52", DependencyNames = new List<string> { "arbalest_projectile_frost.prefab" } }); _features.Add(new FeatureItem("BoltLightning") { Category = "4 - Bolts", Description = "Adds new lightning bolts", EnabledByDefault = false, AssetPath = "Assets/PrefabInstance/BoltLightning.prefab", Type = FeatureType.Bolt, Amount = 20, Table = "BlackForge", MinTableLevel = 2, Requirements = "Wood:8,Feathers:2,Eitr:1", Damages = "Pierce:36,Lightning:62", DependencyNames = new List<string> { "sfx_lightning_hit.prefab", "arbalest_projectile_lightning.prefab" } }); _features.Add(new FeatureItem("ArrowLightning") { Category = "3 - Arrows", Description = "Adds new lightning arrows", EnabledByDefault = false, AssetPath = "Assets/PrefabInstance/ArrowLightning.prefab", Type = FeatureType.Arrow, Amount = 20, Table = "BlackForge", MinTableLevel = 2, Requirements = "Wood:8,Feathers:2,Eitr:1", Damages = "Pierce:36,Lightning:62", DependencyNames = new List<string> { "sfx_lightning_hit.prefab", "arbalest_projectile_lightning.prefab" } }); _features.Add(new FeatureItem("BoltOoze") { Category = "5 - Area Effect Bolts", Description = "Adds new Ooze bomb bolts. These cause the same Ooze explosions as bombs. Damage set here is applied to both projectile & explosion.", EnabledByDefault = false, AssetPath = "Assets/PrefabInstance/BoltOoze.prefab", Type = FeatureType.Bolt, Amount = 10, Table = "Workbench", MinTableLevel = 1, Requirements = "Wood:4,Feathers:1,LeatherScraps:5,Ooze:5", Damages = "Pierce:5,Poison:40", AoePrefabName = "oozebomb_explosion", DependencyNames = new List<string> { "arbalest_projectile_ooze.prefab" } }); _features.Add(new FeatureItem("BoltSurtling") { Category = "5 - Area Effect Bolts", Description = "Adds new Surtling bolts. Damage set here is applied to both projectile & explosion.", EnabledByDefault = false, AssetPath = "Assets/PrefabInstance/BoltSurtling.prefab", Type = FeatureType.Bolt, Amount = 10, Table = "Forge", MinTableLevel = 4, Requirements = "Wood:4,Feathers:1,SurtlingCore:3,Iron:1", Damages = "Pierce:22,Fire:18", AoePrefabName = "firebolt_explosion", DependencyNames = new List<string> { "arbalest_projectile_surtling.prefab", "firebolt_explosion.prefab" } }); _features.Add(new FeatureItem("BoltBile") { Category = "5 - Area Effect Bolts", Description = "Adds new Bile bomb bolts. These cause the same Bile explosions as bombs. Damage set here is applied to both projectile & explosion.", EnabledByDefault = false, AssetPath = "Assets/PrefabInstance/BoltBile.prefab", Type = FeatureType.Bolt, Amount = 10, Table = "Workbench", MinTableLevel = 1, Requirements = "Wood:4,Feathers:1,Sap:3,Bilebag:3", Damages = "Pierce:22,Fire:15,Poison:30", AoePrefabName = "bilebomb_explosion", DependencyNames = new List<string> { "arbalest_projectile_bile.prefab" } }); _features.Add(new FeatureItem("BoltIce") { Category = "5 - Area Effect Bolts", Description = "Adds new Ice bolts which strike an area with frost damage. Damage set here is SPLIT between projectile & explosion.", EnabledByDefault = false, AssetPath = "Assets/PrefabInstance/BoltIce.prefab", Type = FeatureType.Bolt, Amount = 10, Table = "Forge", MinTableLevel = 4, Requirements = "Wood:4,Feathers:1,FreezeGland:3,BlackMetal:1", Damages = "Pierce:22,Frost:62", AoePrefabName = "icebolt_explosion", DependencyNames = new List<string> { "arbalest_projectile_ice.prefab", "icebolt_explosion.prefab" } }); _features.Add(new FeatureItem("BoltFlametal") { Category = "5 - Area Effect Bolts", Description = "Adds new Flametal bolts. Hits all targets very hard. Damage set here is applied ONLY to projectile.", EnabledByDefault = false, AssetPath = "Assets/PrefabInstance/BoltFlametal.prefab", Type = FeatureType.Bolt, Amount = 10, Table = "BlackForge", MinTableLevel = 2, Requirements = "FlametalNew:1,Feathers:1,Eitr:3,SurtlingCore:3", Damages = "Blunt:22,Pierce:22,Fire:102", DependencyNames = new List<string> { "arbalest_projectile_flametal.prefab", "firebolt_explosion.prefab" } }); _features.Add(new FeatureRecipe("BoltBone") { Category = "4 - Bolts", Description = "Enables bone bolts to be craftable earlier", EnabledByDefault = true, Type = FeatureType.Bolt, Table = "Workbench", MinTableLevel = 2, Requirements = "BoneFragments:8,Feathers:2", Amount = 20 }); _features.Add(new FeatureRecipe("BoltIron") { Category = "4 - Bolts", Description = "Enables iron bolts to be craftable earlier", EnabledByDefault = true, Type = FeatureType.Bolt, Table = "Forge", MinTableLevel = 2, Requirements = "Wood:8,Iron:1,Feathers:2", Amount = 20 }); _features.Add(new FeatureRecipe("BoltBlackmetal") { Category = "4 - Bolts", Description = "Enables blackmetal bolts to be craftable earlier", EnabledByDefault = true, Type = FeatureType.Bolt, Table = "Forge", MinTableLevel = 4, Requirements = "Wood:8,BlackMetal:2,Feathers:2", Amount = 20 }); foreach (Feature feature in _features) { feature.Initialize(); } } ConfigFile IPlugin.get_Config() { return ((BaseUnityPlugin)this).Config; } } public static class TooltipHelper { public static string Damage(float damage) { return string.Concat(new string[3] { "<color=orange>", Mathf.RoundToInt(damage).ToString(), "</color>" }); } public static string GetAoeTooltipForItem(ItemData item, Aoe aoe) { StringBuilder stringBuilder = new StringBuilder(256); stringBuilder.Append(Environment.NewLine + Environment.NewLine + "$area_of_effect "); int num = Mathf.RoundToInt(aoe.m_hitInterval); if ((float)num * 2f < aoe.m_ttl) { if (num == 1) { stringBuilder.Append("($per_second) "); } else if (num >= 2) { stringBuilder.Append("($every " + num + " $seconds) "); } } if (aoe.m_damage.m_damage != 0f) { stringBuilder.Append(Environment.NewLine + "$inventory_damage: " + Damage(aoe.m_damage.m_damage)); } if (aoe.m_damage.m_blunt != 0f) { stringBuilder.Append(Environment.NewLine + "$inventory_blunt: " + Damage(aoe.m_damage.m_blunt)); } if (aoe.m_damage.m_slash != 0f) { stringBuilder.Append(Environment.NewLine + "$inventory_slash: " + Damage(aoe.m_damage.m_slash)); } if (aoe.m_damage.m_pierce != 0f) { stringBuilder.Append(Environment.NewLine + "$inventory_pierce: " + Damage(aoe.m_damage.m_pierce)); } if (aoe.m_damage.m_fire != 0f) { stringBuilder.Append(Environment.NewLine + "$inventory_fire: " + Damage(aoe.m_damage.m_fire)); } if (aoe.m_damage.m_frost != 0f) { stringBuilder.Append(Environment.NewLine + "$inventory_frost: " + Damage(aoe.m_damage.m_frost)); } if (aoe.m_damage.m_lightning != 0f) { stringBuilder.Append(Environment.NewLine + "$inventory_lightning: " + Damage(aoe.m_damage.m_lightning)); } if (aoe.m_damage.m_poison != 0f) { stringBuilder.Append(Environment.NewLine + "$inventory_poison: " + Damage(aoe.m_damage.m_poison)); } if (aoe.m_damage.m_spirit != 0f) { stringBuilder.Append(Environment.NewLine + "$inventory_spirit: " + Damage(aoe.m_damage.m_spirit)); } return stringBuilder.ToString(); } } [Flags] public enum VisualEffectCondition : uint { IsSkill = 0xFFFu, Swords = 1u, Knives = 2u, Clubs = 3u, Polearms = 4u, Spears = 5u, Blocking = 6u, Axes = 7u, Bows = 8u, Unarmed = 0xBu, Pickaxes = 0xCu, WoodCutting = 0xDu, Crossbows = 0xEu, IsItem = 0xFF000u, Helmet = 0x6000u, Chest = 0x7000u, Legs = 0xB000u, Hands = 0xC000u, Shoulder = 0x11000u, Tool = 0x13000u, GenericExtraAttributes = 0xFF000000u, Blackmetal = 0x40000000u, TwoHanded = 0x80000000u, SpecificExtraAttributes = 0xF00000u, Hammer = 0x113000u, Hoe = 0x213000u, Buckler = 0x100006u, Towershield = 0x200006u, FineWoodBow = 0x100008u, BowHuntsman = 0x200008u, BowDraugrFang = 0x300008u, Arbalest = 0x10000Eu, CrossbowWood = 0x20000Eu, CrossbowBronze = 0x30000Eu, CrossbowIron = 0x40000Eu, CrossbowSilver = 0x50000Eu, CrossbowBlackmetal = 0x60000Eu, PickaxeIron = 0x10000Cu, Club = 0x100003u } }