using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Timers; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using IniParser; using IniParser.Model; using JetBrains.Annotations; using PlayFab.MultiplayerModels; using PlayFab.Party; using ServerSync; using Splatform; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; using Valheim.SettingsGui; using ValheimPlus.Configurations; using ValheimPlus.Configurations.Sections; using ValheimPlus.GameClasses; using ValheimPlus.Http; using ValheimPlus.RPC; using ValheimPlus.Utility; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ValheimPlus")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ValheimPlus")] [assembly: AssemblyCopyright("")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("2a837100-a030-4d0c-bffb-b38356118d9a")] [assembly: AssemblyFileVersion("0.10.1.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.10.1.0")] [module: UnverifiableCode] internal sealed class ConfigurationManagerAttributes { public delegate void CustomHotkeyDrawerFunc(ConfigEntryBase setting, ref bool isCurrentlyAcceptingInput); public bool? ShowRangeAsPercent; public Action CustomDrawer; public CustomHotkeyDrawerFunc CustomHotkeyDrawer; public bool? Browsable; public string Category; public object DefaultValue; public bool? HideDefaultButton; public bool? HideSettingName; public string Description; public string DispName; public int? Order; public bool? ReadOnly; public bool? IsAdvanced; public Func ObjToStr; public Func StrToObj; } public static class ZNetExtensions { public enum ZNetInstanceType { Local, Client, Server } public static bool IsLocalInstance(this ZNet znet) { if (znet.IsServer()) { return !znet.IsDedicated(); } return false; } public static bool IsClientInstance(this ZNet znet) { if (!znet.IsServer()) { return !znet.IsDedicated(); } return false; } public static bool IsServerInstance(this ZNet znet) { if (znet.IsServer()) { return znet.IsDedicated(); } return false; } public static ZNetInstanceType GetInstanceType(this ZNet znet) { if (znet.IsLocalInstance()) { return ZNetInstanceType.Local; } if (znet.IsClientInstance()) { return ZNetInstanceType.Client; } return ZNetInstanceType.Server; } } namespace ValheimPlus { internal class ABM { public static bool isActive; private static Player PlayerInstance; private static bool controlFlag; private static bool shiftFlag; private static bool altFlag; public static bool exitOnNextIteration; private static Piece component; private const float BASE_TRANSLATION_DISTANCE = 0.1f; private const float BASE_ROTATION_ANGLE_DEGREES = 3f; private static float currentModificationSpeed = 1f; private const float MIN_MODIFICATION_SPEED = 1f; private const float MAX_MODIFICATION_SPEED = 30f; private static Quaternion savedRotation; public static void Run(ref Player __instance) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) PlayerInstance = __instance; if (AEM.isActive) { if (isActive) { exitMode(); } return; } if (Input.GetKeyDown(Configuration.Current.AdvancedBuildingMode.exitAdvancedBuildingMode)) { if (isActive) { exitMode(); } return; } if (exitOnNextIteration) { isActive = false; exitOnNextIteration = false; component = null; } if (isActive && (Object)(object)component == (Object)null) { exitMode(); } else if ((Object)(object)selectedPrefab() == (Object)null || (Object)(object)PlayerInstance.m_placementGhost == (Object)null) { if (isActive) { exitMode(); } } else if (isInBuildMode() && IsHoeOrTerrainTool(selectedPrefab())) { if (isActive) { exitMode(); } } else if (isActive) { if (Vector3.Distance(((Component)PlayerInstance).transform.position, ((Component)component).transform.position) > PlayerInstance.m_maxPlaceDistance) { exitMode(); } isRunning(); listenToHotKeysAndDoWork(); } else if (Input.GetKeyDown(Configuration.Current.AdvancedBuildingMode.enterAdvancedBuildingMode)) { startMode(); } } private static void listenToHotKeysAndDoWork() { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: 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_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0378: Unknown result type (might be due to invalid IL or missing references) //IL_037f: Unknown result type (might be due to invalid IL or missing references) //IL_035b: Unknown result type (might be due to invalid IL or missing references) //IL_0362: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) //IL_0319: Unknown result type (might be due to invalid IL or missing references) //IL_031e: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_032a: Unknown result type (might be due to invalid IL or missing references) //IL_03ea: Unknown result type (might be due to invalid IL or missing references) //IL_03f1: Unknown result type (might be due to invalid IL or missing references) //IL_03c3: Unknown result type (might be due to invalid IL or missing references) //IL_03ca: Unknown result type (might be due to invalid IL or missing references) //IL_03a6: Unknown result type (might be due to invalid IL or missing references) //IL_03ad: Unknown result type (might be due to invalid IL or missing references) //IL_0411: Unknown result type (might be due to invalid IL or missing references) //IL_0418: Unknown result type (might be due to invalid IL or missing references) float num = 0f; float num2 = 0f; float num3 = 0f; if (Input.GetKeyDown((KeyCode)306)) { controlFlag = true; } if (Input.GetKeyUp((KeyCode)306)) { controlFlag = false; } if (Input.GetKeyDown((KeyCode)304)) { shiftFlag = true; } if (Input.GetKeyUp((KeyCode)304)) { shiftFlag = false; } if (Input.GetKeyDown((KeyCode)308)) { altFlag = true; } if (Input.GetKeyUp((KeyCode)308)) { altFlag = false; } changeModificationSpeed(); if (Input.GetKeyUp(Configuration.Current.AdvancedBuildingMode.copyObjectRotation)) { savedRotation = ((Component)component).transform.rotation; } if (Input.GetKeyUp(Configuration.Current.AdvancedBuildingMode.pasteObjectRotation)) { ((Component)component).transform.rotation = savedRotation; } float num4 = 3f * currentModificationSpeed; if (Input.GetAxis("Mouse ScrollWheel") > 0f) { Quaternion rotation; if (controlFlag) { num += 1f; rotation = Quaternion.Euler(((Component)component).transform.eulerAngles.x + num4 * num, ((Component)component).transform.eulerAngles.y, ((Component)component).transform.eulerAngles.z); } else if (altFlag) { num2 += 1f; rotation = Quaternion.Euler(((Component)component).transform.eulerAngles.x, ((Component)component).transform.eulerAngles.y, ((Component)component).transform.eulerAngles.z + num4 * num2); } else { num3 += 1f; rotation = Quaternion.Euler(((Component)component).transform.eulerAngles.x, ((Component)component).transform.eulerAngles.y + num4 * num3, ((Component)component).transform.eulerAngles.z); } ((Component)component).transform.rotation = rotation; } if (Input.GetAxis("Mouse ScrollWheel") < 0f) { Quaternion rotation2; if (controlFlag) { num -= 1f; rotation2 = Quaternion.Euler(((Component)component).transform.eulerAngles.x + num4 * num, ((Component)component).transform.eulerAngles.y, ((Component)component).transform.eulerAngles.z); } else if (altFlag) { num2 -= 1f; rotation2 = Quaternion.Euler(((Component)component).transform.eulerAngles.x, ((Component)component).transform.eulerAngles.y, ((Component)component).transform.eulerAngles.z + num4 * num2); } else { num3 -= 1f; rotation2 = Quaternion.Euler(((Component)component).transform.eulerAngles.x, ((Component)component).transform.eulerAngles.y + num4 * num3, ((Component)component).transform.eulerAngles.z); } ((Component)component).transform.rotation = rotation2; } float num5 = 0.1f * currentModificationSpeed; if (Input.GetKeyDown((KeyCode)273)) { if (controlFlag) { ((Component)component).transform.Translate(Vector3.up * num5); } else { ((Component)component).transform.Translate(Vector3.forward * num5); } } if (Input.GetKeyDown((KeyCode)274)) { if (controlFlag) { ((Component)component).transform.Translate(Vector3.down * num5); } else { ((Component)component).transform.Translate(Vector3.back * num5); } } if (Input.GetKeyDown((KeyCode)276)) { ((Component)component).transform.Translate(Vector3.left * num5); } if (Input.GetKeyDown((KeyCode)275)) { ((Component)component).transform.Translate(Vector3.right * num5); } try { isValidPlacement(); } catch { } } private static void isValidPlacement() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) PlayerInstance.m_placementStatus = (PlacementStatus)0; if (component.m_groundOnly || component.m_groundPiece || component.m_cultivatedGroundOnly) { PlayerInstance.m_placementMarkerInstance.SetActive(false); } StationExtension val = ((Component)component).GetComponent(); if ((Object)(object)val != (Object)null) { CraftingStation val2 = val.FindClosestStationInRange(((Component)component).transform.position); if (Object.op_Implicit((Object)(object)val2)) { val.StartConnectionEffect(val2, 1f); } else { val.StopConnectionEffect(); PlayerInstance.m_placementStatus = (PlacementStatus)7; } if (val.OtherExtensionInRange(component.m_spaceRequirement)) { PlayerInstance.m_placementStatus = (PlacementStatus)5; } } if (component.m_onlyInTeleportArea && !Object.op_Implicit((Object)(object)EffectArea.IsPointInsideArea(((Component)component).transform.position, (Type)16, 0f))) { PlayerInstance.m_placementStatus = (PlacementStatus)6; } if (!component.m_allowedInDungeons && ((Component)component).transform.position.y > 3000f) { PlayerInstance.m_placementStatus = (PlacementStatus)11; } if (Location.IsInsideNoBuildLocation(PlayerInstance.m_placementGhost.transform.position)) { PlayerInstance.m_placementStatus = (PlacementStatus)3; } float num = (Object.op_Implicit((Object)(object)((Component)component).GetComponent()) ? ((Component)component).GetComponent().m_radius : 0f); if (!PrivateArea.CheckAccess(PlayerInstance.m_placementGhost.transform.position, num, true, false)) { PlayerInstance.m_placementStatus = (PlacementStatus)4; } if ((int)PlayerInstance.m_placementStatus != 0) { component.SetInvalidPlacementHeightlight(true); } else { component.SetInvalidPlacementHeightlight(false); } } private static void startMode() { notifyUser("Starting ABM", (MessageType)1); isActive = true; component = PlayerInstance.m_placementGhost.GetComponent(); } private static void exitMode() { notifyUser("Exiting ABM", (MessageType)1); exitOnNextIteration = true; isActive = false; component = null; } private static bool isInBuildMode() { return ((Character)PlayerInstance).InPlaceMode(); } private static GameObject selectedPrefab() { if ((Object)(object)PlayerInstance.m_buildPieces != (Object)null) { try { return PlayerInstance.m_buildPieces.GetSelectedPrefab(); } catch { return null; } } return null; } private static bool IsHoeOrTerrainTool(GameObject selectedPrefab) { string[] source = new string[4] { "paved_road", "mud_road", "raise", "path" }; string[] source2 = new string[2] { "cultivate", "replant" }; if (((Object)selectedPrefab).name.ToLower().Contains("sapling")) { return true; } if (source.Contains(((Object)selectedPrefab).name) || source2.Contains(((Object)selectedPrefab).name)) { return true; } return false; } private static void notifyUser(string Message, MessageType position = (MessageType)1) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) MessageHud.instance.ShowMessage(position, "ABM: " + Message, 0, (Sprite)null, false, true); } private static void isRunning() { if (isActive) { MessageHud.instance.ShowMessage((MessageType)2, "ABM is active", 0, (Sprite)null, false, true); } } private static void changeModificationSpeed() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) float num = 1f; if (shiftFlag) { num = 10f; } if (Input.GetKeyDown(Configuration.Current.AdvancedBuildingMode.increaseScrollSpeed)) { currentModificationSpeed = Mathf.Clamp(currentModificationSpeed + num, 1f, 30f); notifyUser("Modification Speed: " + currentModificationSpeed, (MessageType)1); } if (Input.GetKeyDown(Configuration.Current.AdvancedBuildingMode.decreaseScrollSpeed)) { currentModificationSpeed = Mathf.Clamp(currentModificationSpeed - num, 1f, 30f); notifyUser("Modification Speed: " + currentModificationSpeed, (MessageType)1); } } } internal class AEM { public static bool isActive; public static Player PlayerInstance; private static bool controlFlag; private static bool shiftFlag; private static bool altFlag; public static Vector3 HitPoint; public static Vector3 HitNormal; public static Piece HitPiece; public static GameObject HitObject; public static Heightmap HitHeightmap; private static Quaternion InitialRotation; private static Vector3 InitialPosition; private static bool isInExistence; private const float BASE_TRANSLATION_DISTANCE = 0.1f; private const float BASE_ROTATION_ANGLE_DEGREES = 3f; private static float currentModificationSpeed = 1f; private const float MIN_MODIFICATION_SPEED = 1f; private const float MAX_MODIFICATION_SPEED = 30f; private static Quaternion savedRotation; public static bool forceExitNextIteration; public static bool ExecuteRayCast(Player playerInstance) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) int placeRayMask = playerInstance.m_placeRayMask; RaycastHit val = default(RaycastHit); if (Physics.Raycast(((Component)GameCamera.instance).transform.position, ((Component)GameCamera.instance).transform.forward, ref val, 50f, placeRayMask) && Object.op_Implicit((Object)(object)((RaycastHit)(ref val)).collider) && !Object.op_Implicit((Object)(object)((RaycastHit)(ref val)).collider.attachedRigidbody) && Vector3.Distance(Helper.getPlayerCharacter(playerInstance).m_eye.position, ((RaycastHit)(ref val)).point) < playerInstance.m_maxPlaceDistance) { HitPoint = ((RaycastHit)(ref val)).point; HitNormal = ((RaycastHit)(ref val)).normal; HitPiece = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent(); HitObject = ((Component)((RaycastHit)(ref val)).collider).gameObject; HitHeightmap = ((Component)((RaycastHit)(ref val)).collider).GetComponent(); InitialRotation = ((Component)HitPiece).transform.rotation; InitialPosition = ((Component)HitPiece).transform.position; return isValidRayCastTarget(); } resetObjectInfo(); return false; } public static bool checkForObject() { if ((Object)(object)PlayerInstance == (Object)null) { return false; } if (!ExecuteRayCast(PlayerInstance)) { return false; } return true; } public static void run() { //IL_005c: 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) if (forceExitNextIteration) { forceExitNextIteration = false; resetObjectInfo(); isActive = false; } else if (isInBuildMode()) { if (isActive) { exitMode(); resetObjectTransform(); } } else if (ABM.isActive) { if (isActive) { exitMode(); resetObjectTransform(); } } else if (!isActive && Input.GetKeyDown(Configuration.Current.AdvancedEditingMode.enterAdvancedEditingMode)) { if (checkForObject()) { startMode(); } } else if (isActive && Input.GetKeyDown(Configuration.Current.AdvancedEditingMode.abortAndExitAdvancedEditingMode)) { resetObjectTransform(); exitMode(); } else { if (!isActive) { return; } if (hitPieceStillExists()) { try { if ((Object)(object)((Component)HitPiece).GetComponent() == (Object)null) { ValheimPlusPlugin.Logger.LogWarning((object)"AEM: Error, network object empty. Code: 2."); exitMode(); return; } } catch { ValheimPlusPlugin.Logger.LogWarning((object)"AEM: Error, network object empty. Code: 3."); exitMode(); } isRunning(); listenToHotKeysAndDoWork(); } else { exitMode(); } } } private static void listenToHotKeysAndDoWork() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_0384: Unknown result type (might be due to invalid IL or missing references) //IL_039c: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: Unknown result type (might be due to invalid IL or missing references) //IL_03ba: Unknown result type (might be due to invalid IL or missing references) //IL_03bf: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_0335: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Unknown result type (might be due to invalid IL or missing references) //IL_0344: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_02ee: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_0350: Unknown result type (might be due to invalid IL or missing references) //IL_04c5: Unknown result type (might be due to invalid IL or missing references) //IL_04cc: Unknown result type (might be due to invalid IL or missing references) //IL_04a8: Unknown result type (might be due to invalid IL or missing references) //IL_04af: Unknown result type (might be due to invalid IL or missing references) //IL_0430: Unknown result type (might be due to invalid IL or missing references) //IL_0444: Unknown result type (might be due to invalid IL or missing references) //IL_045c: Unknown result type (might be due to invalid IL or missing references) //IL_0466: Unknown result type (might be due to invalid IL or missing references) //IL_046b: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Unknown result type (might be due to invalid IL or missing references) //IL_03f3: Unknown result type (might be due to invalid IL or missing references) //IL_0407: Unknown result type (might be due to invalid IL or missing references) //IL_0415: Unknown result type (might be due to invalid IL or missing references) //IL_041a: Unknown result type (might be due to invalid IL or missing references) //IL_0477: Unknown result type (might be due to invalid IL or missing references) //IL_0537: Unknown result type (might be due to invalid IL or missing references) //IL_053e: Unknown result type (might be due to invalid IL or missing references) //IL_0510: Unknown result type (might be due to invalid IL or missing references) //IL_0517: Unknown result type (might be due to invalid IL or missing references) //IL_04f3: Unknown result type (might be due to invalid IL or missing references) //IL_04fa: Unknown result type (might be due to invalid IL or missing references) //IL_055e: Unknown result type (might be due to invalid IL or missing references) //IL_0565: Unknown result type (might be due to invalid IL or missing references) float num = 0f; float num2 = 0f; float num3 = 0f; if (Input.GetKeyDown(Configuration.Current.AdvancedEditingMode.resetAdvancedEditingMode)) { resetObjectTransform(); } if (Input.GetKeyDown(Configuration.Current.AdvancedEditingMode.confirmPlacementOfAdvancedEditingMode)) { if (isContainer()) { dropContainerContents(); } GameObject val = Object.Instantiate(((Component)HitPiece).gameObject, ((Component)HitPiece).transform.position, ((Component)HitPiece).transform.rotation); HitPiece.m_placeEffect.Create(((Component)HitPiece).transform.position, ((Component)HitPiece).transform.rotation, val.transform, 1f, -1, default(ZDOID)); ZNetView component = ((Component)HitPiece).GetComponent(); if ((Object)(object)component == (Object)null) { ValheimPlusPlugin.Logger.LogWarning((object)"AEM: Error, network object empty."); resetObjectTransform(); exitMode(); } else { component.ClaimOwnership(); ZNetScene.instance.Destroy(((Component)HitPiece).gameObject); ValheimPlusPlugin.Logger.LogDebug((object)"AEM: Executed."); exitMode(); } return; } if (Input.GetKeyDown((KeyCode)306)) { controlFlag = true; } if (Input.GetKeyUp((KeyCode)306)) { controlFlag = false; } if (Input.GetKeyDown((KeyCode)304)) { shiftFlag = true; } if (Input.GetKeyUp((KeyCode)304)) { shiftFlag = false; } if (Input.GetKeyDown((KeyCode)308)) { altFlag = true; } if (Input.GetKeyUp((KeyCode)308)) { altFlag = false; } changeModificationSpeed(); if (Input.GetKeyUp(Configuration.Current.AdvancedEditingMode.copyObjectRotation)) { savedRotation = ((Component)HitPiece).transform.rotation; } if (Input.GetKeyUp(Configuration.Current.AdvancedEditingMode.pasteObjectRotation)) { ((Component)HitPiece).transform.rotation = savedRotation; } if (Vector3.Distance(((Component)PlayerInstance).transform.position, ((Component)HitPiece).transform.position) > PlayerInstance.m_maxPlaceDistance) { resetObjectTransform(); exitMode(); } float num4 = 3f * currentModificationSpeed; if (Input.GetAxis("Mouse ScrollWheel") > 0f) { Quaternion rotation; if (controlFlag) { num += 1f; rotation = Quaternion.Euler(((Component)HitPiece).transform.eulerAngles.x + num4 * num, ((Component)HitPiece).transform.eulerAngles.y, ((Component)HitPiece).transform.eulerAngles.z); } else if (altFlag) { num2 += 1f; rotation = Quaternion.Euler(((Component)HitPiece).transform.eulerAngles.x, ((Component)HitPiece).transform.eulerAngles.y, ((Component)HitPiece).transform.eulerAngles.z + num4 * num2); } else { num3 += 1f; rotation = Quaternion.Euler(((Component)HitPiece).transform.eulerAngles.x, ((Component)HitPiece).transform.eulerAngles.y + num4 * num3, ((Component)HitPiece).transform.eulerAngles.z); } ((Component)HitPiece).transform.rotation = rotation; } if (Input.GetAxis("Mouse ScrollWheel") < 0f) { Quaternion rotation2; if (controlFlag) { num -= 1f; rotation2 = Quaternion.Euler(((Component)HitPiece).transform.eulerAngles.x + num4 * num, ((Component)HitPiece).transform.eulerAngles.y, ((Component)HitPiece).transform.eulerAngles.z); } else if (altFlag) { num2 -= 1f; rotation2 = Quaternion.Euler(((Component)HitPiece).transform.eulerAngles.x, ((Component)HitPiece).transform.eulerAngles.y, ((Component)HitPiece).transform.eulerAngles.z + num4 * num2); } else { num3 -= 1f; rotation2 = Quaternion.Euler(((Component)HitPiece).transform.eulerAngles.x, ((Component)HitPiece).transform.eulerAngles.y + num4 * num3, ((Component)HitPiece).transform.eulerAngles.z); } ((Component)HitPiece).transform.rotation = rotation2; } float num5 = 0.1f * currentModificationSpeed; if (Input.GetKeyDown((KeyCode)273)) { if (controlFlag) { ((Component)HitPiece).transform.Translate(Vector3.up * num5); } else { ((Component)HitPiece).transform.Translate(Vector3.forward * num5); } } if (Input.GetKeyDown((KeyCode)274)) { if (controlFlag) { ((Component)HitPiece).transform.Translate(Vector3.down * num5); } else { ((Component)HitPiece).transform.Translate(Vector3.back * num5); } } if (Input.GetKeyDown((KeyCode)276)) { ((Component)HitPiece).transform.Translate(Vector3.left * num5); } if (Input.GetKeyDown((KeyCode)275)) { ((Component)HitPiece).transform.Translate(Vector3.right * num5); } } private static bool hitPieceStillExists() { try { if (isActive) { isInExistence = true; } } catch { isInExistence = false; } return isInExistence; } private static bool isValidRayCastTarget() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_00a5: Unknown result type (might be due to invalid IL or missing references) bool result = true; if (HitPiece.m_onlyInTeleportArea && !Object.op_Implicit((Object)(object)EffectArea.IsPointInsideArea(((Component)HitPiece).transform.position, (Type)16, 0f))) { result = false; } if (!HitPiece.m_allowedInDungeons && ((Component)HitPiece).transform.position.y > 3000f) { result = false; } if (Location.IsInsideNoBuildLocation(((Component)HitPiece).transform.position)) { result = false; } float num = (Object.op_Implicit((Object)(object)((Component)HitPiece).GetComponent()) ? ((Component)HitPiece).GetComponent().m_radius : 0f); if (!PrivateArea.CheckAccess(((Component)HitPiece).transform.position, num, true, false)) { result = false; } return result; } private static bool isInBuildMode() { return ((Character)PlayerInstance).InPlaceMode(); } private static void resetObjectTransform() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)HitPiece == (Object)null) { resetObjectInfo(); return; } notifyUser("Object has been reset to initial position & rotation.", (MessageType)1); ((Component)HitPiece).transform.position = InitialPosition; ((Component)HitPiece).transform.rotation = InitialRotation; } private static void resetObjectInfo() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) HitPoint = Vector3.zero; HitNormal = Vector3.zero; HitObject = null; HitPiece = null; HitHeightmap = null; InitialRotation = default(Quaternion); InitialPosition = default(Vector3); } private static void startMode() { notifyUser("Entering AEM", (MessageType)1); isActive = true; } private static void exitMode() { notifyUser("Exiting AEM", (MessageType)1); forceExitNextIteration = true; } private static void notifyUser(string Message, MessageType position = (MessageType)1) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) MessageHud.instance.ShowMessage(position, "AEM: " + Message, 0, (Sprite)null, false, true); } private static void isRunning() { if (isActive) { MessageHud.instance.ShowMessage((MessageType)2, "AEM is active", 0, (Sprite)null, false, true); } } private static bool isContainer() { return (Object)(object)((Component)HitPiece).GetComponent() != (Object)null; } private static void dropContainerContents() { ((Component)HitPiece).GetComponent().DropAllItems(); } private static void changeModificationSpeed() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) float num = 1f; if (shiftFlag) { num = 10f; } if (Input.GetKeyDown(Configuration.Current.AdvancedEditingMode.increaseScrollSpeed)) { currentModificationSpeed = Mathf.Clamp(currentModificationSpeed + num, 1f, 30f); notifyUser("Modification Speed: " + currentModificationSpeed, (MessageType)1); } if (Input.GetKeyDown(Configuration.Current.AdvancedEditingMode.decreaseScrollSpeed)) { currentModificationSpeed = Mathf.Clamp(currentModificationSpeed - num, 1f, 30f); notifyUser("Modification Speed: " + currentModificationSpeed, (MessageType)1); } } } [HarmonyPatch(typeof(Player), "UpdatePlacementGhost")] public static class Player_UpdatePlacementGhost_Transpile { private static readonly MethodInfo Method_Quaternion_Euler = AccessTools.Method(typeof(Quaternion), "Euler", new Type[3] { typeof(float), typeof(float), typeof(float) }, (Type[])null); private static readonly MethodInfo Method_GetRotation = AccessTools.Method(typeof(Player_UpdatePlacementGhost_Transpile), "GetRotation", (Type[])null, (Type[])null); [UsedImplicitly] [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown if (!Configuration.Current.FreePlacementRotation.IsEnabled) { return instructions; } List list = instructions.ToList(); for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], Method_Quaternion_Euler) && list[i + 1].opcode == OpCodes.Stloc_S) { object operand = list[i + 1].operand; list.InsertRange(i + 2, (IEnumerable)(object)new CodeInstruction[4] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldloc_S, operand), new CodeInstruction(OpCodes.Call, (object)Method_GetRotation), new CodeInstruction(OpCodes.Stloc_S, operand) }); return list.AsEnumerable(); } } PatchLog.Failed("Player_UpdatePlacementGhost_Transpile", "Free placement rotation will not work."); return list.AsEnumerable(); } public static Quaternion GetRotation(Player __instance, Quaternion quaternion) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) if (ABM.isActive) { return quaternion; } FreePlacementRotation.PlayerData value; return Quaternion.Euler(FreePlacementRotation.PlayersData.TryGetValue(__instance, out value) ? value.PlaceRotation : ((float)__instance.m_placeRotation * 22.5f * Vector3.up)); } } public static class FreePlacementRotation { public class PlayerData { public Vector3 PlaceRotation = Vector3.zero; public bool Opposite; public Piece LastPiece; public KeyCode LastKeyCode; } [HarmonyPatch(typeof(Player), "UpdatePlacement")] public static class ModifyPUpdatePlacement { [UsedImplicitly] private static void Postfix(Player __instance, bool takeInput, float dt) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) FreePlacementRotationConfiguration freePlacementRotation = Configuration.Current.FreePlacementRotation; if (freePlacementRotation.IsEnabled && !ABM.isActive && ((Character)__instance).InPlaceMode() && takeInput && !Hud.IsPieceSelectionVisible()) { if (!PlayersData.ContainsKey(__instance)) { PlayersData[__instance] = new PlayerData(); } RotateWithWheel(__instance); SyncRotationWithTargetInFront(__instance, freePlacementRotation.copyRotationParallel, perpendicular: false); SyncRotationWithTargetInFront(__instance, freePlacementRotation.copyRotationPerpendicular, perpendicular: true); } } private static void RotateWithWheel(Player __instance) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) float axis = Input.GetAxis("Mouse ScrollWheel"); PlayerData playerData = PlayersData[__instance]; if (!axis.Equals(0f) || ZInput.GetButton("JoyRotate")) { if (Input.GetKey(Configuration.Current.FreePlacementRotation.rotateY)) { playerData.PlaceRotation += Vector3.up * Mathf.Sign(axis); __instance.m_placeRotation = (int)(playerData.PlaceRotation.y / 22.5f); } else if (Input.GetKey(Configuration.Current.FreePlacementRotation.rotateX)) { playerData.PlaceRotation += Vector3.right * Mathf.Sign(axis); } else if (Input.GetKey(Configuration.Current.FreePlacementRotation.rotateZ)) { playerData.PlaceRotation += Vector3.forward * Mathf.Sign(axis); } else { __instance.m_placeRotation = ClampPlaceRotation(__instance.m_placeRotation); playerData.PlaceRotation = new Vector3(0f, (float)__instance.m_placeRotation * 22.5f, 0f); } playerData.PlaceRotation = ClampAngles(playerData.PlaceRotation); } } private static void SyncRotationWithTargetInFront(Player __instance, KeyCode keyCode, bool perpendicular) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_008b: Unknown result type (might be due to invalid IL or missing references) //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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) Vector3 val = default(Vector3); Vector3 val2 = default(Vector3); Piece val3 = default(Piece); Heightmap val4 = default(Heightmap); Collider val5 = default(Collider); if (!((Object)(object)__instance.m_placementGhost == (Object)null) && Input.GetKeyUp(keyCode) && __instance.PieceRayTest(ref val, ref val2, ref val3, ref val4, ref val5, false) && !((Object)(object)val3 == (Object)null)) { PlayerData playerData = PlayersData[__instance]; Quaternion val6 = ((Component)val3).transform.rotation; if (perpendicular) { val6 *= Quaternion.Euler(0f, 90f, 0f); } if (playerData.LastKeyCode != keyCode || (Object)(object)playerData.LastPiece != (Object)(object)val3) { playerData.Opposite = false; } playerData.LastKeyCode = keyCode; playerData.LastPiece = val3; if (playerData.Opposite) { val6 *= Quaternion.Euler(0f, 180f, 0f); } playerData.Opposite = !playerData.Opposite; playerData.PlaceRotation = ((Quaternion)(ref val6)).eulerAngles; } } } public static readonly Dictionary PlayersData = new Dictionary(); private const int MaxIndex = 16; private static Vector3 ClampAngles(Vector3 angles) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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) return new Vector3(ClampAngle(angles.x), ClampAngle(angles.y), ClampAngle(angles.z)); } private static int ClampPlaceRotation(int index) { if (index >= 0) { if (index >= 16) { return index - 16; } return index; } return 16 + index; } private static float ClampAngle(float angle) { if (!(angle < 0f)) { if (angle >= 360f) { return angle - 360f; } return angle; } return 360f + angle; } } [HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")] public static class CharacterDrop_GenerateDropList_Patch { private static void Prefix(ref List ___m_drops, ref List __state) { if (Configuration.Current.LootDrop.IsEnabled) { __state = ___m_drops; ItemDrop val = default(ItemDrop); ___m_drops = ___m_drops.ConvertAll((Drop originalDrop) => (Drop)(originalDrop.m_prefab.TryGetComponent(ref val) ? ((object)new Drop { m_prefab = originalDrop.m_prefab, m_amountMin = (int)Helper.applyModifierValue(originalDrop.m_amountMin, Configuration.Current.LootDrop.lootDropAmountMultiplier), m_amountMax = (int)Helper.applyModifierValue(originalDrop.m_amountMax, Configuration.Current.LootDrop.lootDropAmountMultiplier), m_chance = Helper.applyModifierValue(originalDrop.m_chance, Configuration.Current.LootDrop.lootDropChanceMultiplier), m_onePerPlayer = originalDrop.m_onePerPlayer, m_levelMultiplier = originalDrop.m_levelMultiplier, m_dontScale = originalDrop.m_dontScale }) : ((object)originalDrop))); } } private static void Postfix(ref List ___m_drops, List __state) { if (Configuration.Current.LootDrop.IsEnabled) { ___m_drops = __state; } } } [HarmonyPatch(typeof(Piece), "DropResources")] public static class Piece_DropResources_Transpiler { private static MethodInfo method_Piece_IsPlacedByPlayer = AccessTools.Method(typeof(Piece), "IsPlacedByPlayer", (Type[])null, (Type[])null); private static FieldInfo field_Requirement_m_recover = AccessTools.Field(typeof(Requirement), "m_recover"); [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown if (!Configuration.Current.Building.IsEnabled) { return instructions; } List list = instructions.ToList(); if (Configuration.Current.Building.alwaysDropResources) { for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], method_Piece_IsPlacedByPlayer)) { list[i] = new CodeInstruction(OpCodes.Ldc_I4_1, (object)null); list.RemoveAt(i - 1); } } } if (Configuration.Current.Building.alwaysDropExcludedResources) { for (int j = 0; j < list.Count; j++) { if (CodeInstructionExtensions.LoadsField(list[j], field_Requirement_m_recover, false)) { list.RemoveRange(j - 1, 3); } } } return list.AsEnumerable(); } } [HarmonyPatch(typeof(StationExtension), "Awake")] public static class StationExtension_Awake_Patch { [HarmonyPrefix] public static void Prefix(ref float ___m_maxStationDistance) { if (Configuration.Current.Workbench.IsEnabled) { ___m_maxStationDistance = Configuration.Current.Workbench.workbenchAttachmentRange; } } } internal static class Helper { private const BindingFlags FieldBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; public static Character getPlayerCharacter(Player __instance) { return (Character)(object)__instance; } public static Player getPlayerBySenderId(long id) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) foreach (Player allPlayer in Player.GetAllPlayers()) { ZDOID zDOID = getPlayerCharacter(allPlayer).GetZDOID(); if (zDOID != new ZDOID(0L, 0u) && ((ZDOID)(ref zDOID)).UserID == id) { return allPlayer; } } return null; } public static bool IsSenderPlayerInRange(long senderId, float range) { //IL_000b: 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) return Vector3.Distance(((Component)getPlayerBySenderId(senderId)).transform.position, ((Component)Player.m_localPlayer).transform.position) <= range; } public static float tFloat(this float value, int digits) { double num = Math.Pow(10.0, digits); return (float)(Math.Truncate(num * (double)value) / num); } public static float applyModifierValue(float targetValue, float value) { if (!(value <= -100f)) { return targetValue + targetValue / 100f * value; } return 0f; } public static void applyModifierValueTo(ref float targetValue, float modifier) { targetValue = ((modifier <= -100f) ? 0f : (targetValue + targetValue / 100f * modifier)); } public static int applyModifierValueWithChance(float targetValue, float value) { float num = applyModifierValue(targetValue, value); if (num == 0f) { return 0; } int num2 = (int)Math.Floor(num); return num2 + (((double)(num - (float)num2) > 1.0 - new Random().NextDouble()) ? 1 : 0); } public static string CreateMD5(string input) { using MD5 mD = MD5.Create(); byte[] bytes = Encoding.ASCII.GetBytes(input); byte[] array = mD.ComputeHash(bytes); StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < array.Length; i++) { stringBuilder.Append(array[i].ToString("X2")); } return stringBuilder.ToString(); } public static void ResizeChildEffectArea(MonoBehaviour parent, Type includedTypes, float newRadius) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)parent != (Object)null)) { return; } EffectArea componentInChildren = ((Component)parent).GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null && (componentInChildren.m_type & includedTypes) != 0) { SphereCollider component = ((Component)componentInChildren).GetComponent(); if ((Object)(object)component != (Object)null) { component.radius = newRadius; } } } public static int Clamp(int value, int min, int max) { return Math.Min(max, Math.Max(min, value)); } public static float Clamp(float value, float min, float max) { return Math.Min(max, Math.Max(min, value)); } public static bool SetFieldIfFound(object obj, string field, object value) { FieldInfo field2 = obj.GetType().GetField(field, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field2 == null) { return false; } field2.SetValue(obj, value); return true; } } internal static class InventoryAssistant { public static List GetNearbyChests(GameObject target, float range, bool checkWard = true) { //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; long num; if (Object.op_Implicit((Object)(object)localPlayer)) { num = localPlayer.GetPlayerID(); } else { Piece val = (Object.op_Implicit((Object)(object)target) ? target.GetComponentInParent() : null); if (!Object.op_Implicit((Object)(object)val)) { return new List(); } num = val.GetCreator(); if (num == 0L) { return new List(); } } string[] array = new string[1] { "piece" }; if (Configuration.Current.CraftFromChest.allowCraftingFromCarts || Configuration.Current.CraftFromChest.allowCraftingFromShips) { array = new string[3] { "piece", "item", "vehicle" }; } IOrderedEnumerable orderedEnumerable = from x in Physics.OverlapSphere(target.transform.position, range, LayerMask.GetMask(array)) orderby Vector3.Distance(((Component)x).gameObject.transform.position, target.transform.position) select x; List list = new List(); foreach (Collider item in orderedEnumerable) { try { Container componentInParent = ((Component)item).GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent) && componentInParent.m_lastRevision != uint.MaxValue && !list.Contains(componentInParent)) { bool flag = componentInParent.CheckAccess(num); if (checkWard) { flag = flag && (Object.op_Implicit((Object)(object)localPlayer) ? PrivateArea.CheckAccess(((Component)item).gameObject.transform.position, 0f, false, true) : CheckWardAccessForPlayer(((Component)item).gameObject.transform.position, 0f, num)); } Piece componentInParent2 = ((Component)componentInParent).GetComponentInParent(); bool flag2 = (Object)(object)((Component)componentInParent).GetComponentInParent() != (Object)null; bool flag3 = (Object)(object)((Component)componentInParent).GetComponentInParent() != (Object)null; if ((Object)(object)componentInParent2 != (Object)null && flag && componentInParent.GetInventory() != null && (!flag2 || Configuration.Current.CraftFromChest.allowCraftingFromCarts) && (!flag3 || Configuration.Current.CraftFromChest.allowCraftingFromShips) && (componentInParent2.IsPlacedByPlayer() || (flag3 && Configuration.Current.CraftFromChest.allowCraftingFromShips))) { list.Add(componentInParent); } } } catch (Exception arg) { ValheimPlusPlugin.Logger.LogDebug((object)$"GetNearbyChests skipped '{((Object)((Component)item).gameObject).name}': {arg}"); } } return list; } private static bool CheckWardAccessForPlayer(Vector3 position, float radius, long playerId) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) foreach (PrivateArea allArea in PrivateArea.m_allAreas) { if (Object.op_Implicit((Object)(object)allArea) && allArea.IsEnabled() && allArea.IsInside(position, radius) && !allArea.IsPermitted(playerId)) { return false; } } return true; } public static List GetNearbyChestsWithItem(GameObject target, float range, ItemData itemInfo, bool checkWard = true) { List nearbyChests = GetNearbyChests(target, range, checkWard); List list = new List(); foreach (Container item in nearbyChests) { if (ChestContainsItem(item, itemInfo)) { list.Add(item); } } return list; } public static bool ChestContainsItem(Container chest, ItemData needle) { foreach (ItemData allItem in chest.GetInventory().GetAllItems()) { if (allItem.m_shared.m_name == needle.m_shared.m_name) { return true; } } return false; } public static bool ChestContainsItem(Container chest, string needle) { foreach (ItemData allItem in chest.GetInventory().GetAllItems()) { if (allItem.m_shared.m_name == needle) { return true; } } return false; } public static List GetNearbyChestItems(GameObject target, float range = 10f, bool checkWard = true) { List list = new List(); foreach (Container nearbyChest in GetNearbyChests(target, range, checkWard)) { foreach (ItemData allItem in nearbyChest.GetInventory().GetAllItems()) { list.Add(allItem); } } return list; } public static List GetNearbyChestItemsByContainerList(List nearbyChests) { List list = new List(); foreach (Container nearbyChest in nearbyChests) { foreach (ItemData allItem in nearbyChest.GetInventory().GetAllItems()) { list.Add(allItem); } } return list; } public static int GetItemAmountInItemList(List itemList, ItemData item, int quality = -1, bool matchWorldLevel = true) { return itemList.Where((ItemData current) => current.m_shared.m_name == item.m_shared.m_name && (quality < 0 || quality == current.m_quality) && (!matchWorldLevel || current.m_worldLevel >= Game.m_worldLevel)).Sum((ItemData current) => current.m_stack); } public static int GetItemAmountInItemList(List itemList, string name, int quality = -1, bool matchWorldLevel = true) { return itemList.Where((ItemData current) => current.m_shared.m_name == name && (quality < 0 || quality == current.m_quality) && (!matchWorldLevel || current.m_worldLevel >= Game.m_worldLevel)).Sum((ItemData current) => current.m_stack); } public static int RemoveItemInAmountFromAllNearbyChests(GameObject target, float range, ItemData needle, int amount, bool checkWard = true) { List nearbyChests = GetNearbyChests(target, range, checkWard); GetItemAmountInItemList(GetNearbyChestItemsByContainerList(nearbyChests), needle); if (amount == 0) { return 0; } int num = 0; foreach (Container item in nearbyChests) { if (num != amount) { int num2 = RemoveItemFromChest(item, needle, amount); num += num2; amount -= num2; } } return num; } public static int RemoveItemInAmountFromAllNearbyChests(GameObject target, float range, string needle, int amount, bool checkWard = true) { List nearbyChests = GetNearbyChests(target, range, checkWard); GetItemAmountInItemList(GetNearbyChestItemsByContainerList(nearbyChests), needle); if (amount == 0) { return 0; } int num = 0; foreach (Container item in nearbyChests) { if (num != amount) { int num2 = RemoveItemFromChest(item, needle, amount); num += num2; amount -= num2; } } return num; } public static int RemoveItemFromChest(Container chest, ItemData needle, int amount = 1) { if (!ChestContainsItem(chest, needle)) { return 0; } int num = 0; List allItems = chest.GetInventory().GetAllItems(); foreach (ItemData item in allItems) { if (item.m_shared.m_name == needle.m_shared.m_name) { int num2 = Mathf.Min(item.m_stack, amount); item.m_stack -= num2; amount -= num2; num += num2; if (amount <= 0) { break; } } } if (num == 0) { return 0; } allItems.RemoveAll((ItemData x) => x.m_stack <= 0); chest.m_inventory.m_inventory = allItems; ConveyContainerToNetwork(chest); return num; } public static int RemoveItemFromChest(Container chest, string needle, int amount = 1) { if (!ChestContainsItem(chest, needle)) { return 0; } int num = 0; List allItems = chest.GetInventory().GetAllItems(); foreach (ItemData item in allItems) { if (item.m_shared.m_name == needle) { int num2 = Mathf.Min(item.m_stack, amount); item.m_stack -= num2; amount -= num2; num += num2; if (amount <= 0) { break; } } } if (num == 0) { return 0; } allItems.RemoveAll((ItemData x) => x.m_stack <= 0); chest.m_inventory.m_inventory = allItems; ConveyContainerToNetwork(chest); return num; } public static void ConveyContainerToNetwork(Container c) { c.Save(); c.GetInventory().Changed(false, false); } } [BepInPlugin("org.bepinex.plugins.valheim_plus", "Valheim Plus", "0.10.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class ValheimPlusPlugin : BaseUnityPlugin { internal const string ValheimPlusGuid = "org.bepinex.plugins.valheim_plus"; private const string ValheimPlusName = "Valheim Plus"; public const string NumericVersion = "0.10.1.0"; private const string VersionExtra = ""; public const string FullVersion = "0.10.1.0"; internal const string MinRequiredNumericVersion = "0.10.1.0"; private static readonly GameVersion MinSupportedGameVersion = new GameVersion(1, 0, 12); private static readonly GameVersion TargetGameVersion = new GameVersion(1, 0, 12); private static readonly Dictionary ExcludeGameVersions = new Dictionary(); public static readonly Timer MapSyncSaveTimer = new Timer(TimeSpan.FromMinutes(5.0).TotalMilliseconds); public static readonly string VPlusDataDirectoryPath; private static readonly Harmony Harmony; public const string Repository = "https://github.com/Grantapher/ValheimPlus/releases/latest"; private const string ApiRepository = "https://api.github.com/repos/grantapher/valheimPlus/releases/latest"; internal static string newestVersion { get; private set; } = ""; internal static bool isUpToDate { get; private set; } public static ManualLogSource Logger { get; private set; } private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; Logger.LogInfo((object)("Valheim game version: " + Version.GetVersionString(false))); Logger.Log((LogLevel)(("".Length > 0) ? 16 : 32), (object)"Valheim Plus full version: 0.10.1.0"); Logger.LogInfo((object)("Valheim Plus dll file location: '" + ((object)this).GetType().Assembly.Location + "'")); bool num = IsGameVersionTooOld(); if (num) { LogTooOld(); } bool flag = CheckIsGameVersionExcluded(); if (num || flag) { Logger.LogFatal((object)"Aborting loading of Valheim Plus due to incompatible version."); return; } try { BepInExConfig.Load(((BaseUnityPlugin)this).Config); Logger.LogInfo((object)("Configuration loaded successfully from '" + ((BaseUnityPlugin)this).Config.ConfigFilePath + "'.")); PatchAll(); isUpToDate = !IsNewVersionAvailable(); if (!isUpToDate) { Logger.LogWarning((object)"There is a newer version available of ValheimPlus. Please visit https://github.com/Grantapher/ValheimPlus/releases/latest."); } else { Logger.LogInfo((object)"ValheimPlus [0.10.1.0] is up to date."); } if (!Directory.Exists(VPlusDataDirectoryPath)) { Directory.CreateDirectory(VPlusDataDirectoryPath); } if (ZNet.m_isServer && Configuration.Current.Map.IsEnabled && Configuration.Current.Map.shareMapProgression) { MapSyncSaveTimer.AutoReset = true; MapSyncSaveTimer.Elapsed += delegate { VPlusMapSync.SaveMapDataToDisk(); }; } } catch (Exception arg) { Logger.LogError((object)$"Error while loading the configuration: {arg}"); } } private static bool IsGameVersionTooOld() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) return Version.CurrentVersion < MinSupportedGameVersion; } private static bool IsGameVersionNewerThanTarget() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) return Version.CurrentVersion > TargetGameVersion; } private static bool CheckIsGameVersionExcluded() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) string value; bool num = ExcludeGameVersions.TryGetValue(Version.CurrentVersion, out value); if (num) { Logger.LogError((object)value); } return num; } private static bool IsNewVersionAvailable() { try { string input = HttpHelper.DownloadString("https://api.github.com/repos/grantapher/valheimPlus/releases/latest"); newestVersion = new Regex("\"tag_name\":\"([^\"]*)?\"").Match(input).Groups[1].Value; } catch { Logger.LogWarning((object)"The newest version could not be determined."); newestVersion = "Unknown"; } if (Version.TryParse(newestVersion, out Version result)) { if (Version.TryParse("0.10.1.0", out Version result2)) { if (result2 < result) { return true; } } else { Logger.LogWarning((object)"Couldn't parse current version"); } } else { Logger.LogWarning((object)"Couldn't parse newest version, comparing version strings with equality."); if (newestVersion != "0.10.1.0") { return true; } } return false; } public static void PatchAll() { //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown Logger.LogDebug((object)"Applying patches."); try { Harmony.PatchAll(); if (AppDomain.CurrentDomain.GetAssemblies().Any((Assembly assembly) => assembly.FullName.Contains("assembly_steamworks"))) { Harmony.Patch((MethodBase)AccessTools.TypeByName("SteamGameServer").GetMethod("SetMaxPlayerCount"), new HarmonyMethod(typeof(ChangeSteamServerVariables).GetMethod("Prefix")), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } ConfigSyncGlue.SetModRequired(Configuration.Current.Server.enforceMod); Logger.LogDebug((object)"Patches successfully applied."); } catch (Exception) { Logger.LogError((object)"Failed to apply patches."); if (IsGameVersionTooOld()) { LogTooOld(); } else if (IsGameVersionNewerThanTarget()) { Logger.LogWarning((object)("This version of Valheim Plus (0.10.1.0) was compiled with a game version of " + $"\"{TargetGameVersion}\", but this game version is newer at \"{Version.CurrentVersion}\". " + "If you are using the PTB, you likely need to use the non-beta version of the game. Otherwise, the errors seen above likely will require the Valheim Plus mod to be updated. If a game update just came out for Valheim, this may take some time for the mod to be updated. See https://github.com/Grantapher/ValheimPlus/blob/grantapher-development/COMPATIBILITY.md for what game versions are compatible with what mod versions.")); } else { Logger.LogWarning((object)("Valheim Plus failed to apply patches. Please ensure the game version (" + Version.GetVersionString(false) + ") is compatible with the Valheim Plus version (0.10.1.0) at https://github.com/Grantapher/ValheimPlus/blob/grantapher-development/COMPATIBILITY.md. If it already is, please report a bug at https://github.com/Grantapher/ValheimPlus/issues.")); } throw; } } private static void LogTooOld() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) Logger.LogError((object)("This version of Valheim Plus (0.10.1.0) expects a minimum game version of " + $"\"{MinSupportedGameVersion}\", but this game version is older at \"{Version.CurrentVersion}\". " + "Please either update the Valheim game, or use an older version of Valheim Plus as per https://github.com/Grantapher/ValheimPlus/blob/grantapher-development/COMPATIBILITY.md.")); } public static void UnpatchSelf() { Logger.LogDebug((object)"Unpatching."); try { Harmony.UnpatchSelf(); Logger.LogDebug((object)"Successfully unpatched."); } catch (Exception arg) { Logger.LogError((object)$"Failed to unpatch. Exception: {arg}"); } } static ValheimPlusPlugin() { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown string bepInExRootPath = Paths.BepInExRootPath; char directorySeparatorChar = Path.DirectorySeparatorChar; VPlusDataDirectoryPath = bepInExRootPath + directorySeparatorChar + "vplus-data"; Harmony = new Harmony("mod.valheim_plus"); } } public static class VPlusDataObjects { public class MapRange { public int StartingX; public int EndingX; public int Y; } } } namespace ValheimPlus.Http { public static class HttpHelper { private const string UserAgent = "ValheimPlusClient/1.0"; public static string DownloadString(string url, TimeSpan? timeout = null) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown if (string.IsNullOrWhiteSpace(url)) { throw new ArgumentException("url is null or empty", "url"); } if (!Uri.TryCreate(url, UriKind.Absolute, out Uri result) || (result.Scheme != Uri.UriSchemeHttp && result.Scheme != Uri.UriSchemeHttps)) { throw new ArgumentException("Invalid URL scheme: '" + url + "'", "url"); } try { ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12; } catch { } HttpClientHandler val = new HttpClientHandler { AllowAutoRedirect = true }; try { HttpClient val2 = new HttpClient((HttpMessageHandler)(object)val); try { val2.Timeout = timeout ?? TimeSpan.FromSeconds(20.0); val2.DefaultRequestHeaders.UserAgent.Clear(); val2.DefaultRequestHeaders.UserAgent.ParseAdd("ValheimPlusClient/1.0"); val2.DefaultRequestHeaders.Accept.Clear(); val2.DefaultRequestHeaders.Accept.ParseAdd("*/*"); HttpResponseMessage result2 = val2.GetAsync(result).GetAwaiter().GetResult(); result2.EnsureSuccessStatusCode(); return result2.Content.ReadAsStringAsync().GetAwaiter().GetResult(); } finally { ((IDisposable)val2)?.Dispose(); } } finally { ((IDisposable)val)?.Dispose(); } } } } namespace ValheimPlus.Utility { public static class EmbeddedAsset { public static Stream LoadEmbeddedAsset(string assetPath) { Assembly executingAssembly = Assembly.GetExecutingAssembly(); executingAssembly.GetManifestResourceNames(); if (executingAssembly.GetManifestResourceInfo(executingAssembly.GetName().Name + "." + assetPath) != null) { return executingAssembly.GetManifestResourceStream(executingAssembly.GetName().Name + "." + assetPath); } return null; } } internal static class GameObjectAssistant { private static readonly ConcurrentDictionary Stopwatches = new ConcurrentDictionary(); public static Stopwatch GetStopwatch(GameObject o) { float gameObjectPositionHash = GetGameObjectPositionHash(o); if (Stopwatches.TryGetValue(gameObjectPositionHash, out var value)) { return value; } value = new Stopwatch(); Stopwatches.TryAdd(gameObjectPositionHash, value); return value; } public static float GetGameObjectPositionHash(GameObject obj) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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_0024: Unknown result type (might be due to invalid IL or missing references) Vector3 position = obj.transform.position; return 1000f * position.x + position.y + 0.001f * position.z; } public static T GetChildComponentByName(string name, GameObject objected) where T : Component { T[] componentsInChildren = objected.GetComponentsInChildren(true); foreach (T val in componentsInChildren) { if (((Object)((Component)val).gameObject).name == name) { return val; } } return default(T); } } public static class ListExtensions { public static List> ChunkBy(this List source, int chunkSize) { return (from x in source.Select((T x, int i) => new { Index = i, Value = x }) group x by x.Index / chunkSize into x select x.Select(v => v.Value).ToList()).ToList(); } } public static class PatchLog { public static void Failed(string patch, string detail = null, Exception exception = null) { string text = "Failed to apply `" + patch + "`."; if (detail != null) { text = text + " " + detail; } if (exception != null) { text += $" Exception is:\n{exception}"; } ValheimPlusPlugin.Logger.LogError((object)text); } } public class RpcData { public string Name; public long Target; public object[] Payload; } public static class RpcQueue { private static Queue _rpcQueue = new Queue(); private static bool _ack = true; public static void Enqueue(RpcData rpc) { _rpcQueue.Enqueue(rpc); } public static bool SendNextRpc() { if (_rpcQueue.Count == 0 || !_ack) { return false; } RpcData rpcData = _rpcQueue.Dequeue(); if (Utility.IsNullOrWhiteSpace(rpcData.Name) || rpcData.Payload == null) { return false; } ZRoutedRpc.instance.InvokeRoutedRPC(rpcData.Target, rpcData.Name, rpcData.Payload); _ack = false; return true; } public static void GotAck() { _ack = true; } } public static class ZPackageExtensions { public static VPlusDataObjects.MapRange ReadVPlusMapRange(this ZPackage pkg) { return new VPlusDataObjects.MapRange { StartingX = pkg.m_reader.ReadInt32(), EndingX = pkg.m_reader.ReadInt32(), Y = pkg.m_reader.ReadInt32() }; } public static void WriteVPlusMapRange(this ZPackage pkg, VPlusDataObjects.MapRange mapRange) { pkg.m_writer.Write(mapRange.StartingX); pkg.m_writer.Write(mapRange.EndingX); pkg.m_writer.Write(mapRange.Y); } } } namespace ValheimPlus.UI { [HarmonyPatch(typeof(HotkeyBar), "UpdateIcons")] public static class HotkeyBar_UpdateIcons_Patch { private const string hudObjectNamePrefix = "BowAmmoCounts"; private const string noAmmoDisplay = "No Ammo"; private static readonly GameObject[] ammoCounters = (GameObject[])(object)new GameObject[8]; private static int elementCount = -1; private static bool IsEnabled() { if (Configuration.Current.Hud.IsEnabled) { return Configuration.Current.Hud.displayBowAmmoCounts > 0; } return false; } private static void Prefix(HotkeyBar __instance, Player player) { if (IsEnabled()) { elementCount = __instance.m_elements.Count; if ((Object)(object)player == (Object)null || ((Character)player).IsDead()) { DestroyAllAmmoCounters(); } } } private static void Postfix(HotkeyBar __instance, Player player) { if (IsEnabled()) { if (elementCount != __instance.m_elements.Count) { DestroyAllAmmoCounters(); } if (!((Object)(object)player == (Object)null) && !((Character)player).IsDead()) { DisplayAmmoCountsUnderBowHotbarIcons(__instance, player); } } } private static void DisplayAmmoCountsUnderBowHotbarIcons(HotkeyBar __instance, Player player) { HashSet hashSet = new HashSet { 0, 1, 2, 3, 4, 5, 6, 7 }; foreach (ItemData item in __instance.m_items) { if (item != null) { hashSet.Remove(item.m_gridPos.x); DisplayAmmoCountsUnderBowHotbarIcon(__instance, player, item); } } foreach (int item2 in hashSet) { DestroyAmmoCounter(item2); } } private static void DisplayAmmoCountsUnderBowHotbarIcon(HotkeyBar __instance, Player player, ItemData item) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Invalid comparison between Unknown and I4 //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Invalid comparison between Unknown and I4 int x = item.m_gridPos.x; GameObject val = ammoCounters[x]; if ((int)item.m_shared.m_itemType != 4 || (Configuration.Current.Hud.displayBowAmmoCounts == 1 && !((Humanoid)player).IsItemEquiped(item)) || x >= __instance.m_elements.Count || x < 0) { DestroyAmmoCounter(x); return; } ElementData val2 = __instance.m_elements[x]; TMP_Text componentInChildren; if ((Object)(object)val == (Object)null) { GameObject gameObject = ((Component)val2.m_amount).gameObject; val = Object.Instantiate(gameObject, gameObject.transform.parent, false); ((Object)val).name = "BowAmmoCounts" + x; val.SetActive(true); Vector3 val3 = gameObject.transform.position - ((Component)val2.m_icon).transform.position - new Vector3(0f, 15f); val.transform.Translate(val3); componentInChildren = val.GetComponentInChildren(); TMP_Text obj = componentInChildren; obj.fontSize -= 2f; ammoCounters[x] = val; } else { componentInChildren = val.GetComponentInChildren(); } val.gameObject.transform.SetParent(((Component)val2.m_amount).gameObject.transform.parent, false); ItemData ammoItem = ((Humanoid)player).m_ammoItem; if (ammoItem == null || ammoItem.m_shared.m_ammoType != item.m_shared.m_ammoType) { ammoItem = ((Humanoid)player).GetInventory().GetAmmoItem(item.m_shared.m_ammoType, (string)null); } int num = 0; int num2 = 0; foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems()) { if (allItem.m_shared.m_ammoType == item.m_shared.m_ammoType && ((int)allItem.m_shared.m_itemType == 9 || (int)allItem.m_shared.m_itemType == 2)) { num2 += allItem.m_stack; if (allItem.m_shared.m_name == ammoItem.m_shared.m_name) { num += allItem.m_stack; } } } if (num2 == 0) { componentInChildren.text = "No Ammo"; return; } componentInChildren.text = ammoItem.m_shared.m_name.Split(new char[1] { '_' }).Last() + "\n" + num + "/" + num2; } private static void DestroyAllAmmoCounters() { for (int i = 0; i < 8; i++) { DestroyAmmoCounter(i); } } private static void DestroyAmmoCounter(int index) { GameObject val = ammoCounters[index]; if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); ammoCounters[index] = null; } } } } namespace ValheimPlus.RPC { public class VPlusAck { public static void RPC_VPlusAck(long sender) { RpcQueue.GotAck(); } public static void SendAck(long target) { ZRoutedRpc.instance.InvokeRoutedRPC(target, "VPlusAck", Array.Empty()); } } public class VPlusMapPinSync { public static void RPC_VPlusMapAddPin(long sender, ZPackage mapPinPkg) { //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) if (ZNet.m_isServer) { if (sender == ZRoutedRpc.instance.GetServerPeerID() || mapPinPkg == null) { return; } foreach (ZNetPeer peer in ZRoutedRpc.instance.m_peers) { if (peer.m_uid != sender) { ZRoutedRpc.instance.InvokeRoutedRPC(peer.m_uid, "VPlusMapAddPin", new object[1] { mapPinPkg }); } } ValheimPlusPlugin.Logger.LogDebug((object)"Sent map pin to all clients"); } else { if (sender != ZRoutedRpc.instance.GetServerPeerID()) { return; } if (mapPinPkg == null) { ValheimPlusPlugin.Logger.LogWarning((object)"Warning: Got empty map pin package from server."); return; } long num = mapPinPkg.ReadLong(); string text = mapPinPkg.ReadString(); if (!(text != Player.m_localPlayer.GetPlayerName()) || num == ZRoutedRpc.instance.m_id) { return; } ValheimPlusPlugin.Logger.LogDebug((object)"Checking sent pin"); Vector3 val = mapPinPkg.ReadVector3(); int num2 = mapPinPkg.ReadInt(); string text2 = mapPinPkg.ReadString(); bool flag = mapPinPkg.ReadBool(); if (!Minimap.instance.HaveSimilarPin(val, (PinType)num2, text2, true)) { Minimap.instance.AddPin(val, (PinType)num2, text2, true, false, 0L, default(PlatformUserID)); if (!flag) { MessageHud.instance.ShowMessage((MessageType)2, "Received map pin " + text2 + " from " + text + "!", 0, Minimap.instance.GetSprite((PinType)num2), false, true); } ValheimPlusPlugin.Logger.LogDebug((object)("I got pin named " + text2 + " from " + text + "!")); } } } public static void SendMapPinToServer(PinData pinData, bool keepQuiet = false) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected I4, but got Unknown ZPackage val = new ZPackage(); val.Write(ZRoutedRpc.instance.m_id); if (keepQuiet) { val.Write(""); } else { val.Write(Player.m_localPlayer.GetPlayerName()); } val.Write(pinData.m_pos); val.Write((int)pinData.m_type); val.Write(pinData.m_name); val.Write(keepQuiet); ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "VPlusMapAddPin", new object[1] { val }); ValheimPlusPlugin.Logger.LogDebug((object)("Sent map pin " + pinData.m_name + " to the server")); } } public class VPlusMapSync { public static BitArray ServerMapData; public static bool ShouldSyncOnSpawn = true; public static void RPC_VPlusMapSync(long sender, ZPackage mapPkg) { if (ZNet.m_isServer) { if (sender == ZRoutedRpc.instance.GetServerPeerID() || mapPkg == null) { return; } int num = mapPkg.ReadInt(); if (num > 0) { for (int i = 0; i < num; i++) { VPlusDataObjects.MapRange mapRange = mapPkg.ReadVPlusMapRange(); for (int j = mapRange.StartingX; j < mapRange.EndingX; j++) { ServerMapData[mapRange.Y * Minimap.instance.m_textureSize + j] = true; } } ValheimPlusPlugin.Logger.LogDebug((object)$"Received {num} map ranges from peer #{sender}."); VPlusAck.SendAck(sender); } if (!mapPkg.ReadBool()) { return; } List list = ExplorationDataToMapRanges(ServerMapData); List list2 = ChunkMapData(list); foreach (ZPackage item in list2) { RpcData rpcData = new RpcData(); rpcData.Name = "VPlusMapSync"; rpcData.Payload = new object[1] { item }; rpcData.Target = 0L; RpcQueue.Enqueue(rpcData); } ValheimPlusPlugin.Logger.LogDebug((object)$"Sent map updates to all clients ({list.Count} map ranges, {list2.Count} chunks)"); } else { if (sender != ZRoutedRpc.instance.GetServerPeerID()) { return; } if (mapPkg == null) { ValheimPlusPlugin.Logger.LogWarning((object)"Warning: Got empty map sync package from server."); return; } int num2 = mapPkg.ReadInt(); if (num2 > 0) { for (int k = 0; k < num2; k++) { VPlusDataObjects.MapRange mapRange2 = mapPkg.ReadVPlusMapRange(); for (int l = mapRange2.StartingX; l < mapRange2.EndingX; l++) { Minimap.instance.Explore(l, mapRange2.Y); } } Minimap.instance.m_fogTexture.Apply(); ValheimPlusPlugin.Logger.LogDebug((object)$"I got {num2} map ranges from the server!"); VPlusAck.SendAck(sender); } else { ValheimPlusPlugin.Logger.LogDebug((object)"Server has no explored areas to sync, continuing."); } } } public static void SendMapToServer() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown List list = ExplorationDataToMapRanges(Minimap.instance.m_explored); if (list.Count == 0) { ZPackage val = new ZPackage(); val.Write(0); val.Write(true); ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "VPlusMapSync", new object[1] { val }); return; } List list2 = ChunkMapData(list); foreach (ZPackage item in list2) { RpcData rpcData = new RpcData(); rpcData.Name = "VPlusMapSync"; rpcData.Payload = new object[1] { item }; rpcData.Target = ZRoutedRpc.instance.GetServerPeerID(); RpcQueue.Enqueue(rpcData); } ValheimPlusPlugin.Logger.LogDebug((object)$"Sent my map data to the server ({list.Count} map ranges, {list2.Count} chunks)"); } public static void LoadMapDataFromDisk() { if (ServerMapData == null) { return; } string vPlusDataDirectoryPath = ValheimPlusPlugin.VPlusDataDirectoryPath; char directorySeparatorChar = Path.DirectorySeparatorChar; if (!File.Exists(vPlusDataDirectoryPath + directorySeparatorChar + ZNet.instance.GetWorldName() + "_mapSync.dat")) { return; } try { string vPlusDataDirectoryPath2 = ValheimPlusPlugin.VPlusDataDirectoryPath; directorySeparatorChar = Path.DirectorySeparatorChar; string[] array = File.ReadAllText(vPlusDataDirectoryPath2 + directorySeparatorChar + ZNet.instance.GetWorldName() + "_mapSync.dat").Split(new char[1] { ',' }); string[] array2 = array; for (int i = 0; i < array2.Length; i++) { if (int.TryParse(array2[i], out var result)) { ServerMapData[result] = true; } } ValheimPlusPlugin.Logger.LogDebug((object)$"Loaded {array.Length} map points from disk."); } catch (Exception ex) { ValheimPlusPlugin.Logger.LogError((object)"Failed to load synchronized map data."); ValheimPlusPlugin.Logger.LogError((object)ex); } } public static void SaveMapDataToDisk() { if (ServerMapData == null) { return; } List list = new List(); for (int i = 0; i < Minimap.instance.m_textureSize; i++) { for (int j = 0; j < Minimap.instance.m_textureSize; j++) { if (ServerMapData[i * Minimap.instance.m_textureSize + j]) { list.Add(i * Minimap.instance.m_textureSize + j); } } } if (list.Count > 0) { string vPlusDataDirectoryPath = ValheimPlusPlugin.VPlusDataDirectoryPath; char directorySeparatorChar = Path.DirectorySeparatorChar; File.Delete(vPlusDataDirectoryPath + directorySeparatorChar + ZNet.instance.GetWorldName() + "_mapSync.dat"); string vPlusDataDirectoryPath2 = ValheimPlusPlugin.VPlusDataDirectoryPath; directorySeparatorChar = Path.DirectorySeparatorChar; File.WriteAllText(vPlusDataDirectoryPath2 + directorySeparatorChar + ZNet.instance.GetWorldName() + "_mapSync.dat", string.Join(",", list)); ValheimPlusPlugin.Logger.LogDebug((object)$"Saved {list.Count} map points to disk."); } } private static List ExplorationDataToMapRanges(BitArray explorationData) { List list = new List(); for (int i = 0; i < Minimap.instance.m_textureSize; i++) { int num = -1; int num2 = -1; for (int j = 0; j < Minimap.instance.m_textureSize; j++) { if (explorationData[i * Minimap.instance.m_textureSize + j] && num == -1 && num2 == -1) { num = j; } else if (!explorationData[i * Minimap.instance.m_textureSize + j] && num > -1 && num2 == -1) { num2 = j - 1; } else if (num > -1 && num2 > -1) { list.Add(new VPlusDataObjects.MapRange { StartingX = num, EndingX = num2, Y = i }); num = -1; num2 = -1; } } if (num > -1 && num2 == -1) { list.Add(new VPlusDataObjects.MapRange { StartingX = num, EndingX = Minimap.instance.m_textureSize, Y = i }); } } return list; } private static List ChunkMapData(List mapData, int chunkSize = 10000) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown if (mapData == null || mapData.Count == 0) { return null; } List> list = mapData.ChunkBy(chunkSize); List list2 = new List(); foreach (List item in list) { ZPackage val = new ZPackage(); val.Write(item.Count); foreach (VPlusDataObjects.MapRange item2 in item) { val.WriteVPlusMapRange(item2); } if (item == list.Last()) { val.Write(true); } else { val.Write(false); } list2.Add(val); } return list2; } } } namespace ValheimPlus.GameClasses { public static class AttackExtensions { public static SkillType GetCharacterWeaponSkillType(this Attack __instance) { //IL_002e: 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) return (SkillType)(((??)__instance.m_character.GetCurrentWeapon()?.m_shared?.m_skillType) ?? 11); } public static bool IsAttackFromLocalPlayer(this Attack __instance) { return (Object)(object)__instance.m_character == (Object)(object)Player.m_localPlayer; } } [HarmonyPatch(typeof(Attack), "GetAttackStamina")] public static class Attack_GetAttackStamina_Patch { [UsedImplicitly] private static void Postfix(ref Attack __instance, ref float __result) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected I4, but got Unknown if (Configuration.Current.StaminaUsage.IsEnabled && __instance.IsAttackFromLocalPlayer()) { SkillType characterWeaponSkillType = __instance.GetCharacterWeaponSkillType(); float num = (characterWeaponSkillType - 1) switch { 0 => Configuration.Current.StaminaUsage.swords, 1 => Configuration.Current.StaminaUsage.knives, 2 => Configuration.Current.StaminaUsage.clubs, 3 => Configuration.Current.StaminaUsage.polearms, 4 => Configuration.Current.StaminaUsage.spears, 6 => Configuration.Current.StaminaUsage.axes, 10 => Configuration.Current.StaminaUsage.unarmed, 11 => Configuration.Current.StaminaUsage.pickaxes, 7 => Configuration.Current.StaminaUsage.bows, _ => 0f, }; if (num != 0f) { __result = Helper.applyModifierValue(__result, num); } } } } [HarmonyPatch(typeof(Attack), "GetAttackEitr", new Type[] { typeof(Character), typeof(ItemData) })] public static class Attack_GetAttackEitr_Patch { [UsedImplicitly] private static void Postfix(ref Attack __instance, ref float __result) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Invalid comparison between Unknown and I4 if (Configuration.Current.EitrUsage.IsEnabled && __instance.IsAttackFromLocalPlayer()) { SkillType characterWeaponSkillType = __instance.GetCharacterWeaponSkillType(); float num = (((int)characterWeaponSkillType == 9) ? Configuration.Current.EitrUsage.elementalMagic : (((int)characterWeaponSkillType != 10) ? 0f : Configuration.Current.EitrUsage.bloodMagic)); float num2 = num; if (num2 != 0f) { __result = Helper.applyModifierValue(__result, num2); } } } } [HarmonyPatch(typeof(Attack), "GetAttackHealth")] public static class Attack_GetAttackHealth_Patch { [UsedImplicitly] private static void Postfix(ref Attack __instance, ref float __result) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Invalid comparison between Unknown and I4 if (Configuration.Current.HealthUsage.IsEnabled && __instance.IsAttackFromLocalPlayer()) { float num = (((int)__instance.GetCharacterWeaponSkillType() != 10) ? 0f : Configuration.Current.HealthUsage.bloodMagic); float num2 = num; if (num2 != 0f) { __result = Helper.applyModifierValue(__result, num2); } } } } [HarmonyPatch(typeof(Attack), "ProjectileAttackTriggered")] public static class Attack_ProjectileAttackTriggered_Patch { private const float MaxClampValue = 1000000f; [UsedImplicitly] private static void Prefix(ref Attack __instance) { if (__instance != null) { if (Configuration.Current.PlayerProjectile.IsEnabled && __instance.IsAttackFromLocalPlayer()) { AdjustPlayerProjectile(ref __instance); } if (Configuration.Current.MonsterProjectile.IsEnabled && !((Character)__instance.m_character).IsPlayer()) { AdjustEnemyProjectile(ref __instance); } } } private static void AdjustPlayerProjectile(ref Attack __instance) { //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_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) float b = Helper.applyModifierValue(__instance.m_projectileVelMin, Configuration.Current.PlayerProjectile.playerMinChargeVelocityMultiplier); float b2 = Helper.applyModifierValue(__instance.m_projectileVel, Configuration.Current.PlayerProjectile.playerMaxChargeVelocityMultiplier); float b3 = Helper.applyModifierValue(__instance.m_projectileAccuracyMin, 0f - Configuration.Current.PlayerProjectile.playerMinChargeAccuracyMultiplier); float b4 = Helper.applyModifierValue(__instance.m_projectileAccuracy, 0f - Configuration.Current.PlayerProjectile.playerMaxChargeAccuracyMultiplier); float t = 1f; if (Configuration.Current.PlayerProjectile.enableScaleWithSkillLevel) { SkillType skillType = __instance.m_weapon.m_shared.m_skillType; if ((int)skillType == 0) { return; } t = ((Player)__instance.m_character).m_skills.GetSkill(skillType).m_level * 0.01f; } __instance.m_projectileVelMin = ShortcutLerp(__instance.m_projectileVelMin, b, t); __instance.m_projectileVel = ShortcutLerp(__instance.m_projectileVel, b2, t); __instance.m_projectileAccuracyMin = ShortcutLerp(__instance.m_projectileAccuracyMin, b3, t); __instance.m_projectileAccuracy = ShortcutLerp(__instance.m_projectileAccuracy, b4, t); } private static void AdjustEnemyProjectile(ref Attack __instance) { __instance.m_projectileVelMin = ClampValue(__instance.m_projectileVelMin); __instance.m_projectileVel = ClampValue(Helper.applyModifierValue(__instance.m_projectileVel, Configuration.Current.MonsterProjectile.monsterMaxChargeVelocityMultiplier)); __instance.m_projectileAccuracyMin = ClampValue(__instance.m_projectileAccuracyMin); __instance.m_projectileAccuracy = ClampValue(Helper.applyModifierValue(__instance.m_projectileAccuracy, 0f - Configuration.Current.MonsterProjectile.monsterMaxChargeAccuracyMultiplier)); } private static float ShortcutLerp(float a, float b, float t) { if (t != 1f) { return Mathf.Lerp(a, b, t); } return b; } private static float ClampValue(float velocity) { return Mathf.Clamp(velocity, 0f, 1000000f); } } public static class BedHelper { public static bool CanSleepWithoutSpawn(this Bed bed) { if (Configuration.Current.Bed.IsEnabled && Configuration.Current.Bed.sleepWithoutSpawn && !bed.IsCurrent()) { if (Configuration.Current.Bed.unclaimedBedsOnly) { return bed.GetOwner() == 0; } return true; } return false; } public static void InteractWithoutOwnershipReadWrite(this Bed bed, Player player) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) if (!EnvMan.CanSleep()) { ((Character)player).Message((MessageType)2, "$msg_cantsleep", 0, (Sprite)null, false); } else if (bed.CheckEnemies(player) && bed.CheckExposure(player) && bed.CheckFire(player) && bed.CheckWet(player)) { ((Character)player).AttachStart(bed.m_spawnPoint, ((Component)bed).gameObject, true, true, false, "attach_bed", new Vector3(0f, 0.5f, 0f), (Transform)null); } } } [HarmonyPatch(typeof(Bed), "GetHoverText")] public static class Bed_GetHoverText_Patch { private const string AppendStr = "\n[LShift+$KEY_Use] $piece_bed_sleep"; [UsedImplicitly] private static void Postfix(Bed __instance, ref string __result) { if (__instance.CanSleepWithoutSpawn()) { __result += Localization.instance.Localize("\n[LShift+$KEY_Use] $piece_bed_sleep"); } } } [HarmonyPatch(typeof(Bed), "Interact")] public static class Bed_Interact_Patch { [UsedImplicitly] private static bool Prefix(Bed __instance, Humanoid human) { if (ZInput.GetButtonDown("Use")) { return !ZInput.GetKey((KeyCode)304, true); } return true; } [UsedImplicitly] private static void Postfix(Bed __instance, Humanoid human, bool repeat) { if (!repeat && __instance.CanSleepWithoutSpawn() && ZInput.GetKey((KeyCode)304, true) && ZInput.GetButtonDown("Use")) { __instance.InteractWithoutOwnershipReadWrite((Player)(object)((human is Player) ? human : null)); } } } [HarmonyPatch(typeof(Beehive), "Awake")] public static class Beehive_Awake_Patch { private static bool Prefix(ref float ___m_secPerUnit, ref int ___m_maxHoney) { if (Configuration.Current.Beehive.IsEnabled) { ___m_secPerUnit = Configuration.Current.Beehive.honeyProductionSpeed; ___m_maxHoney = Configuration.Current.Beehive.maximumHoneyPerBeehive; } return true; } } [HarmonyPatch(typeof(Beehive), "Awake")] public static class Beehive_Awake_Transpiler { [UsedImplicitly] [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown BeehiveConfiguration beehive = Configuration.Current.Beehive; if (!beehive.IsEnabled || !beehive.autoDeposit) { return instructions; } List list = instructions.ToList(); float num = Mathf.Clamp(beehive.honeyProductionSpeed * (float)beehive.maximumHoneyPerBeehive, 3f, 10f); MethodInfo methodInfo = AccessTools.Method(typeof(MonoBehaviour), "InvokeRepeating", (Type[])null, (Type[])null); try { return new CodeMatcher((IEnumerable)list, generator).MatchStartForward((CodeMatch[])(object)new CodeMatch[4] { new CodeMatch((OpCode?)OpCodes.Ldstr, (object)"UpdateBees", (string)null), new CodeMatch((OpCode?)OpCodes.Ldc_R4, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldc_R4, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Call, (object)methodInfo, (string)null) }).ThrowIfNotMatch("No match for InvokeRepeating(\"UpdateBees\", float, float).", Array.Empty()).Advance(1) .SetOperandAndAdvance((object)1f) .SetOperandAndAdvance((object)num) .InstructionEnumeration(); } catch (Exception exception) { PatchLog.Failed("Beehive_Awake_Transpiler", "The beehive auto-deposit timing fix will not work.", exception); return list; } } } [HarmonyPatch(typeof(Beehive), "GetHoverText")] public static class Beehive_GetHoverText_Patch { private static bool Prefix(Beehive __instance, ref string __result) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (!Configuration.Current.Beehive.IsEnabled || !Configuration.Current.Beehive.showDuration) { return true; } if (!PrivateArea.CheckAccess(((Component)__instance).transform.position, 0f, false, false)) { __result = Localization.instance.Localize(__instance.m_name + "\n$piece_noaccess"); return false; } int honeyLevel = __instance.GetHoneyLevel(); if (honeyLevel > 0) { __result = Localization.instance.Localize(string.Concat(__instance.m_name, " ( ", __instance.m_honeyItem.m_itemData.m_shared.m_name, " x ", honeyLevel, " ) " + calculateTimeLeft(__instance) + "\n[$KEY_Use] $piece_beehive_extract")); return false; } __result = Localization.instance.Localize(__instance.m_name + " ( $piece_container_empty ) " + calculateTimeLeft(__instance) + "\n[$KEY_Use] $piece_beehive_check"); return false; } private static string calculateTimeLeft(Beehive BeehiveInstance) { string result = ""; if (BeehiveInstance.GetHoneyLevel() == BeehiveInstance.m_maxHoney) { return result; } float num = BeehiveInstance.m_nview.GetZDO().GetFloat("product", 0f); float num2 = BeehiveInstance.m_secPerUnit - num; int num3 = (int)num2 / 60; result = (((int)num2 < 120) ? ((int)num2 + " seconds") : (num3 + " minutes")); return " (" + result + ")"; } } [HarmonyPatch(typeof(Beehive), "RPC_Extract")] public static class Beehive_RPC_Extract_Patch { private static bool Prefix(long caller, ref Beehive __instance) { //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) Beehive beehive = __instance; if (!Configuration.Current.Beehive.autoDeposit || !Configuration.Current.Beehive.IsEnabled || !beehive.m_nview.IsOwner()) { return true; } if (beehive.GetHoneyLevel() <= 0) { return true; } float range = Helper.Clamp(Configuration.Current.Beehive.autoDepositRange, 1f, 50f); List nearbyChests = InventoryAssistant.GetNearbyChests(((Component)beehive).gameObject, range); if (nearbyChests.Count == 0) { return true; } while (beehive.GetHoneyLevel() > 0) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(((Object)((Component)__instance.m_honeyItem).gameObject).name); ZNetView.m_forceDisableInit = true; GameObject val = Object.Instantiate(itemPrefab); ZNetView.m_forceDisableInit = false; bool num = spawnNearbyChest(val.GetComponent(), mustHaveItem: true); Object.Destroy((Object)(object)val); if (!num) { return true; } } if (beehive.GetHoneyLevel() == 0) { beehive.m_spawnEffect.Create(beehive.m_spawnPoint.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); } return true; bool spawnNearbyChest(ItemDrop item, bool mustHaveItem) { foreach (Container item in nearbyChests) { Inventory inventory = item.GetInventory(); if ((!mustHaveItem || inventory.HaveItem(item.m_itemData.m_shared.m_name, true)) && inventory.AddItem(item.m_itemData)) { beehive.m_nview.GetZDO().Set("level", beehive.GetHoneyLevel() - 1); InventoryAssistant.ConveyContainerToNetwork(item); return true; } } if (mustHaveItem) { return spawnNearbyChest(item, mustHaveItem: false); } return false; } } } [HarmonyPatch(typeof(Beehive), "UpdateBees")] public static class Beehive_UpdateBees_Transpiler { private static MethodInfo method_AutoDepositToChest = AccessTools.Method(typeof(Beehive_UpdateBees_Transpiler), "AutoDepositToChest", (Type[])null, (Type[])null); [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown if (!Configuration.Current.Beehive.IsEnabled || !Configuration.Current.Beehive.autoDeposit) { return instructions; } List list = instructions.ToList(); int num = list.Count - 2; list.Insert(++num, new CodeInstruction(OpCodes.Ldarga, (object)0)); list.Insert(++num, new CodeInstruction(OpCodes.Call, (object)method_AutoDepositToChest)); return list.AsEnumerable(); } private static void AutoDepositToChest(ref Beehive __instance) { //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) Beehive beehive = __instance; List nearbyChests = InventoryAssistant.GetNearbyChests(((Component)beehive).gameObject, Helper.Clamp(Configuration.Current.Beehive.autoDepositRange, 1f, 50f)); if (beehive.GetHoneyLevel() != beehive.m_maxHoney) { return; } while (beehive.GetHoneyLevel() > 0) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(((Object)((Component)beehive.m_honeyItem).gameObject).name); ZNetView.m_forceDisableInit = true; GameObject val = Object.Instantiate(itemPrefab); ZNetView.m_forceDisableInit = false; bool num = spawnNearbyChest(val.GetComponent(), mustHaveItem: true); Object.Destroy((Object)(object)val); if (!num) { return; } } if (beehive.GetHoneyLevel() == 0) { beehive.m_spawnEffect.Create(beehive.m_spawnPoint.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); } bool spawnNearbyChest(ItemDrop item, bool mustHaveItem) { foreach (Container item in nearbyChests) { Inventory inventory = item.GetInventory(); if ((!mustHaveItem || inventory.HaveItem(item.m_itemData.m_shared.m_name, true)) && inventory.AddItem(item.m_itemData)) { beehive.m_nview.GetZDO().Set("level", beehive.GetHoneyLevel() - 1); InventoryAssistant.ConveyContainerToNetwork(item); return true; } } if (mustHaveItem) { return spawnNearbyChest(item, mustHaveItem: false); } return false; } } } [HarmonyPatch(typeof(Character), "Damage")] public static class Character_Damage_Patch { public static void Prefix(ref Character __instance, ref HitData hit) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown if (Configuration.Current.Tameable.IsEnabled && isMortality(TameableMortalityTypes.Immortal)) { ZDO zDO = __instance.m_nview.GetZDO(); Tameable component = ((Component)__instance).GetComponent(); if (__instance.IsTamed() && zDO != null && hit != null && !((Object)(object)component == (Object)null) && ShouldIgnoreDamage(__instance, hit, zDO)) { hit = new HitData(); } } } public static void Postfix(ref Character __instance, ref HitData hit) { if (Configuration.Current.Tameable.IsEnabled && isMortality(TameableMortalityTypes.Essential)) { ZDO zDO = __instance.m_nview.GetZDO(); Tameable component = ((Component)__instance).GetComponent(); if (__instance.IsTamed() && zDO != null && hit != null && !((Object)(object)component == (Object)null) && __instance.GetHealth() <= 5f && ShouldIgnoreDamage(__instance, hit, zDO)) { __instance.SetHealth(__instance.GetMaxHealth()); __instance.m_animator.SetBool("sleeping", true); zDO.Set("sleeping", true); zDO.Set("isRecoveringFromStun", true); } } } private static bool isMortality(TameableMortalityTypes type) { if (Mathf.Clamp(Configuration.Current.Tameable.mortality, 0, 2) == (int)type) { return true; } return false; } private static bool ShouldIgnoreDamage(Character __instance, HitData hit, ZDO zdo) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (Configuration.Current.Tameable.ownerDamageOverride) { Character attacker = hit.GetAttacker(); if ((Object)(object)attacker == (Object)(object)((Component)__instance).GetComponent().GetPlayer(attacker.GetZDOID())) { return false; } } return true; } } [HarmonyPatch(typeof(Character), "UpdateGroundContact")] public static class Character_UpdateGroundContact_Transpiler { private static readonly MethodInfo method_calculateFallDamage = AccessTools.Method(typeof(Character_UpdateGroundContact_Transpiler), "calculateFallDamage", (Type[])null, (Type[])null); [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown if (!Configuration.Current.Player.IsEnabled) { return instructions; } List list = instructions.ToList(); bool flag = false; for (int i = 0; i < list.Count; i++) { if (flag || !(list[i].opcode != OpCodes.Newobj)) { if (list[i].opcode == OpCodes.Newobj) { flag = true; } else if (list[i].opcode == OpCodes.Ldloc_2) { list[i].opcode = OpCodes.Ldloc_0; list.Insert(i + 1, new CodeInstruction(OpCodes.Call, (object)method_calculateFallDamage)); return list.AsEnumerable(); } } } PatchLog.Failed("Character_UpdateGroundContact_Transpiler", "Fall damage will be unchanged."); return instructions; } private static float calculateFallDamage(float fallDistance) { if (fallDistance < 4f) { return 0f; } return Math.Min(Helper.applyModifierValue((fallDistance - 4f) / 16f * 100f, Configuration.Current.Player.fallDamageScalePercent), Configuration.Current.Player.maxFallDamage); } } [HarmonyPatch(typeof(Character), "GetHoverText")] public static class Character_GetHoverText_Patch { [UsedImplicitly] public static void Postfix(Character __instance, ref string __result) { Growup component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { ProcreationHelpers.AddGrowupInformation(__instance, component, ref __result); } } } [HarmonyPatch(typeof(Chat), "OnNewChatMessage", new Type[] { typeof(GameObject), typeof(long), typeof(Vector3), typeof(Type), typeof(UserInfo), typeof(string) })] public static class Chat_OnNewChatMessage_Patch { [UsedImplicitly] private static bool Prefix(ref Chat __instance, GameObject go, long senderID, Vector3 pos, Type type, UserInfo sender, string text) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Invalid comparison between Unknown and I4 //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 ChatConfiguration chat = Configuration.Current.Chat; if (!chat.IsEnabled) { return true; } if ((int)type != 2) { if ((int)type == 3) { return chat.pingDistance <= 0f || Helper.IsSenderPlayerInRange(senderID, chat.pingDistance); } return true; } return chat.shoutDistance <= 0f || chat.outOfRangeShoutsDisplayInChatWindow || Helper.IsSenderPlayerInRange(senderID, chat.shoutDistance); } } [HarmonyPatch(typeof(Chat), "AddInworldText", new Type[] { typeof(GameObject), typeof(long), typeof(Vector3), typeof(Type), typeof(UserInfo), typeof(string) })] public static class Chat_AddInworldText_Patch { [UsedImplicitly] private static bool Prefix(ref Chat __instance, long senderID, Type type, UserInfo user, string text) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 if ((int)type != 2) { return true; } ChatConfiguration chat = Configuration.Current.Chat; if (!chat.IsEnabled || !chat.outOfRangeShoutsDisplayInChatWindow) { return true; } float shoutDistance = chat.shoutDistance; if (!(shoutDistance <= 0f)) { return Helper.IsSenderPlayerInRange(senderID, shoutDistance); } return true; } } [HarmonyPatch(typeof(Chat), "AddInworldText", new Type[] { typeof(GameObject), typeof(long), typeof(Vector3), typeof(Type), typeof(UserInfo), typeof(string) })] public static class Chat_AddInworldText_Transpiler { private static readonly MethodInfo Method_String_ToUpper = AccessTools.Method(typeof(string), "ToUpper", (Type[])null, (Type[])null); private static readonly MethodInfo Method_String_ToLowerInvariant = AccessTools.Method(typeof(string), "ToLowerInvariant", (Type[])null, (Type[])null); [UsedImplicitly] [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown ChatConfiguration chat = Configuration.Current.Chat; if (!chat.IsEnabled || chat.forcedCase) { return instructions; } List list = instructions.ToList(); try { return new CodeMatcher((IEnumerable)list, generator).MatchStartForward((CodeMatch[])(object)new CodeMatch[3] { CodeMatch.op_Implicit(OpCodes.Ldarg_S), new CodeMatch((OpCode?)OpCodes.Callvirt, (object)Method_String_ToLowerInvariant, (string)null), CodeMatch.op_Implicit(OpCodes.Starg_S) }).ThrowIfNotMatch("No match for code that sets whispers to lower case.", Array.Empty()).RemoveInstructions(3) .Start() .MatchStartForward((CodeMatch[])(object)new CodeMatch[3] { CodeMatch.op_Implicit(OpCodes.Ldarg_S), new CodeMatch((OpCode?)OpCodes.Callvirt, (object)Method_String_ToUpper, (string)null), CodeMatch.op_Implicit(OpCodes.Starg_S) }) .ThrowIfNotMatch("No match for code that sets shouts to upper case.", Array.Empty()) .RemoveInstructions(3) .InstructionEnumeration(); } catch (Exception exception) { PatchLog.Failed("Chat_AddInworldText_Transpiler", "The `Chat.forcedCase` setting will not work.", exception); return list; } } } [HarmonyPatch(typeof(Console), "Awake")] public static class Console_Awake_Patch { private static void Postfix(ref Console __instance) { ((Terminal)__instance).AddString("ValheimPlus [0.10.1.0] is loaded."); if (!ValheimPlusPlugin.isUpToDate && ValheimPlusPlugin.newestVersion != "Unknown") { ((Terminal)__instance).AddString("ValheimPlus [0.10.1.0] is outdated, version [" + ValheimPlusPlugin.newestVersion + "] is available."); ((Terminal)__instance).AddString("Please visit https://github.com/Grantapher/ValheimPlus/releases/latest."); } else { ((Terminal)__instance).AddString("ValheimPlus [0.10.1.0] is up to date."); } ((Terminal)__instance).AddString(""); } } [HarmonyPatch(typeof(Console), "IsConsoleEnabled")] public static class Console_IsConsoleEnabled_Patch { private static bool Prefix(ref Console __instance, ref bool __result) { if (Configuration.Current.Game.IsEnabled && Configuration.Current.Game.disableConsole) { __result = false; return false; } return true; } } [HarmonyPatch(typeof(Container), "Awake")] public static class Container_Awake_Patch { private const int woodChestInventoryMaxRows = 10; private const int woodChestInventoryMinRows = 2; private const int woodChestInventoryMaxCol = 8; private const int woodChestInventoryMinCol = 3; private const int personalChestInventoryMaxRows = 20; private const int personalChestInventoryMinRows = 2; private const int personalChestInventoryMaxCol = 8; private const int personalChestInventoryMinCol = 3; private const int ironChestInventoryMaxRows = 20; private const int ironChestInventoryMinRows = 3; private const int ironChestInventoryMaxCol = 8; private const int ironChestInventoryMinCol = 3; private const int blackmetalChestInventoryMaxRows = 20; private const int blackmetalChestInventoryMinRows = 3; private const int blackmetalChestInventoryMaxCol = 8; private const int blackmetalChestInventoryMinCol = 3; private const int karveChestInventoryMaxRows = 30; private const int karveChestInventoryMinRows = 2; private const int karveChestInventoryMaxCol = 8; private const int karveChestInventoryMinCol = 2; private const int longboatChestInventoryMaxRows = 30; private const int longboatChestInventoryMinRows = 3; private const int longboatChestInventoryMaxCol = 8; private const int longboatChestInventoryMinCol = 6; private const int cartChestInventoryMaxRows = 30; private const int cartChestInventoryMinRows = 3; private const int cartChestInventoryMaxCol = 8; private const int cartChestInventoryMinCol = 6; private static void Postfix(Container __instance, ref Inventory ___m_inventory) { ApplyConfiguredSize(__instance, ref ___m_inventory); if (Configuration.Current.Inventory.IsEnabled && !((Object)(object)__instance == (Object)null) && ___m_inventory != null) { __instance.m_width = ___m_inventory.m_width; __instance.m_height = ___m_inventory.m_height; } } private static void ApplyConfiguredSize(Container __instance, ref Inventory ___m_inventory) { if (!Configuration.Current.Inventory.IsEnabled) { return; } if ((Object)(object)__instance == (Object)null || ___m_inventory == null || !Object.op_Implicit((Object)(object)((Component)__instance).transform.parent)) { if (___m_inventory != null) { string name = ___m_inventory.m_name; ref int width = ref ___m_inventory.m_width; ref int height = ref ___m_inventory.m_height; switch (name) { case "$piece_chestprivate": height = Helper.Clamp(Configuration.Current.Inventory.personalChestRows, 2, 20); width = Helper.Clamp(Configuration.Current.Inventory.personalChestColumns, 3, 8); break; case "$piece_chestwood": height = Helper.Clamp(Configuration.Current.Inventory.woodChestRows, 2, 10); width = Helper.Clamp(Configuration.Current.Inventory.woodChestColumns, 3, 8); break; case "$piece_chest": height = Helper.Clamp(Configuration.Current.Inventory.ironChestRows, 3, 20); width = Helper.Clamp(Configuration.Current.Inventory.ironChestColumns, 3, 8); break; case "$piece_chestblackmetal": height = Helper.Clamp(Configuration.Current.Inventory.blackmetalChestRows, 3, 20); width = Helper.Clamp(Configuration.Current.Inventory.blackmetalChestColumns, 3, 8); break; } } } else { string name2 = ((Object)((Component)__instance).transform.parent).name; _ = ___m_inventory.m_name; ref int width2 = ref ___m_inventory.m_width; ref int height2 = ref ___m_inventory.m_height; if (name2.Contains("Karve")) { height2 = Helper.Clamp(Configuration.Current.Inventory.karveInventoryRows, 2, 30); width2 = Helper.Clamp(Configuration.Current.Inventory.karveInventoryColumns, 2, 8); } else if (name2.Contains("VikingShip")) { height2 = Helper.Clamp(Configuration.Current.Inventory.longboatInventoryRows, 3, 30); width2 = Helper.Clamp(Configuration.Current.Inventory.longboatInventoryColumns, 6, 8); } else if (name2.Contains("Cart")) { height2 = Helper.Clamp(Configuration.Current.Inventory.cartInventoryRows, 3, 30); width2 = Helper.Clamp(Configuration.Current.Inventory.cartInventoryColumns, 6, 8); } } } } [HarmonyPatch(typeof(Container), "RPC_StackResponse")] public static class Container_RPC_StackResponse_Patch { public static TaskCompletionSource ResponseReceived = new TaskCompletionSource(); [UsedImplicitly] private static void Postfix(long uid, bool granted) { ResponseReceived.TrySetResult(granted); } } [HarmonyPatch(typeof(CookingStation), "FindCookableItem")] public static class CookingStation_FindCookableItem_Transpiler { private static List nearbyChests; private static readonly MethodInfo Method_PullCookableItemFromNearbyChests = AccessTools.Method(typeof(CookingStation_FindCookableItem_Transpiler), "PullCookableItemFromNearbyChests", (Type[])null, (Type[])null); [UsedImplicitly] [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown CraftFromChestConfiguration craftFromChest = Configuration.Current.CraftFromChest; if (!craftFromChest.IsEnabled || craftFromChest.disableCookingStation) { return instructions; } List list = instructions.ToList(); for (int i = 0; i < list.Count; i++) { if (list[i].opcode == OpCodes.Ldnull) { list[i] = new CodeInstruction(OpCodes.Ldarg_0, (object)null) { labels = list[i].labels }; list.Insert(++i, new CodeInstruction(OpCodes.Call, (object)Method_PullCookableItemFromNearbyChests)); list.Insert(++i, new CodeInstruction(OpCodes.Stloc_3, (object)null)); list.Insert(++i, new CodeInstruction(OpCodes.Ldloc_3, (object)null)); return list; } } PatchLog.Failed("CookingStation_FindCookableItem_Transpiler", "Cooking stations will not take food from nearby chests."); return list; } private static ItemData PullCookableItemFromNearbyChests(CookingStation station) { if (station.GetFreeSlot() == -1) { return null; } Stopwatch stopwatch = GameObjectAssistant.GetStopwatch(((Component)station).gameObject); int num = Helper.Clamp(Configuration.Current.CraftFromChest.lookupInterval, 1, 10) * 1000; if (nearbyChests == null || !stopwatch.IsRunning || stopwatch.ElapsedMilliseconds > num) { nearbyChests = InventoryAssistant.GetNearbyChests(((Component)station).gameObject, Helper.Clamp(Configuration.Current.CraftFromChest.range, 1f, 50f), !Configuration.Current.CraftFromChest.ignorePrivateAreaCheck); stopwatch.Restart(); } foreach (ItemConversion item in station.m_conversion) { ItemData itemData = item.m_from.m_itemData; foreach (Container nearbyChest in nearbyChests) { if (nearbyChest.GetInventory().HaveItem(itemData.m_shared.m_name, true)) { InventoryAssistant.RemoveItemFromChest(nearbyChest, itemData); GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(((Object)((Component)item.m_from).gameObject).name); ZNetView.m_forceDisableInit = true; GameObject obj = Object.Instantiate(itemPrefab); ZNetView.m_forceDisableInit = false; return obj.GetComponent().m_itemData; } } } return null; } } public static class CookingStationFuel { [HarmonyPatch(typeof(CookingStation), "Awake")] public static class CookingStation_Awake_Patch { [UsedImplicitly] private static void Postfix(CookingStation __instance) { OvenConfiguration oven = Configuration.Current.Oven; if (__instance.m_useFuel && oven.IsEnabled && oven.infiniteFuel) { ZNetView nview = __instance.m_nview; if (nview != null && nview.IsValid()) { __instance.SetFuel((float)__instance.m_maxFuel); } } } } [HarmonyPatch(typeof(CookingStation), "UpdateFuel")] public static class CookingStation_UpdateFuel_Patch { [UsedImplicitly] private static void Prefix(CookingStation __instance, ref float dt) { OvenConfiguration oven = Configuration.Current.Oven; if (oven.IsEnabled && oven.infiniteFuel) { dt = 0f; } } } [HarmonyPatch(typeof(CookingStation), "UpdateCooking")] public static class CookingStation_UpdateCooking_Patch { [UsedImplicitly] private static void Prefix(CookingStation __instance) { OvenConfiguration oven = Configuration.Current.Oven; if (!__instance.m_useFuel || !oven.IsEnabled || !oven.autoFuel) { return; } ZNetView nview = __instance.m_nview; if (nview != null && nview.IsValid()) { Stopwatch stopwatch = GameObjectAssistant.GetStopwatch(((Component)__instance).gameObject); if (!stopwatch.IsRunning || stopwatch.ElapsedMilliseconds >= 1000) { stopwatch.Restart(); AddFuelFromNearbyChests(__instance); } } } } private static void AddFuelFromNearbyChests(CookingStation __instance) { int num = __instance.m_maxFuel - (int)Math.Ceiling(__instance.GetFuel()); if (num < 1) { return; } ItemData itemData = __instance.m_fuelItem.m_itemData; int num2 = InventoryAssistant.RemoveItemInAmountFromAllNearbyChests(((Component)__instance).gameObject, Helper.Clamp(Configuration.Current.Oven.autoRange, 1f, 50f), itemData, num, !Configuration.Current.Oven.ignorePrivateAreaCheck); if (num2 >= 1) { for (int i = 0; i < num2; i++) { __instance.m_nview.InvokeRPC("RPC_AddFuel", Array.Empty()); } ValheimPlusPlugin.Logger.LogDebug((object)$"Added {num2} fuel({itemData.m_shared.m_name}) in {__instance.m_name}"); } } } internal class CraftingStationChanges { [HarmonyPatch(typeof(CraftingStation), "Start")] public static class WorkbenchRangeIncrease { private static void Prefix(ref CraftingStation __instance, ref float ___m_rangeBuild, GameObject ___m_areaMarker) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) if (Configuration.Current.Workbench.IsEnabled && Configuration.Current.Workbench.workbenchRange > 0f) { try { ___m_rangeBuild = Configuration.Current.Workbench.workbenchRange; ___m_areaMarker.GetComponent().m_radius = ___m_rangeBuild; float num = Configuration.Current.Workbench.workbenchRange / 20f; ___m_areaMarker.gameObject.transform.localScale = new Vector3(num, 1f, num); Helper.ResizeChildEffectArea((MonoBehaviour)(object)__instance, (Type)4, (Configuration.Current.Workbench.workbenchEnemySpawnRange > 0f) ? Configuration.Current.Workbench.workbenchEnemySpawnRange : Configuration.Current.Workbench.workbenchRange); } catch { } } } } [HarmonyPatch(typeof(CraftingStation), "CheckUsable")] public static class WorkbenchRemoveRestrictions { private static bool Prefix(ref CraftingStation __instance, ref Player player, ref bool showMessage, ref bool __result) { if (Configuration.Current.Workbench.disableRoofCheck && Configuration.Current.Workbench.IsEnabled) { __instance.m_craftRequireRoof = false; } return true; } } } [HarmonyPatch(typeof(Demister), "OnEnable")] internal static class Demister_OnEnable_Patch { private static readonly string wispLight = "demister_ball"; private static readonly string wispTorch = "piece_groundtorch_mist"; private static readonly string mistwalker = "Mistwalker"; private static void Postfix(ref Demister __instance) { GameObject gameObject = ((Component)__instance).gameObject; if (Utils.GetPrefabName(((Object)gameObject.transform.root).name) == wispLight && Configuration.Current.Demister.IsEnabled) { EditRange(gameObject, Configuration.Current.Demister.wispLight); } else if (Utils.GetPrefabName(((Object)gameObject.transform.root).name) == wispTorch && Configuration.Current.Demister.IsEnabled) { EditRange(gameObject, Configuration.Current.Demister.wispTorch); } else if (Utils.GetPrefabName(((Object)gameObject.transform.parent).name) == mistwalker && Configuration.Current.Demister.IsEnabled) { EditRange(gameObject, Configuration.Current.Demister.Mistwalker); } } private static void EditRange(GameObject gameObject, float range) { gameObject.GetComponentInChildren().endRange = range; } } [HarmonyPatch(typeof(DropTable), "GetDropList", new Type[] { typeof(int) })] public static class DropTable_GetDropList_Patch { [UsedImplicitly] private static void Prefix(ref DropTable __instance, ref List __result, int amount, ref float __state) { __state = __instance.m_dropChance; GatherConfiguration gathering = Configuration.Current.Gathering; if (gathering.IsEnabled && gathering.dropChance != 0f && Mathf.Approximately(__instance.m_dropChance, 1f)) { float value = Helper.applyModifierValue(__instance.m_dropChance, gathering.dropChance); __instance.m_dropChance = Helper.Clamp(value, 0f, 1f); } } [UsedImplicitly] private static void Postfix(ref DropTable __instance, ref List __result, ref float __state) { __instance.m_dropChance = __state; GatherConfiguration gathering = Configuration.Current.Gathering; if (!gathering.IsEnabled) { return; } List list = new List(); foreach (GameObject item in __result) { float num = ((Object)item).name switch { "Wood" => gathering.wood, "FineWood" => gathering.fineWood, "RoundLog" => gathering.coreWood, "ElderBark" => gathering.elderBark, "YggdrasilWood" => gathering.yggdrasilWood, "Stone" => gathering.stone, "BlackMarble" => gathering.blackMarble, "TinOre" => gathering.tinOre, "CopperOre" => gathering.copperOre, "CopperScrap" => gathering.copperScrap, "IronScrap" => gathering.ironScrap, "SilverOre" => gathering.silverOre, "Chitin" => gathering.chitin, "Feathers" => gathering.feather, "Grausten" => gathering.grausten, "Blackwood" => gathering.blackwood, "FlametalOreNew" => gathering.flametalOre, "ProustitePowder" => gathering.proustitePowder, _ => 1f, }; if (num == 1f) { list.Add(item); continue; } int num2 = Helper.applyModifierValueWithChance(1f, num); for (int i = 0; i < num2; i++) { list.Add(item); } } __result = list; } } public static class EggGrowHelpers { private static readonly FieldInfo Field_ItemData_M_Stack = AccessTools.Field(typeof(ItemData), "m_stack"); public static CodeMatcher ApplyStackTranspiler(IEnumerable instructions, ILGenerator generator, string caller) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown EggConfiguration egg = Configuration.Current.Egg; List list = instructions.ToList(); CodeMatcher val = new CodeMatcher((IEnumerable)list, generator); if (!egg.IsEnabled || !egg.canStack) { return val; } try { return val.MatchEndForward((CodeMatch[])(object)new CodeMatch[2] { new CodeMatch((Func)((CodeInstruction inst) => CodeInstructionExtensions.LoadsField(inst, Field_ItemData_M_Stack, false)), (string)null), CodeMatch.op_Implicit(OpCodes.Ldc_I4_1) }).ThrowIfNotMatch("No match for code that checks egg stack size.", Array.Empty()).Set(OpCodes.Ldc_I4, (object)int.MaxValue) .Start(); } catch (Exception exception) { PatchLog.Failed(caller, "The `Egg.canStack` setting will not work.", exception); return new CodeMatcher((IEnumerable)list, generator); } } } [HarmonyPatch(typeof(EggGrow), "Start")] public static class EggGrow_Start_Patch { [UsedImplicitly] public static void Prefix(EggGrow __instance) { EggConfiguration egg = Configuration.Current.Egg; if (egg.IsEnabled) { __instance.m_growTime = egg.hatchTime; __instance.m_requireNearbyFire = egg.requireShelter; __instance.m_requireUnderRoof = egg.requireShelter; } } } [HarmonyPatch(typeof(EggGrow), "CanGrow")] public static class EggGrow_CanGrow_Transpiler { [UsedImplicitly] public static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { return EggGrowHelpers.ApplyStackTranspiler(instructions, generator, "EggGrow_CanGrow_Transpiler").InstructionEnumeration(); } } [HarmonyPatch(typeof(EggGrow), "GrowUpdate")] public static class EggGrow_GrowUpdate_Transpiler { private static readonly MethodInfo Method_SpawnAll = AccessTools.Method(typeof(EggGrow_GrowUpdate_Transpiler), "SpawnAll", (Type[])null, (Type[])null); private static readonly FieldInfo Field_EggGrow_M_Nview = AccessTools.Field(typeof(EggGrow), "m_nview"); private static readonly MethodInfo Method_ZNetView_Destroy = AccessTools.Method(typeof(ZNetView), "Destroy", (Type[])null, (Type[])null); [UsedImplicitly] public static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Expected O, but got Unknown EggConfiguration egg = Configuration.Current.Egg; if (!egg.IsEnabled || !egg.canStack) { return instructions; } List list = instructions.ToList(); CodeMatcher val = EggGrowHelpers.ApplyStackTranspiler(list, generator, "EggGrow_GrowUpdate_Transpiler"); try { return val.MatchStartForward((CodeMatch[])(object)new CodeMatch[3] { CodeMatch.op_Implicit(OpCodes.Ldarg_0), new CodeMatch((Func)((CodeInstruction inst) => CodeInstructionExtensions.LoadsField(inst, Field_EggGrow_M_Nview, false)), (string)null), new CodeMatch((Func)((CodeInstruction inst) => CodeInstructionExtensions.Calls(inst, Method_ZNetView_Destroy)), (string)null) }).ThrowIfNotMatch("No match for code that destroys the ZNetView.", Array.Empty()).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)Method_SpawnAll) }) .InstructionEnumeration(); } catch (Exception exception) { PatchLog.Failed("EggGrow_GrowUpdate_Transpiler", "The `Egg.canStack` setting will not work.", exception); return list; } } private static void SpawnAll(EggGrow instance) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) int stack = instance.m_item.m_itemData.m_stack; for (int i = 0; i < stack - 1; i++) { Character component = Object.Instantiate(instance.m_grownPrefab, ((Component)instance).transform.position, ((Component)instance).transform.rotation).GetComponent(); instance.m_hatchEffect.Create(((Component)instance).transform.position, ((Component)instance).transform.rotation, (Transform)null, 1f, -1, default(ZDOID)); if (Object.op_Implicit((Object)(object)component)) { component.SetTamed(instance.m_tamed); component.SetLevel(instance.m_item.m_itemData.m_quality); } } } } [HarmonyPatch(typeof(EggGrow), "GetHoverText")] public static class EggGrow_GetHoverText_Patch { [UsedImplicitly] public static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { return EggGrowHelpers.ApplyStackTranspiler(instructions, generator, "EggGrow_GetHoverText_Patch").InstructionEnumeration(); } [UsedImplicitly] public static void Postfix(EggGrow __instance, ref string __result) { if (!Configuration.Current.Egg.IsEnabled || !Configuration.Current.Egg.showHatchTime) { return; } int num = __result.IndexOf("\n", StringComparison.Ordinal); if (num > 0) { string text = __result.Substring(0, num); if (text.Contains(Localization.instance.Localize("$item_chicken_egg_warm"))) { string timeLeft = GetTimeLeft(__instance.m_nview.GetZDO().GetFloat(ZDOVars.s_growStart, 0f)); string text2 = __result.Substring(num); __result = text + timeLeft + text2; } } } private static string GetTimeLeft(float growStart) { double num = ZNet.instance.GetTimeSeconds() - (double)growStart; int num2 = (int)Math.Max(0.0, (double)Configuration.Current.Egg.hatchTime - num); string text = ((num2 < 120) ? (num2 + " seconds") : (num / 60.0 + " minutes")); return "\nTime left: " + text; } } public static class TimeManipulation { [HarmonyPatch(typeof(EnvMan), "Awake")] public static class EnvMan_Awake_Patch { [UsedImplicitly] private static void Postfix(ref EnvMan __instance) { if (Configuration.Current.Time.IsEnabled) { __instance.m_dayLengthSec = (long)Configuration.Current.Time.totalDayTimeInSeconds; } } } [HarmonyPatch(typeof(EnvMan), "RescaleDayFraction")] public static class EnvMan_RescaleDayFraction_Patch { [UsedImplicitly] private static void Postfix(ref float __result) { if (Configuration.Current.Time.IsEnabled && Configuration.Current.Time.forcePartOfDay) { __result = Mathf.Clamp01(Configuration.Current.Time.forcePartOfDayTime); } } } [HarmonyPatch(typeof(EnvMan), "RescaleDayFraction")] public static class EnvMan_RescaleDayFraction_Transpiler { [UsedImplicitly] [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { if (!Configuration.Current.Time.IsEnabled || Configuration.Current.Time.forcePartOfDay) { return instructions; } List list = instructions.ToList(); int[] array = ReplaceFloats(list); int[] array2 = new int[3] { 4, 2, 1 }; if (!array.SequenceEqual(array2)) { PatchLog.Failed("EnvMan_RescaleDayFraction_Transpiler", "`Time.nightDurationModifier` will not work. Expected [" + GeneralExtensions.Join((IEnumerable)array2, (Func)null, ", ") + "] but was [" + GeneralExtensions.Join((IEnumerable)array, (Func)null, ", ") + "]."); } return list; } } [HarmonyPatch(typeof(EnvMan), "GetMorningStartSec")] public static class EnvMan_GetMorningStartSec_Transpiler { [UsedImplicitly] [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { if (!Configuration.Current.Time.IsEnabled || Configuration.Current.Time.forcePartOfDay) { return instructions; } List list = instructions.ToList(); int[] array = ReplaceFloats(list); int[] array2 = new int[3] { 1, 0, 0 }; if (!array.SequenceEqual(array2)) { PatchLog.Failed("EnvMan_GetMorningStartSec_Transpiler", "`Time.nightDurationModifier` will not work. Expected [" + GeneralExtensions.Join((IEnumerable)array2, (Func)null, ", ") + "] but was [" + GeneralExtensions.Join((IEnumerable)array, (Func)null, ", ") + "]."); } return list; } } [HarmonyPatch(typeof(EnvMan), "SkipToMorning")] public static class EnvMan_SkipToMorning_Transpiler { [UsedImplicitly] [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { if (!Configuration.Current.Time.IsEnabled || Configuration.Current.Time.forcePartOfDay) { return instructions; } List list = instructions.ToList(); int[] array = ReplaceFloats(list); int[] array2 = new int[3] { 1, 0, 0 }; if (!array.SequenceEqual(array2)) { PatchLog.Failed("EnvMan_SkipToMorning_Transpiler", "`Time.nightDurationModifier` will not work. Expected [" + GeneralExtensions.Join((IEnumerable)array2, (Func)null, ", ") + "] but was [" + GeneralExtensions.Join((IEnumerable)array, (Func)null, ", ") + "]."); } return list; } } private static bool FloatingEquals(this float f1, float f2) { return (double)Math.Abs(f1 - f2) < 1E-05; } private static int[] ReplaceFloats(List il) { float[] array = new float[3] { 0.15f, 0.85f, 0.7f }; float num = Mathf.Clamp01(Configuration.Current.Time.nightPercent / 200f); float[] array2 = new float[3] { num, 1f - num, 1f - 2f * num }; int[] array3 = new int[3]; foreach (CodeInstruction item in il) { if (item.opcode != OpCodes.Ldc_R4) { continue; } float f = (float)item.operand; for (int i = 0; i < array.Length; i++) { if (array[i].FloatingEquals(f)) { item.operand = array2[i]; array3[i]++; break; } } } return array3; } } [HarmonyPatch(typeof(EnvMan), "SetEnv")] public static class EnvMan_SetEnv_Patch { [UsedImplicitly] private static void Prefix(ref EnvSetup env) { if (Configuration.Current.Game.IsEnabled && Configuration.Current.Game.disableFog) { env.m_fogDensityNight = 0f; env.m_fogDensityMorning = 0f; env.m_fogDensityDay = 0f; env.m_fogDensityEvening = 0f; } if (Configuration.Current.Brightness.IsEnabled) { ApplyEnvModifier(env); } } private static void ApplyEnvModifier(EnvSetup env) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) env.m_ambColorNight = ApplyBrightnessModifier(env.m_ambColorNight, Configuration.Current.Brightness.nightBrightnessMultiplier); env.m_fogColorNight = ApplyBrightnessModifier(env.m_fogColorNight, Configuration.Current.Brightness.nightBrightnessMultiplier); env.m_fogColorSunNight = ApplyBrightnessModifier(env.m_fogColorSunNight, Configuration.Current.Brightness.nightBrightnessMultiplier); env.m_sunColorNight = ApplyBrightnessModifier(env.m_sunColorNight, Configuration.Current.Brightness.nightBrightnessMultiplier); } private static Color ApplyBrightnessModifier(Color color, float multiplier) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) float num = default(float); float num2 = default(float); float num3 = default(float); Color.RGBToHSV(color, ref num, ref num2, ref num3); float num4 = ((!(multiplier >= 0f)) ? (1f - Mathf.Sqrt(Mathf.Abs(multiplier)) * 0.00010699527f) : (Mathf.Sqrt(multiplier) * 0.00010699527f + 1f)); num3 = Mathf.Clamp01(num3 * num4); return Color.HSVToRGB(num, num2, num3); } } [HarmonyPatch(typeof(EnvMan), "SetParticleArrayEnabled")] public static class EnvMan_SetParticleArrayEnabled_Patch { [UsedImplicitly] private static void Postfix(GameObject[] psystems) { if (!Configuration.Current.Game.IsEnabled || !Configuration.Current.Game.disableFog) { return; } for (int i = 0; i < psystems.Length; i++) { MistEmitter componentInChildren = psystems[i].GetComponentInChildren(); if (Object.op_Implicit((Object)(object)componentInChildren)) { ((Behaviour)componentInChildren).enabled = false; } } } } [HarmonyPatch(typeof(EventSystem), "OnApplicationFocus")] public static class EventSystem_OnApplicationFocus_Patch { [UsedImplicitly] private static void Postfix(bool hasFocus) { if (PlayerPrefs.GetInt("MuteGameInBackground", 0) == 1) { AudioListener.volume = (hasFocus ? 1f : 0f); } } } [HarmonyPatch(typeof(FejdStartup), "Awake")] public static class HookServerStart { private static void Postfix(ref FejdStartup __instance) { if (Configuration.Current.Server.IsEnabled && Configuration.Current.Server.disableServerPassword) { __instance.m_minimumPasswordLength = 0; } } } [HarmonyPatch(typeof(FejdStartup), "SetupGui")] public static class FejdStartup_SetupGui_Patch { private static void Postfix(ref FejdStartup __instance) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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) Transform transform = __instance.m_moddedText.transform; transform.localPosition += new Vector3(0f, 50f); __instance.m_versionLabel.fontSize = 14f; ((Component)__instance.m_versionLabel).GetComponent().sizeDelta = new Vector2(900f, 30f); TMP_Text versionLabel = __instance.m_versionLabel; versionLabel.text += "\nValheimPlus 0.10.1.0 (Grantapher)"; ValheimPlusPlugin.Logger.LogDebug((object)("Version text: \"" + __instance.m_versionLabel.text + "\"").Replace("\n", ", ")); } } [HarmonyPatch(typeof(FejdStartup), "IsPublicPasswordValid")] public static class ChangeServerPasswordBehavior { private static void Postfix(ref bool __result) { if (Configuration.Current.Server.IsEnabled && Configuration.Current.Server.disableServerPassword) { __result = true; } } } [HarmonyPatch(typeof(FejdStartup), "GetPublicPasswordError")] public static class RemovePublicPasswordError { private static bool Prefix(ref string __result) { if (Configuration.Current.Server.IsEnabled && Configuration.Current.Server.disableServerPassword) { __result = ""; return false; } return true; } } [HarmonyPatch(typeof(Fermenter), "Awake")] public static class ApplyFermenterChanges { private static bool Prefix(ref float ___m_fermentationDuration, ref Fermenter __instance) { if (Configuration.Current.Fermenter.IsEnabled) { float fermenterDuration = Configuration.Current.Fermenter.fermenterDuration; if (fermenterDuration > 0f) { ___m_fermentationDuration = fermenterDuration; } } return true; } } [HarmonyPatch(typeof(Fermenter), "GetItemConversion")] public static class ApplyFermenterItemCountChanges { private static void Postfix(ref ItemConversion __result) { if (Configuration.Current.Fermenter.IsEnabled) { int fermenterItemsProduced = Configuration.Current.Fermenter.fermenterItemsProduced; if (fermenterItemsProduced > 0) { __result.m_producedItems = fermenterItemsProduced; } } } } [HarmonyPatch(typeof(Fermenter), "GetHoverText")] public static class Fermenter_GetHoverText_Patch { private static bool Prefix(ref Fermenter __instance, ref string __result) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected I4, but got Unknown if (!Configuration.Current.Fermenter.IsEnabled || !Configuration.Current.Fermenter.showDuration) { return true; } if (!PrivateArea.CheckAccess(((Component)__instance).transform.position, 0f, false, true)) { __result = Localization.instance.Localize(__instance.m_name + "\n$piece_noaccess"); return false; } Status status = __instance.GetStatus(); switch ((int)status) { case 0: __result = Localization.instance.Localize(__instance.m_name + " ( $piece_container_empty )\n[$KEY_Use] $piece_fermenter_add"); return false; case 1: { string contentName2 = __instance.GetContentName(); if (__instance.m_exposed) { __result = Localization.instance.Localize(__instance.m_name + " ( " + contentName2 + ", $piece_fermenter_exposed )"); return false; } double num = (double)__instance.m_fermentationDuration - __instance.GetFermentationTime(); string text = ""; int num2 = (int)num / 60; __result = string.Concat(str2: ((int)num < 120) ? ((int)num + " seconds") : (num2 + " minutes"), str0: Localization.instance.Localize(__instance.m_name + " ( " + contentName2 + ", $piece_fermenter_fermenting )"), str1: " (", str3: ")"); return false; } case 3: { string contentName = __instance.GetContentName(); __result = Localization.instance.Localize(__instance.m_name + " ( " + contentName + ", $piece_fermenter_ready )\n[$KEY_Use] $piece_fermenter_tap"); return false; } default: __result = __instance.m_name; return false; } } } [HarmonyPatch(typeof(Fermenter), "SlowUpdate")] public static class Fermenter_SlowUpdate_Transpiler { private static MethodInfo method_GameObject_SetActive = AccessTools.Method(typeof(GameObject), "SetActive", (Type[])null, (Type[])null); private static MethodInfo method_InvokeRPCTap = AccessTools.Method(typeof(Fermenter_SlowUpdate_Transpiler), "InvokeRPCTap", (Type[])null, (Type[])null); private static MethodInfo method_AddItemFromNearbyChests = AccessTools.Method(typeof(Fermenter_SlowUpdate_Transpiler), "AddItemFromNearbyChests", (Type[])null, (Type[])null); [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown if (!Configuration.Current.Fermenter.IsEnabled) { return instructions; } List list = instructions.ToList(); int num = 0; bool flag = false; for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], method_GameObject_SetActive)) { num++; } if (num == 3) { list.Insert(++i, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Insert(++i, new CodeInstruction(OpCodes.Call, (object)method_AddItemFromNearbyChests)); flag = true; break; } } if (!flag) { PatchLog.Failed("Fermenter_SlowUpdate_Transpiler", "Fermenters will not take items from nearby chests."); return instructions; } flag = false; for (int num2 = list.Count - 1; num2 >= 0; num2--) { if (CodeInstructionExtensions.Calls(list[num2], method_GameObject_SetActive)) { list.Insert(++num2, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Insert(++num2, new CodeInstruction(OpCodes.Call, (object)method_InvokeRPCTap)); return list.AsEnumerable(); } } PatchLog.Failed("Fermenter_SlowUpdate_Transpiler", "Fermenters will not tap themselves."); return instructions; } private static void InvokeRPCTap(Fermenter __instance) { if (Configuration.Current.Fermenter.autoDeposit) { __instance.m_nview.InvokeRPC("RPC_Tap", new object[0]); } } private static void AddItemFromNearbyChests(Fermenter __instance) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (!Configuration.Current.Fermenter.autoFuel || (int)__instance.GetStatus() != 0 || !__instance.m_nview.IsOwner()) { return; } Stopwatch stopwatch = GameObjectAssistant.GetStopwatch(((Component)__instance).gameObject); if (stopwatch.IsRunning && stopwatch.ElapsedMilliseconds <= 1000) { return; } foreach (Container nearbyChest in InventoryAssistant.GetNearbyChests(((Component)__instance).gameObject, Helper.Clamp(Configuration.Current.Fermenter.autoRange, 1f, 50f), !Configuration.Current.Fermenter.ignorePrivateAreaCheck)) { ItemData val = __instance.FindCookableItem(nearbyChest.GetInventory()); if (val != null && InventoryAssistant.RemoveItemFromChest(nearbyChest, val) != 0) { __instance.m_nview.InvokeRPC("RPC_AddItem", new object[2] { StringExtensionMethods.GetStableHashCode(((Object)val.m_dropPrefab).name), val.m_cheated }); ValheimPlusPlugin.Logger.LogDebug((object)("Added " + val.m_shared.m_name + " to " + __instance.m_name)); break; } } stopwatch.Restart(); } } [HarmonyPatch(typeof(Fermenter), "DelayedTap")] public static class Fermenter_DelayedTap_Transpiler { private static MethodInfo method_Object_Instantiate = AccessTools.Method(typeof(Object), "Instantiate", new Type[3] { typeof(ItemDrop), typeof(Vector3), typeof(Quaternion) }, (Type[])null); private static MethodInfo method_DropItemToNearbyChest = AccessTools.Method(typeof(Fermenter_DelayedTap_Transpiler), "DropItemToNearbyChest", (Type[])null, (Type[])null); [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown if (!Configuration.Current.Fermenter.IsEnabled || !Configuration.Current.Fermenter.autoDeposit) { return instructions; } List list = instructions.ToList(); int num = -1; for (int i = 0; i < list.Count; i++) { if (list[i].opcode == OpCodes.Brfalse) { num = i; list.Insert(++i, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Insert(++i, new CodeInstruction(OpCodes.Ldloca, (object)0)); list.Insert(++i, new CodeInstruction(OpCodes.Call, (object)method_DropItemToNearbyChest)); list.Insert(++i, new CodeInstruction(OpCodes.Brtrue, list[num].operand)); return list.AsEnumerable(); } } PatchLog.Failed("Fermenter_DelayedTap_Transpiler", "Fermenters will not deposit into nearby chests."); return instructions; } private static bool DropItemToNearbyChest(Fermenter __instance, ref ItemConversion itemConversion) { List nearbyChests = InventoryAssistant.GetNearbyChests(((Component)__instance).gameObject, Helper.Clamp(Configuration.Current.Fermenter.autoRange, 1f, 50f), !Configuration.Current.Fermenter.ignorePrivateAreaCheck); int num = 0; for (int i = 0; i < itemConversion.m_producedItems; i++) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(((Object)((Component)itemConversion.m_to).gameObject).name); ZNetView.m_forceDisableInit = true; GameObject val = Object.Instantiate(itemPrefab); ZNetView.m_forceDisableInit = false; ItemDrop component = val.GetComponent(); ItemDrop.OnCreateNew(component, (__instance.m_delayedTapItemCheated || __instance.m_nview.GetZDO().GetBool(ZDOVars.s_cheated, false)) && !PlayerProfile.s_bypassCheatChecks); bool num2 = spawnNearbyChest(component, mustHaveItem: true); Object.Destroy((Object)(object)val); if (!num2) { ItemConversion obj = itemConversion; obj.m_producedItems -= num; return false; } num++; } return true; bool spawnNearbyChest(ItemDrop item, bool mustHaveItem) { foreach (Container item in nearbyChests) { Inventory inventory = item.GetInventory(); if ((!mustHaveItem || inventory.HaveItem(item.m_itemData.m_shared.m_name, true)) && inventory.AddItem(item.m_itemData)) { InventoryAssistant.ConveyContainerToNetwork(item); return true; } } if (mustHaveItem) { return spawnNearbyChest(item, mustHaveItem: false); } return false; } } } internal static class FireplaceFuel { [HarmonyPatch(typeof(Fireplace), "Awake")] public static class Fireplace_Awake_Patch { [UsedImplicitly] private static void Postfix(ref Fireplace __instance) { FireSourceConfiguration fireSource = Configuration.Current.FireSource; if (fireSource.IsEnabled) { bool flag = IsTorch(__instance.m_nview.GetPrefabName()); if ((!flag || fireSource.torches) && (flag || fireSource.fires)) { __instance.m_infiniteFuel = true; } } } } [HarmonyPatch(typeof(Fireplace), "UpdateFireplace")] public static class Fireplace_UpdateFireplace_Transpiler { private static readonly MethodInfo Method_Zdo_SetFloat = AccessTools.Method(typeof(ZDO), "GetFloat", new Type[2] { typeof(int), typeof(float) }, (Type[])null); private static readonly MethodInfo Method_AddFuelFromNearbyChests = AccessTools.Method(typeof(Fireplace_UpdateFireplace_Transpiler), "AddFuelFromNearbyChests", (Type[])null, (Type[])null); [HarmonyTranspiler] [UsedImplicitly] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown FireSourceConfiguration fireSource = Configuration.Current.FireSource; if (!fireSource.IsEnabled || !fireSource.autoFuel) { return instructions; } List list = instructions.ToList(); for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], Method_Zdo_SetFloat)) { i -= 2; list.Insert(++i, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Insert(++i, new CodeInstruction(OpCodes.Call, (object)Method_AddFuelFromNearbyChests)); i++; list.Insert(++i, new CodeInstruction(OpCodes.Add, (object)null)); return list; } } PatchLog.Failed("Fireplace_UpdateFireplace_Transpiler", "Fireplaces will not take fuel from nearby chests."); return list; } private static float AddFuelFromNearbyChests(Fireplace __instance) { FireSourceConfiguration fireSource = Configuration.Current.FireSource; bool flag = IsTorch(__instance.m_nview.GetPrefabName()); if ((flag && fireSource.torches) || (!flag && fireSource.fires)) { return 0f; } int num = (int)Math.Ceiling(__instance.m_nview.GetZDO().GetFloat(ZDOVars.s_fuel, 0f)); int num2 = (int)__instance.m_maxFuel - num; if (num2 <= 0) { return 0f; } Stopwatch stopwatch = GameObjectAssistant.GetStopwatch(((Component)__instance).gameObject); if (stopwatch.IsRunning && stopwatch.ElapsedMilliseconds < 1000) { return 0f; } stopwatch.Restart(); ItemData itemData = __instance.m_fuelItem.m_itemData; float range = Helper.Clamp(fireSource.autoRange, 1f, 50f); int num3 = InventoryAssistant.RemoveItemInAmountFromAllNearbyChests(((Component)__instance).gameObject, range, itemData, num2, !fireSource.ignorePrivateAreaCheck); if (num3 <= 0) { return 0f; } __instance.m_nview.InvokeRPC("RPC_AddFuelAmount", new object[1] { (float)num3 }); ValheimPlusPlugin.Logger.LogDebug((object)$"Added {num3} fuel({itemData.m_shared.m_name}) in {__instance.m_name}"); return num3; } } private static readonly HashSet TorchItemNames = new HashSet { "piece_groundtorch_wood", "piece_groundtorch", "piece_groundtorch_green", "piece_groundtorch_blue", "piece_walltorch", "piece_brazierceiling01", "piece_brazierfloor01", "piece_brazierfloor02", "piece_jackoturnip" }; private static bool IsTorch(string itemName) { return TorchItemNames.Contains(itemName); } } [HarmonyPatch(typeof(Fireplace), "Interact")] public static class Fireplace_Interact_Transpiler { private static readonly Dictionary> NearbyChestsDictionary = new Dictionary>(); private static readonly MethodInfo Method_Inventory_HaveItem = AccessTools.Method(typeof(Inventory), "HaveItem", new Type[2] { typeof(string), typeof(bool) }, (Type[])null); private static readonly MethodInfo Method_ReplaceInventoryRefByChest = AccessTools.Method(typeof(Fireplace_Interact_Transpiler), "ReplaceInventoryRefByChest", (Type[])null, (Type[])null); [HarmonyTranspiler] [UsedImplicitly] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown if (!Configuration.Current.CraftFromChest.IsEnabled) { return instructions; } List list = instructions.ToList(); for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], Method_Inventory_HaveItem)) { list[i - 7] = CodeInstructionExtensions.MoveLabelsFrom(new CodeInstruction(OpCodes.Ldloca_S, (object)1), list[i - 7]); list[i] = new CodeInstruction(OpCodes.Call, (object)Method_ReplaceInventoryRefByChest); list.RemoveRange(i - 5, 5); return list.AsEnumerable(); } } PatchLog.Failed("Fireplace_Interact_Transpiler", "Fireplaces will not accept fuel past their normal limit."); return list; } private static bool ReplaceInventoryRefByChest(ref Inventory inventory, Fireplace fireplace) { string itemName = fireplace.m_fuelItem.m_itemData.m_shared.m_name; if (inventory.HaveItem(itemName, true)) { return true; } CraftFromChestConfiguration config = Configuration.Current.CraftFromChest; GameObject gameObject = ((Component)fireplace).gameObject; Stopwatch stopwatch = GameObjectAssistant.GetStopwatch(gameObject); float hash = GameObjectAssistant.GetGameObjectPositionHash(gameObject); if (NearbyChestsDictionary.TryGetValue(hash, out var nearbyChests)) { int num = Helper.Clamp(config.lookupInterval, 1, 10) * 1000; if (!stopwatch.IsRunning || stopwatch.ElapsedMilliseconds > num) { UpdateNearbyChests(); } } else { UpdateNearbyChests(); } Inventory val = nearbyChests.Select((Container container) => container.GetInventory()).FirstOrDefault((Func)((Inventory inv) => inv.HaveItem(itemName, true))); if (inventory != null) { inventory = val; } return val != null; void UpdateNearbyChests() { float range = Helper.Clamp(config.range, 1f, 50f); nearbyChests = InventoryAssistant.GetNearbyChests(((Component)fireplace).gameObject, range, !config.ignorePrivateAreaCheck); stopwatch.Restart(); NearbyChestsDictionary[hash] = nearbyChests; } } } [HarmonyPatch(typeof(Game), "Start")] public static class Game_Start_Patch { [UsedImplicitly] private static void Prefix() { ZRoutedRpc.instance.Register("VPlusMapSync", (Action)VPlusMapSync.RPC_VPlusMapSync); ZRoutedRpc.instance.Register("VPlusMapAddPin", (Action)VPlusMapPinSync.RPC_VPlusMapAddPin); ZRoutedRpc.instance.Register("VPlusAck", (Action)VPlusAck.RPC_VPlusAck); } } [HarmonyPatch(typeof(Game), "GetDifficultyDamageScalePlayer")] public static class Game_GetDifficultyDamageScale_Patch { [UsedImplicitly] private static void Prefix(Game __instance) { GameConfiguration game = Configuration.Current.Game; if (game.IsEnabled) { __instance.m_damageScalePerPlayer = game.gameDifficultyDamageScale / 100f; } } } [HarmonyPatch(typeof(Game), "GetDifficultyDamageScaleEnemy")] public static class Game_GetDifficultyHealthScale_Patch { [UsedImplicitly] private static void Prefix(Game __instance) { GameConfiguration game = Configuration.Current.Game; if (game.IsEnabled) { __instance.m_healthScalePerPlayer = game.gameDifficultyHealthScale / 100f; } } } [HarmonyPatch(typeof(Game), "UpdateRespawn")] public static class Game_UpdateRespawn_Patch { [UsedImplicitly] private static void Prefix(ref Game __instance, float dt) { PlayerConfiguration player = Configuration.Current.Player; if (player.IsEnabled && !player.iHaveArrivedOnSpawn) { __instance.m_firstSpawn = false; } } } [HarmonyPatch(typeof(Game), "GetPlayerDifficulty")] public static class Game_GetPlayerDifficulty_Patch { private static readonly FieldInfo Field_M_DifficultyScaleRange = AccessTools.Field(typeof(Game), "m_difficultyScaleRange"); [UsedImplicitly] [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown if (!Configuration.Current.Game.IsEnabled) { return instructions; } float num = Math.Min(Configuration.Current.Game.difficultyScaleRange, 2); List list = instructions.ToList(); for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.LoadsField(list[i], Field_M_DifficultyScaleRange, false)) { list.RemoveAt(i - 1); list[i - 1] = new CodeInstruction(OpCodes.Ldc_R4, (object)num); return list.AsEnumerable(); } } PatchLog.Failed("Game_GetPlayerDifficulty_Patch", "`Game.difficultyScaleRange` will not work."); return list; } [UsedImplicitly] private static void Postfix(ref int __result) { GameConfiguration game = Configuration.Current.Game; if (game.IsEnabled) { if (game.setFixedPlayerCountTo > 0) { __result = game.setFixedPlayerCountTo; } __result += game.extraPlayerCountNearby; } } } [HarmonyPatch(typeof(GameCamera), "UpdateCamera")] public static class BlockCameraScrollInAEM { private static void Prefix(GameCamera __instance) { if (AEM.isActive) { __instance.m_maxDistance = __instance.m_distance; __instance.m_minDistance = __instance.m_distance; } else if (Configuration.Current.Camera.IsEnabled) { if (Configuration.Current.Camera.cameraMaximumZoomDistance >= 1f && Configuration.Current.Camera.cameraMaximumZoomDistance <= 100f) { __instance.m_maxDistance = Configuration.Current.Camera.cameraMaximumZoomDistance; } if (Configuration.Current.Camera.cameraBoatMaximumZoomDistance >= 1f && Configuration.Current.Camera.cameraBoatMaximumZoomDistance <= 100f) { __instance.m_maxDistanceBoat = Configuration.Current.Camera.cameraBoatMaximumZoomDistance; } if (Configuration.Current.Camera.cameraFOV >= 1f && Configuration.Current.Camera.cameraFOV <= 140f) { __instance.m_fov = Configuration.Current.Camera.cameraFOV; } __instance.m_minDistance = 1f; } else { __instance.m_maxDistance = 6f; __instance.m_minDistance = 1f; } } } public static class GrowupHelpers { public static int GetGrowTimeLeft(Growup growup) { return (int)((double)growup.m_growTime - growup.m_baseAI.GetTimeSinceSpawned().TotalSeconds); } } [HarmonyPatch(typeof(Growup), "Start")] public static class Growup_Start_Patch { [UsedImplicitly] public static void Prefix(Growup __instance) { EggConfiguration egg = Configuration.Current.Egg; ProcreationConfiguration procreation = Configuration.Current.Procreation; Humanoid component = __instance.m_grownPrefab.GetComponent(); if (Object.op_Implicit((Object)(object)component)) { if (egg.IsEnabled && ((Character)component).m_name == "$enemy_hen") { __instance.m_growTime = egg.growTime; } else if (procreation.IsEnabled && ProcreationHelpers.IsValidAnimalType(((Character)component).m_name)) { Helper.applyModifierValueTo(ref __instance.m_growTime, procreation.maturityDurationMultiplier); } } } } [HarmonyPatch(typeof(Hud), "DamageFlash")] public static class Hud_DamageFlash_Patch { [UsedImplicitly] private static void Postfix(Hud __instance) { HudConfiguration hud = Configuration.Current.Hud; if (hud.IsEnabled && hud.removeDamageFlash) { ((Component)__instance.m_damageScreen).gameObject.SetActive(false); } } } [HarmonyPatch(typeof(Humanoid), "GetCurrentWeapon")] public static class ModifyCurrentWeapon { [UsedImplicitly] private static void Postfix(ref ItemData __result, ref Humanoid __instance) { Humanoid obj = __instance; Player val = (Player)(object)((obj is Player) ? obj : null); if (val != null && Configuration.Current.Player.IsEnabled && !(__result?.m_shared?.m_name != "Unarmed")) { float val2 = ((Character)val).GetSkillFactor((SkillType)11) * Configuration.Current.Player.baseUnarmedDamage; __result.m_shared.m_damages.m_blunt = Math.Max(2f, val2); } } } [HarmonyPatch(typeof(Humanoid), "EquipItem")] public static class Humanoid_EquipItem_Patch { private static bool Postfix(bool __result, Humanoid __instance, ItemData item) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Invalid comparison between Unknown and I4 //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Invalid comparison between Unknown and I4 //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Invalid comparison between Unknown and I4 if (Configuration.Current.Player.IsEnabled && Configuration.Current.Player.autoEquipShield && __result && ((Character)__instance).IsPlayer()) { ItemData rightItem = __instance.m_rightItem; if (rightItem != null && (int)rightItem.m_shared.m_itemType == 3 && (int)item.m_shared.m_itemType != 5) { List allItems = __instance.m_inventory.GetAllItems(); ItemData val = null; foreach (ItemData item2 in allItems) { if ((int)item2.m_shared.m_itemType == 5) { if (val == null) { val = item2; } else if (val.m_shared.m_blockPower < item2.m_shared.m_blockPower) { val = item2; } } } if (val != null) { __instance.EquipItem(val, false); } } } return __result; } } [HarmonyPatch(typeof(Humanoid), "UnequipItem")] public static class Humanoid_UnequipItem_Patch { private static void Postfix(Humanoid __instance, ItemData item) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Invalid comparison between Unknown and I4 if (!Configuration.Current.Player.IsEnabled || !Configuration.Current.Player.autoUnequipShield || item == null || (int)item.m_shared.m_itemType != 3 || !((Character)__instance).IsPlayer()) { return; } foreach (ItemData allItem in __instance.m_inventory.GetAllItems()) { if ((int)allItem.m_shared.m_itemType == 5 && allItem.m_equipped) { __instance.UnequipItem(allItem, false); } } } } public static class UpdateEquipmentState { public static bool shouldReequipItemsAfterSwimming; } [HarmonyPatch(typeof(Humanoid), "UpdateEquipment")] public static class Humanoid_UpdateEquipment_Patch { private static bool Prefix(Humanoid __instance) { if (!Configuration.Current.Player.IsEnabled || !Configuration.Current.Player.reequipItemsAfterSwimming || Configuration.Current.Player.dontUnequipItemsWhenSwimming) { return true; } if (((Character)__instance).IsPlayer() && ((Character)__instance).IsSwimming() && !((Character)__instance).IsOnGround()) { if (__instance.m_leftItem != null || __instance.m_rightItem != null) { UpdateEquipmentState.shouldReequipItemsAfterSwimming = true; } } else if (((Character)__instance).IsPlayer() && !((Character)__instance).IsSwimming() && ((Character)__instance).IsOnGround() && UpdateEquipmentState.shouldReequipItemsAfterSwimming) { __instance.ShowHandItems(false, true); UpdateEquipmentState.shouldReequipItemsAfterSwimming = false; } return true; } } [HarmonyPatch(typeof(Humanoid), "UpdateEquipment")] public static class Player_Humanoid_UpdateEquipment { private static readonly MethodInfo Method_Humanoid_HideHandItems = AccessTools.Method(typeof(Humanoid), "HideHandItems", (Type[])null, (Type[])null); [HarmonyTranspiler] [UsedImplicitly] public static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown PlayerConfiguration player = Configuration.Current.Player; if (!player.IsEnabled || !player.dontUnequipItemsWhenSwimming) { return instructions; } List list = instructions.ToList(); try { CodeMatcher val = new CodeMatcher((IEnumerable)list, generator); int pos = val.MatchEndForward((CodeMatch[])(object)new CodeMatch[2] { new CodeMatch((OpCode?)OpCodes.Call, (object)Method_Humanoid_HideHandItems, (string)null), new CodeMatch((OpCode?)OpCodes.Pop, (object)null, (string)null) }).ThrowIfNotMatch("No match for `HideHandItems` followed by a `pop`", Array.Empty()).Pos; int pos2 = val.MatchBack(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null) }).ThrowIfNotMatch("No match for `this`", Array.Empty()).Pos; return val.RemoveInstructionsInRange(pos2, pos).InstructionEnumeration(); } catch (Exception exception) { PatchLog.Failed("Player_Humanoid_UpdateEquipment", null, exception); return list; } } } [HarmonyPatch(typeof(Inventory), "IsTeleportable")] public static class Inventory_IsTeleportable_Patch { [UsedImplicitly] private static void Postfix(ref bool __result) { ItemsConfiguration items = Configuration.Current.Items; if (items.IsEnabled && items.noTeleportPrevention) { __result = true; } } } [HarmonyPatch(typeof(Inventory), "TopFirst")] public static class Inventory_TopFirst_Patch { [UsedImplicitly] public static void Postfix(ref bool __result) { InventoryConfiguration inventory = Configuration.Current.Inventory; if (inventory.IsEnabled && inventory.inventoryFillTopToBottom) { __result = true; } } } [HarmonyPatch(typeof(Player), "SetInventorySize")] public static class Player_SetInventorySize_Patch { private static readonly MethodInfo Method_Inventory_SetHeight = AccessTools.Method(typeof(Inventory), "SetHeight", (Type[])null, (Type[])null); private static readonly MethodInfo Method_InventoryGui_SetInventorySize = AccessTools.Method(typeof(InventoryGui), "SetInventorySize", (Type[])null, (Type[])null); private static readonly MethodInfo Method_AtLeastConfigured = AccessTools.Method(typeof(Player_SetInventorySize_Patch), "AtLeastConfigured", (Type[])null, (Type[])null); [UsedImplicitly] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown if (!Configuration.Current.Inventory.IsEnabled) { return instructions; } List list = instructions.ToList(); try { return new CodeMatcher((IEnumerable)list, (ILGenerator)null).MatchStartForward((CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((Func)((CodeInstruction i) => CodeInstructionExtensions.Calls(i, Method_Inventory_SetHeight)), (string)null) }).ThrowIfNotMatch("No match for this.m_inventory.SetHeight(rows).", Array.Empty()).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Call, (object)Method_AtLeastConfigured) }) .MatchStartForward((CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((Func)((CodeInstruction i) => CodeInstructionExtensions.Calls(i, Method_InventoryGui_SetInventorySize)), (string)null) }) .ThrowIfNotMatch("No match for InventoryGui.instance.SetInventorySize(rows).", Array.Empty()) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Call, (object)Method_AtLeastConfigured) }) .InstructionEnumeration(); } catch (Exception exception) { PatchLog.Failed("Player_SetInventorySize_Patch", "playerInventoryRows will have no effect.", exception); return list; } } public static int AtLeastConfigured(int rows) { return Math.Max(rows, Configuration.Current.Inventory.playerInventoryRows); } } [HarmonyPatch(typeof(Player), "OnSpawned")] public static class Player_OnSpawned_InventorySize_Patch { [UsedImplicitly] public static void Postfix(Player __instance) { if (Configuration.Current.Inventory.IsEnabled && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { int playerInventoryRows = Configuration.Current.Inventory.playerInventoryRows; if (((Humanoid)__instance).GetInventory().GetHeight() < playerInventoryRows) { ((Humanoid)__instance).GetInventory().SetHeight(playerInventoryRows); InventoryGui.instance.SetInventorySize(playerInventoryRows); } } } } public static class Inventory_NearbyChests_Cache { public static List chests = new List(); public static readonly Stopwatch delta = new Stopwatch(); } [HarmonyPatch(typeof(Inventory), "MoveAll")] public static class Inventory_MoveAll_Patch { [UsedImplicitly] private static void Prefix(ref Inventory __instance, ref Inventory fromInventory) { InventoryConfiguration inventory = Configuration.Current.Inventory; if (!inventory.IsEnabled || !inventory.mergeWithExistingStacks) { return; } foreach (ItemData item in new List(fromInventory.GetAllItems())) { if (item.m_shared.m_maxStackSize <= 1) { continue; } foreach (ItemData item2 in __instance.m_inventory) { if (!(item2.m_shared.m_name != item.m_shared.m_name) && item2.m_quality == item.m_quality) { int num = Math.Min(item2.m_shared.m_maxStackSize - item2.m_stack, item.m_stack); item2.m_stack += num; if (item.m_stack == num) { fromInventory.RemoveItem(item); break; } item.m_stack -= num; } } } } } [HarmonyPatch(typeof(Inventory), "StackAll")] public static class Inventory_StackAll_Patch { private static bool ShouldMessage = false; private static bool IsProcessing = false; private static int ItemsBefore = 0; private static readonly MethodInfo Method_Inventory_ContainsItemByName = AccessTools.Method(typeof(Inventory), "ContainsItemByName", (Type[])null, (Type[])null); private static readonly MethodInfo Method_ContainsItemByName = AccessTools.Method(typeof(Inventory_StackAll_Patch), "ContainsItemByName", (Type[])null, (Type[])null); private static async Task QueueStackAll(List chests, Inventory fromInventory, Inventory instance) { IsProcessing = true; int containerCount = 0; foreach (Container chest in chests) { if (!chest.IsInUse()) { Inventory inventory = chest.GetInventory(); if (inventory != null && inventory != instance) { Container_RPC_StackResponse_Patch.ResponseReceived = new TaskCompletionSource(); chest.StackAll(); containerCount++; await Container_RPC_StackResponse_Patch.ResponseReceived.Task; } } } if (ShouldMessage) { int num = fromInventory.CountItems((string)null, -1, true); int num2 = ItemsBefore - num; string text = ((num2 > 0) ? $"$msg_stackall {num2} in {containerCount} Chests" : $"$msg_stackall_none in {containerCount} Chests"); ((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false); } IsProcessing = false; } private static void Prefix(Inventory fromInventory, ref bool message) { if (Configuration.Current.AutoStack.IsEnabled) { if (!IsProcessing) { ShouldMessage = message; ItemsBefore = fromInventory.CountItems((string)null, -1, true); } message = false; } } [UsedImplicitly] private static void Postfix(Inventory fromInventory, Inventory __instance, ref int __result) { AutoStackConfiguration autoStack = Configuration.Current.AutoStack; if (autoStack.IsEnabled && !IsProcessing) { QueueStackAll(InventoryAssistant.GetNearbyChests(((Component)Player.m_localPlayer).gameObject, Mathf.Clamp(autoStack.autoStackAllRange, 1f, 50f), !autoStack.autoStackAllIgnorePrivateAreaCheck), fromInventory, __instance); } } [UsedImplicitly] [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { AutoStackConfiguration autoStack = Configuration.Current.AutoStack; if (!autoStack.IsEnabled) { return instructions; } if (!autoStack.autoStackAllIgnoreEquipment && !autoStack.ignoreFood && !autoStack.ignoreAmmo && !autoStack.ignoreMead) { return instructions; } List list = instructions.ToList(); for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], Method_Inventory_ContainsItemByName)) { list[i].operand = Method_ContainsItemByName; return list.AsEnumerable(); } } PatchLog.Failed("Inventory_StackAll_Patch", "Stack All will not match items by name."); return list.AsEnumerable(); } public static bool ContainsItemByName(Inventory inventory, string name) { foreach (ItemData item in inventory.m_inventory) { if (!(item.m_shared.m_name != name) && (!Configuration.Current.AutoStack.ignoreAmmo || !item.IsAmmo()) && (!Configuration.Current.AutoStack.ignoreFood || !item.IsFood()) && (!Configuration.Current.AutoStack.ignoreMead || !item.IsMead()) && (!Configuration.Current.AutoStack.autoStackAllIgnoreEquipment || !item.IsEquipable())) { return true; } } return false; } } [HarmonyPatch(typeof(InventoryGrid), "UpdateGui")] public static class InventoryGrid_UpdateGui_Patch { private const float scrollbarPadding = 8f; private static float basePanelWidth = float.NaN; private static float baseGridInset; private static float baseBarOffset; [UsedImplicitly] private static void Prefix(InventoryGrid __instance) { LayoutContainerScrollbar(__instance); int width = __instance.m_inventory.GetWidth(); int height = __instance.m_inventory.GetHeight(); if (__instance.m_width == width && __instance.m_height == height && __instance.m_elements.Count != width * height) { __instance.m_width = ((__instance.m_width != 1) ? 1 : 2); } } private static void LayoutContainerScrollbar(InventoryGrid grid) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) if (!Configuration.Current.Inventory.IsEnabled) { return; } InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance == (Object)null || (Object)(object)grid != (Object)(object)instance.m_containerGrid || grid.m_inventory == null) { return; } Scrollbar scrollbar = grid.m_scrollbar; RectTransform container = instance.m_container; RectTransform component = ((Component)grid).gameObject.GetComponent(); RectTransform val = (RectTransform)(((Object)(object)scrollbar == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/); if ((Object)(object)val == (Object)null || (Object)(object)container == (Object)null || (Object)(object)component == (Object)null) { return; } float x = ((Transform)container).lossyScale.x; if (x <= 0f) { return; } float num = (float)grid.m_inventory.GetWidth() * grid.m_elementSpace * x; if (!(num <= 0f)) { if (float.IsNaN(basePanelWidth)) { basePanelWidth = container.sizeDelta.x; baseGridInset = component.offsetMax.x; baseBarOffset = val.anchoredPosition.x; } float num2 = 8f * x; float num3 = val.sizeDelta.x * x; float num4 = num + 3f * num2 + num3; if (num4 <= basePanelWidth * x) { Restore(component, container, val); return; } float num5 = num3 + num2; Set(component, container, val, (0f - num5) / x, num4 / x, (num4 / 2f - num2 - num3 / 2f) / x); } } private static void Restore(RectTransform gridRect, RectTransform panel, RectTransform bar) { Set(gridRect, panel, bar, baseGridInset, basePanelWidth, baseBarOffset); } private static void Set(RectTransform gridRect, RectTransform panel, RectTransform bar, float inset, float width, float barOffset) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) if (!Mathf.Approximately(gridRect.offsetMax.x, inset)) { gridRect.offsetMax = new Vector2(inset, gridRect.offsetMax.y); } if (!Mathf.Approximately(panel.sizeDelta.x, width)) { panel.sizeDelta = new Vector2(width, panel.sizeDelta.y); } if (!Mathf.Approximately(bar.anchoredPosition.x, barOffset)) { bar.anchoredPosition = new Vector2(barOffset, bar.anchoredPosition.y); } } } [HarmonyPatch(typeof(InventoryGui), "Show")] public static class InventoryGui_Show_Patch { public static void Postfix(InventoryGui __instance) { if (Configuration.Current.Inventory.IsEnabled) { __instance.m_firstContainerUpdate = true; } } } [HarmonyPatch(typeof(InventoryGui), "RepairOneItem")] public static class InventoryGui_RepairOneItem_Transpiler { private static MethodInfo method_EffectList_Create = AccessTools.Method(typeof(EffectList), "Create", (Type[])null, (Type[])null); private static MethodInfo method_CreateNoop = AccessTools.Method(typeof(InventoryGui_RepairOneItem_Transpiler), "CreateNoop", (Type[])null, (Type[])null); [HarmonyTranspiler] public static IEnumerable Transpile(IEnumerable instructions) { if (!Configuration.Current.Player.IsEnabled) { return instructions; } List list = instructions.ToList(); if (Configuration.Current.Player.autoRepair) { for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], method_EffectList_Create)) { list[i].opcode = OpCodes.Call; list[i].operand = method_CreateNoop; } } } return list.AsEnumerable(); } private static GameObject[] CreateNoop(EffectList _0, Vector3 _1, Quaternion _2, Transform _3, float _4, int _5, ZDOID _6) { return null; } } [HarmonyPatch(typeof(InventoryGui), "UpdateRepair")] public static class InventoryGui_UpdateRepair_Patch { [HarmonyPrefix] public static void Prefix(InventoryGui __instance) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) if (!Configuration.Current.Player.IsEnabled || !Configuration.Current.Player.autoRepair) { return; } CraftingStation currentCraftingStation = Player.m_localPlayer.GetCurrentCraftingStation(); if ((Object)(object)currentCraftingStation != (Object)null) { int num = 0; while (__instance.HaveRepairableItems()) { __instance.RepairOneItem(); num++; } if (num > 0) { currentCraftingStation.m_repairItemDoneEffects.Create(((Component)currentCraftingStation).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); } } } } [HarmonyPatch(typeof(InventoryGui), "SetupRequirement")] public static class InventoryGui_SetupRequirement_Patch { private static bool Prefix(Transform elementRoot, Requirement req, Player player, bool craft, int quality, int craftMultiplier, ref bool __result) { //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) if ((!Configuration.Current.Hud.IsEnabled && !Configuration.Current.CraftFromChest.IsEnabled) || (!Configuration.Current.Hud.showRequiredItems && !Configuration.Current.CraftFromChest.IsEnabled)) { return true; } Image component = ((Component)((Component)elementRoot).transform.Find("res_icon")).GetComponent(); TMP_Text component2 = ((Component)((Component)elementRoot).transform.Find("res_name")).GetComponent(); TMP_Text component3 = ((Component)((Component)elementRoot).transform.Find("res_amount")).GetComponent(); UITooltip component4 = ((Component)elementRoot).GetComponent(); if ((Object)(object)req.m_resItem != (Object)null) { ((Component)component).gameObject.SetActive(true); ((Component)component2).gameObject.SetActive(true); ((Component)component3).gameObject.SetActive(true); component.sprite = req.m_resItem.m_itemData.GetIcon(); ((Graphic)component).color = Color.white; component4.m_text = Localization.instance.Localize(req.m_resItem.m_itemData.m_shared.m_name); component2.text = Localization.instance.Localize(req.m_resItem.m_itemData.m_shared.m_name); int num = ((Humanoid)player).GetInventory().CountItems(req.m_resItem.m_itemData.m_shared.m_name, -1, true); int num2 = req.GetAmount(quality) * craftMultiplier; if (num2 <= 0) { InventoryGui.HideRequirement(elementRoot); __result = false; return false; } if (Configuration.Current.CraftFromChest.IsEnabled) { CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); GameObject val = ((currentCraftingStation != null) ? ((Component)currentCraftingStation).gameObject : null); Stopwatch stopwatch; if (!Object.op_Implicit((Object)(object)val) || !Configuration.Current.CraftFromChest.checkFromWorkbench) { val = ((Component)player).gameObject; stopwatch = Inventory_NearbyChests_Cache.delta; } else { stopwatch = GameObjectAssistant.GetStopwatch(val); } int num3 = Helper.Clamp(Configuration.Current.CraftFromChest.lookupInterval, 1, 10) * 1000; if (!stopwatch.IsRunning || stopwatch.ElapsedMilliseconds > num3) { Inventory_NearbyChests_Cache.chests = InventoryAssistant.GetNearbyChests(val, Helper.Clamp(Configuration.Current.CraftFromChest.range, 1f, 50f)); stopwatch.Restart(); } num += InventoryAssistant.GetItemAmountInItemList(InventoryAssistant.GetNearbyChestItemsByContainerList(Inventory_NearbyChests_Cache.chests), req.m_resItem.m_itemData); } component3.text = num + "/" + num2; if (num < num2) { ((Graphic)component3).color = ((Mathf.Sin(Time.time * 10f) > 0f) ? Color.red : Color.white); } else { ((Graphic)component3).color = Color.white; } component3.fontSize = 14f; if (component3.text.Length > 5) { component3.fontSize -= (float)(component3.text.Length - 5); } } __result = true; return false; } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] public static class InventoryGui_DoCrafting_Transpiler { private static MethodInfo method_Player_Inventory_RemoveItem = AccessTools.Method(typeof(Inventory), "RemoveItem", new Type[4] { typeof(string), typeof(int), typeof(int), typeof(bool) }, (Type[])null); private static MethodInfo method_UseItemFromInventoryOrChest = AccessTools.Method(typeof(InventoryGui_DoCrafting_Transpiler), "UseItemFromInventoryOrChest", (Type[])null, (Type[])null); [HarmonyTranspiler] public static IEnumerable Transpile(IEnumerable instructions) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown if (!Configuration.Current.CraftFromChest.IsEnabled) { return instructions; } List list = instructions.ToList(); for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], method_Player_Inventory_RemoveItem)) { list[i] = new CodeInstruction(OpCodes.Call, (object)method_UseItemFromInventoryOrChest); list.RemoveAt(i - 8); return list.AsEnumerable(); } } return instructions; } private static void UseItemFromInventoryOrChest(Player player, string itemName, int quantity, int quality, bool worldLevelBased) { Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory.CountItems(itemName, quality, true) >= quantity) { inventory.RemoveItem(itemName, quantity, quality, worldLevelBased); return; } CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); GameObject val = ((currentCraftingStation != null) ? ((Component)currentCraftingStation).gameObject : null); if (!Object.op_Implicit((Object)(object)val) || !Configuration.Current.CraftFromChest.checkFromWorkbench) { val = ((Component)player).gameObject; } List nearbyChests = InventoryAssistant.GetNearbyChests(val, Helper.Clamp(Configuration.Current.CraftFromChest.range, 1f, 50f), !Configuration.Current.CraftFromChest.ignorePrivateAreaCheck); int num = quantity; foreach (Container item in nearbyChests) { if (item.GetInventory().CountItems(itemName, quality, true) > 0) { num -= InventoryAssistant.RemoveItemFromChest(item, itemName, num); if (num == 0) { break; } } } } } public static class ItemDataExtensions { public static bool IsAmmo(this ItemData itemData) { if (!string.IsNullOrEmpty(itemData.m_shared.m_ammoType)) { return !itemData.m_shared.m_ammoType.EndsWith("turretbolt"); } return false; } public static bool IsFood(this ItemData itemData) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 if ((int)itemData.m_shared.m_itemType == 2) { if (!(itemData.m_shared.m_food > 0f) && !(itemData.m_shared.m_foodEitr > 0f)) { return itemData.m_shared.m_foodStamina > 0f; } return true; } return false; } public static bool IsMead(this ItemData itemData) { return itemData.m_shared.m_isDrink; } } [HarmonyPatch(typeof(ItemDrop), "Awake")] public static class ItemDrop_Awake_Patch { [UsedImplicitly] private static void Prefix(ref ItemDrop __instance) { ItemsConfiguration items = Configuration.Current.Items; if (items.IsEnabled) { SharedData shared = __instance.m_itemData.m_shared; shared.m_weight = Helper.applyModifierValue(shared.m_weight, items.baseItemWeightReduction); if (items.noTeleportPrevention) { shared.m_teleportable = true; } if (shared.m_maxStackSize > 1 && items.itemStackMultiplier >= 1f) { shared.m_maxStackSize = (int)Helper.applyModifierValue(shared.m_maxStackSize, items.itemStackMultiplier); } GameObject gameObject = ((Component)__instance).gameObject; if (items.itemsFloatInWater && Object.op_Implicit((Object)(object)gameObject.GetComponent()) && !Object.op_Implicit((Object)(object)gameObject.GetComponent())) { gameObject.AddComponent().m_waterLevelOffset = 0.5f; } } } } [HarmonyPatch(typeof(ItemDrop), "TimedDestruction")] public static class ItemDrop_TimedDestruction_Patch { private const int defaultSpawnTimeSeconds = 3600; private static MethodInfo method_SetDroppedItemDestroyDuration = AccessTools.Method(typeof(ItemDrop_TimedDestruction_Patch), "SetDroppedItemDestroyDuration", (Type[])null, (Type[])null); [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown if (!Configuration.Current.Items.IsEnabled) { return instructions; } List list = instructions.ToList(); for (int i = 0; i < list.Count; i++) { if (list[i].opcode == OpCodes.Ldc_R8) { list[i] = new CodeInstruction(OpCodes.Call, (object)method_SetDroppedItemDestroyDuration); return list.AsEnumerable(); } } PatchLog.Failed("ItemDrop_TimedDestruction_Patch", "Dropped items will use the game's own despawn time."); return instructions; } private static float SetDroppedItemDestroyDuration() { if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return 3600f; } return Helper.Clamp(Configuration.Current.Items.droppedItemOnGroundDurationInSeconds, 0f, 3600f); } } [HarmonyPatch(typeof(ItemData), "GetMaxDurability", new Type[] { typeof(int) })] public static class ItemDrop_GetMaxDurability_Patch { private static bool Prefix(ref ItemData __instance, ref int quality, ref float __result) { //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: 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_0175: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Expected I4, but got Unknown //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Invalid comparison between Unknown and I4 if (!Configuration.Current.Durability.IsEnabled) { return true; } string text = __instance.m_shared.m_name.Replace("$item_", "").Split(new char[1] { '_' })[0]; float num = (__result = __instance.m_shared.m_maxDurability + (float)Mathf.Max(0, quality - 1) * __instance.m_shared.m_durabilityPerLevel); float num2 = num; bool flag = false; switch (text) { case "pickaxe": flag = true; num2 = Helper.applyModifierValue(num, Configuration.Current.Durability.pickaxes); break; case "axe": flag = true; num2 = Helper.applyModifierValue(num, Configuration.Current.Durability.axes); break; case "hammer": flag = true; num2 = Helper.applyModifierValue(num, Configuration.Current.Durability.hammer); break; case "cultivator": flag = true; num2 = Helper.applyModifierValue(num, Configuration.Current.Durability.cultivator); break; case "hoe": flag = true; num2 = Helper.applyModifierValue(num, Configuration.Current.Durability.hoe); break; case "torch": flag = true; num2 = Helper.applyModifierValue(num, Configuration.Current.Durability.torch); break; } ItemType itemType = __instance.m_shared.m_itemType; switch (itemType - 3) { case 0: case 11: if (!flag) { num2 = Helper.applyModifierValue(num, Configuration.Current.Durability.weapons); } break; case 1: if (!flag) { num2 = Helper.applyModifierValue(num, Configuration.Current.Durability.bows); } break; case 2: if (!flag) { num2 = Helper.applyModifierValue(num, Configuration.Current.Durability.shields); } break; case 3: case 4: case 8: case 14: if (!flag && (int)__instance.m_shared.m_itemType != 5) { num2 = Helper.applyModifierValue(num, Configuration.Current.Durability.armor); } break; } if (num2 != num) { __result = num2; } return false; } } [HarmonyPatch(typeof(ItemData), "GetArmor", new Type[] { typeof(int), typeof(float) })] public static class ItemDrop_GetArmor_Patch { private static void Postfix(ref ItemData __instance, ref float __result) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Invalid comparison between Unknown and I4 //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Invalid comparison between Unknown and I4 //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 if (!Configuration.Current.Armor.IsEnabled) { return; } ItemType itemType = __instance.m_shared.m_itemType; if ((int)itemType <= 7) { if ((int)itemType != 6) { if ((int)itemType == 7) { __result = Helper.applyModifierValue(__result, Configuration.Current.Armor.chests); } } else { __result = Helper.applyModifierValue(__result, Configuration.Current.Armor.helmets); } } else if ((int)itemType != 11) { if ((int)itemType == 17) { __result = Helper.applyModifierValue(__result, Configuration.Current.Armor.capes); } } else { __result = Helper.applyModifierValue(__result, Configuration.Current.Armor.legs); } } } [HarmonyPatch(typeof(ItemData), "GetBaseBlockPower", new Type[] { typeof(int) })] public static class ItemDrop_GetBaseBlockPower_Patch { private static bool Prefix(ref ItemData __instance, ref int quality, ref float __result) { if (!Configuration.Current.Shields.IsEnabled) { return true; } float targetValue = __instance.m_shared.m_blockPower + (float)Mathf.Max(0, quality - 1) * __instance.m_shared.m_blockPowerPerLevel; __result = Helper.applyModifierValue(targetValue, Configuration.Current.Shields.blockRating); return false; } } internal class LuredWispModification { [HarmonyPatch(typeof(LuredWisp), "Awake")] public static class LuredWispPatch { private static readonly FieldRef m_despawnInDaylight = AccessTools.FieldRefAccess("m_despawnInDaylight"); [HarmonyPrefix] private static void Prefix(LuredWisp __instance) { if (Configuration.Current.WispSpawner.IsEnabled) { m_despawnInDaylight.Invoke(__instance) = Configuration.Current.WispSpawner.onlySpawnAtNight; } } } } [HarmonyPatch(typeof(Menu), "IsVisible")] public static class Menu_IsVisible_Patch { [UsedImplicitly] private static void Postfix(ref bool __result) { __result |= ConfigurationManagerWatcher.BlocksGameInput; } } [HarmonyPatch(typeof(Minimap))] public class HookExplore { [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(Minimap), "Explore", new Type[] { typeof(Vector3), typeof(float) })] public static void call_Explore(object instance, Vector3 p, float radius) { throw new NotImplementedException(); } } [HarmonyPatch(typeof(Minimap), "UpdateExplore")] public static class ChangeMapBehavior { internal const float MaxExploreRadius = 10000f; private static void Prefix(ref float dt, ref Player player, ref Minimap __instance, ref float ___m_exploreTimer, ref float ___m_exploreInterval) { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) if (!Configuration.Current.Map.IsEnabled) { return; } if (Configuration.Current.Map.shareMapProgression && ___m_exploreTimer + Time.deltaTime > ___m_exploreInterval && ZNet.instance.m_players.Any()) { foreach (PlayerInfo player2 in ZNet.instance.m_players) { HookExplore.call_Explore(__instance, player2.m_position, Mathf.Min(Configuration.Current.Map.exploreRadius, 10000f)); } } HookExplore.call_Explore(__instance, ((Component)player).transform.position, Mathf.Min(Configuration.Current.Map.exploreRadius, 10000f)); } } [HarmonyPatch(typeof(Minimap), "Awake")] public static class MinimapAwake { private static void Postfix() { if (ZNet.m_isServer && Configuration.Current.Map.IsEnabled && Configuration.Current.Map.shareMapProgression) { VPlusMapSync.ServerMapData = new BitArray(Minimap.instance.m_textureSize * Minimap.instance.m_textureSize); VPlusMapSync.LoadMapDataFromDisk(); ValheimPlusPlugin.MapSyncSaveTimer.Start(); } } } public static class MapPinEditor_Patches { [HarmonyPatch(typeof(Minimap), "AddPin")] public static class Minimap_AddPin_Patch { public static List shareablePins = new List(); private static void Postfix(ref Minimap __instance, ref PinData __result) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Invalid comparison between Unknown and I4 if (Configuration.Current.Map.IsEnabled && Configuration.Current.Map.shareAllPins && shareablePins.Contains(__result.m_type)) { if ((int)__instance.m_mode != 2) { VPlusMapPinSync.SendMapPinToServer(__result, keepQuiet: true); } else { VPlusMapPinSync.SendMapPinToServer(__result); } } } } public static GameObject pinEditorPanel; public static AssetBundle mapPinBundle; public static Dropdown iconSelected; public static InputField pinName; public static Toggle sharePin; public static Vector3 pinPos; } public class displayCartsAndBoatsOnMap { [HarmonyPatch(typeof(Minimap), "OnDestroy")] public static class Minimap_OnDestroy_Patch { private static void Postfix() { customPins.Clear(); icons.Clear(); } } [HarmonyPatch(typeof(Minimap), "UpdateMap")] public static class Minimap_UpdateMap_Patch { private static float timeCounter = updateInterval; private static void FindIcons() { GameObject val = ObjectDB.instance.m_itemByHash[hammerHashCode]; if (!Object.op_Implicit((Object)(object)val)) { return; } ItemDrop component = val.GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { return; } foreach (GameObject piece in component.m_itemData.m_shared.m_buildPieces.m_pieces) { Piece component2 = piece.GetComponent(); icons.Add(StringExtensionMethods.GetStableHashCode(((Object)component2).name), component2.m_icon); } } private static bool CheckPin(Minimap __instance, Player player, ZDO zdo, int hashCode, string pinName) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: 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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) if (zdo.m_prefab != hashCode) { return false; } PinData value; bool flag = customPins.TryGetValue(zdo, out value); Ship controlledShip = player.GetControlledShip(); if (Object.op_Implicit((Object)(object)controlledShip) && Vector3.Distance(((Component)controlledShip).transform.position, zdo.m_position) < 0.01f) { if (flag) { __instance.RemovePin(value); customPins.Remove(zdo); } return true; } if (!flag) { value = __instance.AddPin(zdo.m_position, (PinType)4, pinName, false, false, 0L, default(PlatformUserID)); if (icons.TryGetValue(hashCode, out var value2)) { value.m_icon = value2; } value.m_doubleSize = true; customPins.Add(zdo, value); } else { value.m_pos = zdo.m_position; } return true; } public static void Postfix(ref Minimap __instance, Player player, float dt, bool takeInput) { timeCounter += dt; if (timeCounter < updateInterval || !Configuration.Current.Map.IsEnabled || !Configuration.Current.Map.displayCartsAndBoats) { return; } timeCounter -= updateInterval; if (icons.Count == 0) { FindIcons(); } List[] objectsBySector = ZDOMan.instance.m_objectsBySector; foreach (List list in objectsBySector) { if (list == null) { continue; } foreach (ZDO item in list) { if (!CheckPin(__instance, player, item, CartHashcode, "Cart") && !CheckPin(__instance, player, item, RaftHashcode, "Raft") && !CheckPin(__instance, player, item, KarveHashcode, "Karve")) { CheckPin(__instance, player, item, LongshipHashcode, "Longship"); } } } foreach (KeyValuePair customPin in customPins) { if (!customPin.Key.IsValid()) { __instance.RemovePin(customPin.Value); customPins.Remove(customPin.Key); } } } } private static Dictionary customPins = new Dictionary(); private static Dictionary icons = new Dictionary(); private static int CartHashcode = StringExtensionMethods.GetStableHashCode("Cart"); private static int RaftHashcode = StringExtensionMethods.GetStableHashCode("Raft"); private static int KarveHashcode = StringExtensionMethods.GetStableHashCode("Karve"); private static int LongshipHashcode = StringExtensionMethods.GetStableHashCode("VikingShip"); private static int hammerHashCode = StringExtensionMethods.GetStableHashCode("Hammer"); private static float updateInterval = 5f; } [HarmonyPatch(typeof(MonsterAI), "UpdateSleep")] public static class MonsterAI_UpdateSleep_Patch { public static void Prefix(MonsterAI __instance, ref float dt) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) if (!Configuration.Current.Tameable.IsEnabled || (Object)(object)((Component)__instance).GetComponent() == (Object)null) { return; } ZDO zDO = ((BaseAI)__instance).m_nview.GetZDO(); if (Configuration.Current.Tameable.mortality == 1 && zDO != null && zDO.GetBool("isRecoveringFromStun", false)) { if (((BaseAI)__instance).m_character.m_moveDir != Vector3.zero) { ((BaseAI)__instance).StopMoving(); } if (__instance.m_sleepTimer != 0f) { __instance.m_sleepTimer = 0f; } float num = zDO.GetFloat("timeSinceStun", 0f) + dt; zDO.Set("timeSinceStun", num); if (num >= Configuration.Current.Tameable.stunRecoveryTime) { zDO.Set("timeSinceStun", 0f); __instance.m_sleepTimer = 0.5f; ((BaseAI)__instance).m_character.m_animator.SetBool("sleeping", false); zDO.Set("sleeping", false); zDO.Set("isRecoveringFromStun", false); } dt = 0f; } } } [HarmonyPatch(typeof(MonsterAI), "UpdateAI")] public static class MonsterAI_UpdateAI_Transpiler { [UsedImplicitly] private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator ilGenerator) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown List list = instructions.ToList(); if (!Configuration.Current.Tameable.IsEnabled || !Configuration.Current.Tameable.ignoreAlerted) { return list; } CodeMatcher val = new CodeMatcher((IEnumerable)list, ilGenerator); try { MethodInfo updateConsumeItem = AccessTools.Method(typeof(MonsterAI), "UpdateConsumeItem", (Type[])null, (Type[])null); Label label = val.MatchStartForward((CodeMatch[])(object)new CodeMatch[4] { CodeMatch.op_Implicit(OpCodes.Ldarg_0), CodeMatch.op_Implicit(OpCodes.Ldloc_0), CodeMatch.op_Implicit(OpCodes.Ldarg_1), new CodeMatch((Func)((CodeInstruction inst) => CodeInstructionExtensions.Calls(inst, updateConsumeItem)), (string)null) }).ThrowIfNotMatch("No match for UpdateConsumeItem method call.", Array.Empty()).Labels.First(); return val.MatchStartBackwards((CodeMatch[])(object)new CodeMatch[1] { CodeMatch.op_Implicit(OpCodes.Ret) }).ThrowIfNotMatch("Could not find the end of the conditional before UpdateConsumeItem call.", Array.Empty()).Advance(1) .Set(OpCodes.Br_S, (object)label) .InstructionEnumeration(); } catch (Exception exception) { PatchLog.Failed("MonsterAI_UpdateAI_Transpiler", "`Tameable.ignoreAlerted` will not work.", exception); return list; } } } public static class PickableYieldState { private static Dictionary _yieldModifierDict; public static int CalculateYield(GameObject item, int originalAmount) { if (!Configuration.Current.Pickable.IsEnabled) { return originalAmount; } if (_yieldModifierDict.TryGetValue(((Object)item).name, out var value)) { return Helper.applyModifierValueWithChance(originalAmount, value); } return originalAmount; } public static void InitialSetup() { List obj = new List { "Carrot", "Blueberries", "Cloudberry", "Raspberry", "Mushroom", "MushroomBlue", "MushroomYellow", "MushroomMagecap", "MushroomJotunPuffs", "MushroomSmokePuff", "Fiddleheadfern", "Vineberry", "Onion" }; List list = new List { "Barley", "CarrotSeeds", "Dandelion", "Flax", "Thistle", "TurnipSeeds", "Turnip", "OnionSeeds", "RoyalJelly", "VoltureEgg" }; List list2 = new List { "BoneFragments", "Flint", "Stone", "Wood", "Crystal", "Tar", "WolfHairBundle", "WolfClaw" }; List list3 = new List { "Amber", "AmberPearl", "Coins", "Ruby" }; List list4 = new List { "SurtlingCore" }; List list5 = new List { "BlackCore" }; List list6 = new List { "DragonEgg", "WitheredBone", "GoblinTotem" }; _yieldModifierDict = new Dictionary(); foreach (string item in obj) { _yieldModifierDict.Add(item, Configuration.Current.Pickable.edibles); } foreach (string item2 in list) { _yieldModifierDict.Add(item2, Configuration.Current.Pickable.flowersAndIngredients); } foreach (string item3 in list2) { _yieldModifierDict.Add(item3, Configuration.Current.Pickable.materials); } foreach (string item4 in list3) { _yieldModifierDict.Add(item4, Configuration.Current.Pickable.valuables); } foreach (string item5 in list4) { _yieldModifierDict.Add(item5, Configuration.Current.Pickable.surtlingCores); } foreach (string item6 in list5) { _yieldModifierDict.Add(item6, Configuration.Current.Pickable.blackCores); } foreach (string item7 in list6) { _yieldModifierDict.Add(item7, Configuration.Current.Pickable.questItems); } } } [HarmonyPatch(typeof(Pickable), "RPC_Pick")] public static class Pickable_RPC_Pick_Transpiler { private static readonly MethodInfo Method_CalculateYield = AccessTools.Method(typeof(PickableYieldState), "CalculateYield", (Type[])null, (Type[])null); private static readonly FieldInfo Field_ItemPrefab = AccessTools.Field(typeof(Pickable), "m_itemPrefab"); [HarmonyTranspiler] [UsedImplicitly] public static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected O, but got Unknown //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown if (!Configuration.Current.Pickable.IsEnabled) { return instructions; } List list = instructions.ToList(); for (int i = 0; i < list.Count; i++) { if (list[i].opcode == OpCodes.Stloc_1) { list.Insert(++i, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Insert(++i, new CodeInstruction(OpCodes.Ldfld, (object)Field_ItemPrefab)); list.Insert(++i, new CodeInstruction(OpCodes.Ldloc_1, (object)null)); list.Insert(++i, new CodeInstruction(new CodeInstruction(OpCodes.Call, (object)Method_CalculateYield))); list.Insert(++i, new CodeInstruction(OpCodes.Stloc_1, (object)null)); PickableYieldState.InitialSetup(); return list.AsEnumerable(); } } PatchLog.Failed("Pickable_RPC_Pick_Transpiler", "Pickable item yields will be unchanged."); return list; } } [HarmonyPatch(typeof(PickableItem), "GetStackSize")] public static class PickableItem_GetStackSize_Patch { [UsedImplicitly] public static void Postfix(PickableItem __instance, ref int __result) { __result = PickableYieldState.CalculateYield(((Component)__instance.m_itemPrefab).gameObject, __result); } } [HarmonyPatch(typeof(PickableItem), "Drop")] public static class PickableItem_Drop_Prefix { [UsedImplicitly] public static bool Prefix(PickableItem __instance) { if (!Configuration.Current.Pickable.IsEnabled) { return true; } int maxStackSize = __instance.m_itemPrefab.m_itemData.m_shared.m_maxStackSize; int num = __instance.GetStackSize(); int num2 = 0; while (num > 0) { Drop((Component)(object)__instance, ((Component)__instance.m_itemPrefab).gameObject, num2++, Math.Min(maxStackSize, num)); num -= maxStackSize; } return false; } private static void Drop(Component component, GameObject prefab, int offset, int stack) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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_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_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) Vector2 val = Random.insideUnitCircle * 0.2f; Vector3 val2 = component.transform.position + Vector3.up * 0.2f + new Vector3(val.x, 0.2f * (float)offset, val.y); Quaternion val3 = Quaternion.Euler(0f, (float)Random.Range(0, 360), 0f); GameObject obj = Object.Instantiate(prefab, val2, val3); ItemDrop component2 = obj.GetComponent(); if ((Object)(object)component2 != (Object)null) { component2.SetStack(stack); ItemDrop.OnCreateNew(component2, false); } obj.GetComponent().linearVelocity = Vector3.up * 4f; } } [HarmonyPatch(typeof(Player), "Awake")] public static class Player_Awake_Patch { private static void Postfix(ref Player __instance) { if (Configuration.Current.Stamina.IsEnabled) { __instance.m_dodgeStaminaUsage = Helper.applyModifierValue(__instance.m_dodgeStaminaUsage, Configuration.Current.Stamina.dodgeStaminaUsage); __instance.m_encumberedStaminaDrain = Helper.applyModifierValue(__instance.m_encumberedStaminaDrain, Configuration.Current.Stamina.encumberedStaminaDrain); __instance.m_sneakStaminaDrain = Helper.applyModifierValue(__instance.m_sneakStaminaDrain, Configuration.Current.Stamina.sneakStaminaDrain); __instance.m_runStaminaDrain = Helper.applyModifierValue(__instance.m_runStaminaDrain, Configuration.Current.Stamina.runStaminaDrain); __instance.m_staminaRegenDelay = Helper.applyModifierValue(__instance.m_staminaRegenDelay, Configuration.Current.Stamina.staminaRegenDelay); __instance.m_staminaRegen = Helper.applyModifierValue(__instance.m_staminaRegen, Configuration.Current.Stamina.staminaRegen); __instance.m_swimStaminaDrainMinSkill = Helper.applyModifierValue(__instance.m_swimStaminaDrainMinSkill, Configuration.Current.Stamina.swimStaminaDrain); __instance.m_swimStaminaDrainMaxSkill = Helper.applyModifierValue(__instance.m_swimStaminaDrainMaxSkill, Configuration.Current.Stamina.swimStaminaDrain); ((Character)__instance).m_jumpStaminaUsage = Helper.applyModifierValue(((Character)__instance).m_jumpStaminaUsage, Configuration.Current.Stamina.jumpStaminaDrain); } if (Configuration.Current.Player.IsEnabled) { __instance.m_autoPickupRange = Configuration.Current.Player.baseAutoPickUpRange; __instance.m_baseCameraShake = (Configuration.Current.Player.disableCameraShake ? 0f : 4f); __instance.m_maxCarryWeight = Configuration.Current.Player.baseMaximumWeight; } if (Configuration.Current.Building.IsEnabled) { __instance.m_maxPlaceDistance = Configuration.Current.Building.maximumPlacementDistance; } } } [HarmonyPatch(typeof(Player), "Update")] public static class Player_Update_Patch { private static GameObject timeObj = null; private static double savedEnvMinutes = -1.0; private static void Postfix(ref Player __instance, ref Vector3 ___m_moveDir, ref Vector3 ___m_lookDir, ref GameObject ___m_placementGhost, Transform ___m_eye) { //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Expected O, but got Unknown //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_033a: Unknown result type (might be due to invalid IL or missing references) //IL_0346: Unknown result type (might be due to invalid IL or missing references) //IL_0350: Unknown result type (might be due to invalid IL or missing references) //IL_0355: Unknown result type (might be due to invalid IL or missing references) if (Configuration.Current.Player.IsEnabled && Configuration.Current.Player.queueWeaponChanges && (ZInput.GetButtonDown("Hide") || ZInput.GetButtonDown("JoyHide")) && ((Character)__instance).InAttack() && (((Humanoid)__instance).GetRightItem() != null || ((Humanoid)__instance).GetLeftItem() != null)) { EquipPatchState.shouldHideItemsAfterAttack = true; } if (!((Character)__instance).m_nview.IsValid() || !((Character)__instance).m_nview.IsOwner()) { return; } if (Configuration.Current.AdvancedEditingMode.IsEnabled) { AEM.PlayerInstance = __instance; AEM.run(); } if (Configuration.Current.AdvancedBuildingMode.IsEnabled) { ABM.Run(ref __instance); } if (Configuration.Current.Hotkeys.IsEnabled) { ApplyDodgeHotkeys(ref __instance, ref ___m_moveDir, ref ___m_lookDir); } if (!Configuration.Current.GameClock.IsEnabled) { return; } string text = ""; Hud instance = Hud.instance; TMP_Text val; if ((Object)(object)timeObj == (Object)null) { MessageHud instance2 = MessageHud.instance; timeObj = new GameObject(); timeObj.transform.SetParent(((Component)instance.m_statusEffectListRoot).transform.parent); val = (TMP_Text)(object)timeObj.AddComponent(); float num = Mathf.Clamp01((float)Configuration.Current.GameClock.textRedChannel / 255f); float num2 = Mathf.Clamp01((float)Configuration.Current.GameClock.textGreenChannel / 255f); float num3 = Mathf.Clamp01((float)Configuration.Current.GameClock.textBlueChannel / 255f); float num4 = Mathf.Clamp01((float)Configuration.Current.GameClock.textTransparencyChannel / 255f); ((Graphic)val).color = new Color(num, num2, num3, num4); val.font = instance2.m_messageCenterText.font; val.fontSize = Configuration.Current.GameClock.textFontSize; ((Behaviour)val).enabled = true; val.alignment = (TextAlignmentOptions)514; val.overflowMode = (TextOverflowModes)0; RectTransform component = ((Component)val).GetComponent(); Vector2 sizeDelta = component.sizeDelta; component.sizeDelta = new Vector2(sizeDelta.x * 2f, sizeDelta.y); } else { val = timeObj.GetComponent(); } EnvMan instance3 = EnvMan.instance; if (savedEnvMinutes == instance3.m_totalSeconds / 60.0) { return; } int currentDay = instance3.GetCurrentDay(); float num5 = Mathf.Lerp(0f, 24f, instance3.GetDayFraction()); float num6 = Mathf.Floor(num5); num5 -= num6; float num7 = Mathf.Lerp(0f, 60f, num5); int num8 = Mathf.FloorToInt(num6); int num9 = Mathf.FloorToInt(num7); if (Configuration.Current.GameClock.useAMPM) { text = ((num8 < 12) ? " AM" : " PM"); if (num8 > 12) { num8 -= 12; } } val.text = $"Day {currentDay}, {num8:00}:{num9:00} {text}"; Transform transform = ((Component)instance.m_staminaBar2Root).transform; RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null); Transform transform2 = ((Component)instance.m_statusEffectListRoot).transform; RectTransform val3 = (RectTransform)(object)((transform2 is RectTransform) ? transform2 : null); ((Transform)timeObj.GetComponent()).position = Vector2.op_Implicit(new Vector2(((Transform)val2).position.x, ((Transform)val3).position.y)); timeObj.SetActive(true); savedEnvMinutes = instance3.m_totalSeconds / 60.0; } private static void ApplyDodgeHotkeys(ref Player __instance, ref Vector3 ___m_moveDir, ref Vector3 ___m_lookDir) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) KeyCode rollForwards = Configuration.Current.Hotkeys.rollForwards; if (Input.GetKeyDown(Configuration.Current.Hotkeys.rollBackwards)) { Vector3 dodgeDir = ___m_moveDir; if (((Vector3)(ref dodgeDir)).magnitude < 0.1f) { dodgeDir = -___m_lookDir; dodgeDir.y = 0f; ((Vector3)(ref dodgeDir)).Normalize(); } Player_Dodge_ReversePatch.call_Dodge(__instance, dodgeDir); } if (Input.GetKeyDown(rollForwards)) { Vector3 dodgeDir2 = ___m_moveDir; if (((Vector3)(ref dodgeDir2)).magnitude < 0.1f) { dodgeDir2 = ___m_lookDir; dodgeDir2.y = 0f; ((Vector3)(ref dodgeDir2)).Normalize(); } Player_Dodge_ReversePatch.call_Dodge(__instance, dodgeDir2); } } } [HarmonyPatch(typeof(Player))] public class Player_Dodge_ReversePatch { [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(Player), "Dodge", new Type[] { typeof(Vector3) })] public static void call_Dodge(object instance, Vector3 dodgeDir) { throw new NotImplementedException(); } } [HarmonyPatch(typeof(SE_Stats), "Setup")] public static class SE_Stats_Setup_Patch { private static void Postfix(ref SE_Stats __instance) { if (Configuration.Current.Player.IsEnabled && __instance.m_addMaxCarryWeight > 0f) { __instance.m_addMaxCarryWeight = __instance.m_addMaxCarryWeight - 150f + Configuration.Current.Player.baseMegingjordBuff; } } } [HarmonyPatch(typeof(Player), "OnSpawned")] public static class Player_OnSpawned_Patch { private static void Prefix(ref Player __instance) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown TutorialText item = new TutorialText { m_label = "ValheimPlus Intro", m_name = "vplus", m_text = "We hope you enjoy the mod, please support our Patreon so we can continue to provide new updates!", m_topic = "Welcome to Valheim+" }; if (!Tutorial.instance.m_texts.Contains(item)) { Tutorial.instance.m_texts.Add(item); } Player.m_localPlayer.ShowTutorial("vplus", false); if (VPlusMapSync.ShouldSyncOnSpawn && Configuration.Current.Map.IsEnabled && Configuration.Current.Map.shareMapProgression) { VPlusMapSync.SendMapToServer(); VPlusMapSync.ShouldSyncOnSpawn = false; } } } [HarmonyPatch(typeof(Player), "EatFood")] public static class Player_EatFood_Transpiler { private static FieldInfo field_ItemDrop_ItemData_SharedData_m_foodBurnTime = AccessTools.Field(typeof(SharedData), "m_foodBurnTime"); private static MethodInfo method_ComputeModifiedFoodBurnTime = AccessTools.Method(typeof(Player_EatFood_Transpiler), "ComputeModifiedFoodBurnTime", (Type[])null, (Type[])null); [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown if (!Configuration.Current.Food.IsEnabled) { return instructions; } List list = instructions.ToList(); int num = list.Count; for (int i = 0; i < num; i++) { if (CodeInstructionExtensions.LoadsField(list[i], field_ItemDrop_ItemData_SharedData_m_foodBurnTime, false)) { list.Insert(i + 1, new CodeInstruction(OpCodes.Call, (object)method_ComputeModifiedFoodBurnTime)); num++; } } return list.AsEnumerable(); } private static float ComputeModifiedFoodBurnTime(float foodBurnTime) { return Helper.applyModifierValue(foodBurnTime, Configuration.Current.Food.foodDurationMultiplier); } } [HarmonyPatch(typeof(Player), "RemovePiece")] public static class Player_RemovePiece_Transpiler { private static MethodInfo modifyIsInsideMythicalZone = AccessTools.Method(typeof(Player_RemovePiece_Transpiler), "IsInsideNoBuildLocation", (Type[])null, (Type[])null); [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown if (!Configuration.Current.Building.IsEnabled || !Configuration.Current.Building.noMysticalForcesPreventPlacementRestriction) { return instructions; } List list = instructions.ToList(); for (int i = 0; i < list.Count; i++) { if (list[i].operand != null && list[i].operand.ToString().Contains("IsInsideNoBuildLocation")) { list[i] = new CodeInstruction(OpCodes.Call, (object)modifyIsInsideMythicalZone); } } return list.AsEnumerable(); } private static bool IsInsideNoBuildLocation(Vector3 point) { return false; } } [HarmonyPatch(typeof(Player), "GetTotalFoodValue")] public static class Player_GetTotalFoodValue_Transpiler { private static readonly FieldInfo field_Food_m_health = AccessTools.Field(typeof(Food), "m_health"); private static readonly FieldInfo field_Food_m_stamina = AccessTools.Field(typeof(Food), "m_stamina"); private static readonly FieldInfo field_Food_m_eitr = AccessTools.Field(typeof(Food), "m_eitr"); private static readonly FieldInfo field_Food_m_item = AccessTools.Field(typeof(Food), "m_item"); private static readonly FieldInfo field_ItemData_m_shared = AccessTools.Field(typeof(ItemData), "m_shared"); private static readonly FieldInfo field_SharedData_m_food = AccessTools.Field(typeof(SharedData), "m_food"); private static readonly FieldInfo field_SharedData_m_foodStamina = AccessTools.Field(typeof(SharedData), "m_foodStamina"); private static readonly FieldInfo field_SharedData_m_foodEitr = AccessTools.Field(typeof(SharedData), "m_foodEitr"); [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Expected O, but got Unknown if (!Configuration.Current.Food.IsEnabled) { return instructions; } List list = instructions.ToList(); if (Configuration.Current.Food.disableFoodDegradation) { for (int i = 0; i < list.Count; i++) { bool flag = CodeInstructionExtensions.LoadsField(list[i], field_Food_m_health, false); bool flag2 = CodeInstructionExtensions.LoadsField(list[i], field_Food_m_stamina, false); bool flag3 = CodeInstructionExtensions.LoadsField(list[i], field_Food_m_eitr, false); if (flag || flag2 || flag3) { list[i].operand = field_Food_m_item; list.Insert(++i, new CodeInstruction(OpCodes.Ldfld, (object)field_ItemData_m_shared)); if (flag) { list.Insert(++i, new CodeInstruction(OpCodes.Ldfld, (object)field_SharedData_m_food)); } else if (flag2) { list.Insert(++i, new CodeInstruction(OpCodes.Ldfld, (object)field_SharedData_m_foodStamina)); } else { list.Insert(++i, new CodeInstruction(OpCodes.Ldfld, (object)field_SharedData_m_foodEitr)); } } } } return list.AsEnumerable(); } } [HarmonyPatch(typeof(Player), "UseStamina")] public static class Player_UseStamina_Patch { private static void Prefix(ref Player __instance, ref float v) { if (!Configuration.Current.StaminaUsage.IsEnabled) { return; } string name = new StackTrace().GetFrame(2).GetMethod().Name; if (name.Contains("FixedUpdate") || name.Contains("PlayerAttackInput")) { if (((Humanoid)__instance).GetRightItem()?.m_shared.m_name == "$item_fishingrod") { v = Helper.applyModifierValue(v, Configuration.Current.StaminaUsage.fishing); } } else if (name.Contains("UpdatePlacement") || name.Contains("Repair") || name.Contains("RemovePiece")) { switch (((Humanoid)__instance).GetRightItem()?.m_shared.m_name) { case "$item_hammer": v = Helper.applyModifierValue(v, Configuration.Current.StaminaUsage.hammer); break; case "$item_hoe": v = Helper.applyModifierValue(v, Configuration.Current.StaminaUsage.hoe); break; case "$item_cultivator": v = Helper.applyModifierValue(v, Configuration.Current.StaminaUsage.cultivator); break; } } else if (name.Equals("UpdateAttackBowDraw")) { v = Helper.applyModifierValue(v, Configuration.Current.StaminaUsage.bows); } else if (name.Equals("BlockAttack")) { v = Helper.applyModifierValue(v, Configuration.Current.StaminaUsage.blocking); } } } [HarmonyPatch(typeof(Player), "UpdatePlacementGhost")] public static class Player_UpdatePlacementGhost_Patch { private static Vector3? ghostPosition; private static Quaternion? ghostRotation; private static Vector3? markerPosition; private static Quaternion? markerRotation; private static void Prefix(ref Player __instance, bool flashGuardStone) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) if (ABM.isActive) { if (Object.op_Implicit((Object)(object)__instance.m_placementGhost)) { ghostPosition = __instance.m_placementGhost.transform.position + Vector3.zero; ghostRotation = __instance.m_placementGhost.transform.rotation * Quaternion.identity; } if (Object.op_Implicit((Object)(object)__instance.m_placementMarkerInstance)) { markerPosition = __instance.m_placementMarkerInstance.transform.position + Vector3.zero; markerRotation = __instance.m_placementMarkerInstance.transform.rotation * Quaternion.identity; } } } private static void Postfix(ref Player __instance) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Invalid comparison between Unknown and I4 //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Invalid comparison between Unknown and I4 //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) if (ABM.isActive) { __instance.m_placementGhost.transform.position = ghostPosition.Value; __instance.m_placementGhost.transform.rotation = ghostRotation.Value; ghostPosition = null; ghostRotation = null; __instance.m_placementMarkerInstance.transform.position = markerPosition.Value; __instance.m_placementMarkerInstance.transform.rotation = markerRotation.Value; markerPosition = null; markerRotation = null; if (Object.op_Implicit((Object)(object)__instance.m_placementMarkerInstance)) { __instance.m_placementMarkerInstance.SetActive(false); } } if (ABM.exitOnNextIteration) { try { if (Object.op_Implicit((Object)(object)__instance.m_placementMarkerInstance)) { __instance.m_placementMarkerInstance.SetActive(false); } } catch { } } if (Configuration.Current.GridAlignment.IsEnabled && (GridAlignment.AlignPressed ^ GridAlignment.AlignToggled)) { GridAlignment.UpdatePlacementGhost(__instance); } if (Configuration.Current.Building.IsEnabled && Configuration.Current.Building.noInvalidPlacementRestriction) { try { if ((int)__instance.m_placementStatus == 1) { __instance.m_placementStatus = (PlacementStatus)0; __instance.m_placementGhost.GetComponent().SetInvalidPlacementHeightlight(false); } } catch { } } if (Configuration.Current.Building.IsEnabled && Configuration.Current.Building.noMysticalForcesPreventPlacementRestriction) { try { if ((int)__instance.m_placementStatus == 3) { __instance.m_placementStatus = (PlacementStatus)0; __instance.m_placementGhost.GetComponent().SetInvalidPlacementHeightlight(false); } } catch { } } if (!Configuration.Current.Player.IsEnabled || !Configuration.Current.Player.cropNotifier || (Object)(object)__instance.m_placementGhost == (Object)null) { return; } Plant component = __instance.m_placementGhost.GetComponent(); if (!((Object)(object)component != (Object)null) || (int)__instance.m_placementStatus != 0) { return; } LayerMask val = LayerMask.op_Implicit(LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid" })); Collider[] array = Physics.OverlapSphere(__instance.m_placementGhost.transform.position, component.m_growRadius, LayerMask.op_Implicit(val)); for (int i = 0; i < array.Length; i++) { if ((Object)(object)((Component)array[i]).GetComponent() != (Object)null) { __instance.m_placementStatus = (PlacementStatus)5; } } } } [HarmonyPatch] public static class AreaRepair { [HarmonyPatch(typeof(Player), "UpdatePlacement")] public static class Player_UpdatePlacement_Transpiler { private static FieldInfo s_ghostLayer_FieldInfo = GetStaticFieldInfo("s_ghostLayer"); private static FieldInfo s_allPieces_FieldInfo = GetStaticFieldInfo("s_allPieces"); private static MethodInfo method_Player_Repair = AccessTools.Method(typeof(Player), "Repair", (Type[])null, (Type[])null); private static FieldRef field_Player_m_hoveringPiece = AccessTools.FieldRefAccess("m_hoveringPiece"); private static MethodInfo method_RepairNearby = AccessTools.Method(typeof(Player_UpdatePlacement_Transpiler), "RepairNearby", (Type[])null, (Type[])null); [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { if (!Configuration.Current.Building.IsEnabled) { return instructions; } List list = instructions.ToList(); if (Configuration.Current.Building.enableAreaRepair) { for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], method_Player_Repair)) { list[i].operand = method_RepairNearby; } } } return list.AsEnumerable(); } public static void RepairNearby(Player instance, ItemData toolItem, Piece _1) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) Piece hoveringPiece = instance.GetHoveringPiece(); Vector3 p = (((Object)(object)hoveringPiece != (Object)null) ? ((Component)hoveringPiece).transform.position : ((Component)instance).transform.position); List list = new List(); GetAllPiecesInRadius(p, Configuration.Current.Building.areaRepairRadius, list); m_repair_count = 0; Piece hoveringPiece2 = instance.m_hoveringPiece; foreach (Piece item in list) { bool num = ((Character)instance).HaveStamina(toolItem.m_shared.m_attack.m_attackStamina); bool useDurability = toolItem.m_shared.m_useDurability; bool flag = toolItem.m_durability > 0f; if (!num || (useDurability && !flag)) { break; } instance.m_hoveringPiece = item; instance.Repair(toolItem, _1); instance.m_hoveringPiece = hoveringPiece2; } ((Character)instance).Message((MessageType)1, $"{m_repair_count} pieces repaired", 0, (Sprite)null, false); } private static void GetAllPiecesInRadius(Vector3 p, float radius, List pieces) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) int num = (int)s_ghostLayer_FieldInfo.GetValue(null); foreach (Piece item in (List)s_allPieces_FieldInfo.GetValue(null)) { if (((Component)item).gameObject.layer != num && Vector3.Distance(p, ((Component)item).transform.position) < radius) { pieces.Add(item); } } } private static FieldInfo GetStaticFieldInfo(string name) { return typeof(T).GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } } [HarmonyPatch(typeof(Player), "Repair")] public static class Player_Repair_Transpiler { private static MethodInfo method_Character_Message = AccessTools.Method(typeof(Character), "Message", (Type[])null, (Type[])null); private static MethodInfo method_MessageNoop = AccessTools.Method(typeof(Player_Repair_Transpiler), "MessageNoop", (Type[])null, (Type[])null); [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown if (!Configuration.Current.Building.IsEnabled) { return instructions; } List list = instructions.ToList(); if (Configuration.Current.Building.enableAreaRepair) { int num = 0; for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], method_Character_Message)) { list[i].operand = method_MessageNoop; list.Insert(i++, new CodeInstruction((num++ == 0) ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0, (object)null)); } } } return list.AsEnumerable(); } public static void MessageNoop(Character _0, MessageType _1, string _2, int _3, Sprite _4, bool _5, int repaired) { m_repair_count += repaired; } } private static int m_repair_count; } [HarmonyPatch(typeof(Player), "Update")] public static class GridAlignment { public static int DefaultAlignment = 100; public static bool AlignPressed = false; public static bool AlignToggled = false; private static void Postfix(ref Player __instance) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !Configuration.Current.GridAlignment.IsEnabled) { return; } if (Input.GetKeyDown(Configuration.Current.GridAlignment.align)) { AlignPressed = true; } if (Input.GetKeyUp(Configuration.Current.GridAlignment.align)) { AlignPressed = false; } if (Input.GetKeyDown(Configuration.Current.GridAlignment.changeDefaultAlignment)) { if (DefaultAlignment == 50) { DefaultAlignment = 100; } else if (DefaultAlignment == 100) { DefaultAlignment = 200; } else if (DefaultAlignment == 200) { DefaultAlignment = 400; } else { DefaultAlignment = 50; } MessageHud.instance.ShowMessage((MessageType)1, "Default grid alignment set to " + (float)DefaultAlignment / 100f, 0, (Sprite)null, false, true); } if (Input.GetKeyDown(Configuration.Current.GridAlignment.alignToggle)) { AlignToggled = !AlignToggled; MessageHud.instance.ShowMessage((MessageType)1, "Grid alignment by default " + (AlignToggled ? "enabled" : "disabled"), 0, (Sprite)null, false, true); } } private static float FixAlignment(float f) { int num = (int)Mathf.Round(f * 100f); if (num <= 0) { return (float)DefaultAlignment / 100f; } if (num <= 50) { return 0.5f; } if (num <= 100) { return 1f; } if (num <= 200) { return 2f; } return 4f; } public static void GetAlignment(Piece piece, out Vector3 alignment, out Vector3 offset) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_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_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) List list = new List(); piece.GetSnapPoints(list); if (list.Count != 0) { Vector3 val = Vector3.positiveInfinity; Vector3 val2 = Vector3.negativeInfinity; foreach (Transform item in list) { Vector3 localPosition = item.localPosition; val = Vector3.Min(val, localPosition); val2 = Vector3.Max(val2, localPosition); } alignment = val2 - val; alignment.x = FixAlignment(alignment.x); alignment.y = FixAlignment(alignment.y); alignment.z = FixAlignment(alignment.z); offset = val2; if (((Object)piece).name == "iron_grate" || ((Object)piece).name == "wood_gate") { offset.y = val.y; } if (((Object)piece).name == "wood_gate") { alignment.x = 4f; } } else if (piece.m_notOnFloor || ((Object)piece).name == "sign" || ((Object)piece).name == "itemstand") { alignment = new Vector3(0.5f, 0.5f, 0f); offset = new Vector3(0f, 0f, 0f); if (((Object)piece).name == "sign") { alignment.y = 0.25f; } } else if (((Object)piece).name == "piece_walltorch") { alignment = new Vector3(0f, 0.5f, 0.5f); offset = new Vector3(0f, 0f, 0f); } else { alignment = new Vector3(0.5f, 0f, 0.5f); offset = new Vector3(0f, 0f, 0f); } } public static float Align(float value, out float alpha) { float num = Mathf.Round(value); alpha = value - num; return num; } public static void UpdatePlacementGhost(Player player) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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_0078: 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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: 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_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player.m_placementGhost == (Object)null || !((Character)player).IsPlayer() || ABM.isActive) { return; } bool num = ZInput.GetButton("AltPlace") || ZInput.GetButton("JoyAltPlace"); Piece component = player.m_placementGhost.GetComponent(); Vector3 val = ((Component)component).transform.position; val = Quaternion.Inverse(((Component)component).transform.rotation) * val; GetAlignment(component, out var alignment, out var offset); val += offset; Vector3 val2 = val; ((Vector3)(ref val))..ctor(val.x / alignment.x, val.y / alignment.y, val.z / alignment.z); ((Vector3)(ref val))..ctor(Align(val.x, out var alpha), Align(val.y, out var alpha2), Align(val.z, out var alpha3)); if (num) { float num2 = 0.2f; if (Mathf.Abs(alpha) >= num2 && Mathf.Abs(alpha) >= Mathf.Abs(alpha2) && Mathf.Abs(alpha) >= Mathf.Abs(alpha3)) { val.x += Mathf.Sign(alpha); } else if (Mathf.Abs(alpha2) >= num2 && Mathf.Abs(alpha2) >= Mathf.Abs(alpha3)) { val.y += Mathf.Sign(alpha2); } else if (Mathf.Abs(alpha3) >= num2) { val.z += Mathf.Sign(alpha3); } } ((Vector3)(ref val))..ctor(val.x * alignment.x, val.y * alignment.y, val.z * alignment.z); if (alignment.x <= 0f) { val.x = val2.x; } if (alignment.y <= 0f) { val.y = val2.y; } if (alignment.z <= 0f) { val.z = val2.z; } val -= offset; val = ((Component)component).transform.rotation * val; ((Component)component).transform.position = val; } } [HarmonyPatch(typeof(Player), "SetGuardianPower")] public static class Player_SetGuardianPower_Patch { private static void Postfix(ref Player __instance) { if (Configuration.Current.Player.IsEnabled && Object.op_Implicit((Object)(object)__instance.m_guardianSE)) { __instance.m_guardianSE.m_ttl = Configuration.Current.Player.guardianBuffDuration; __instance.m_guardianSE.m_cooldown = Configuration.Current.Player.guardianBuffCooldown; } } } [HarmonyPatch(typeof(Player), "StartGuardianPower")] public static class Player_StartGuardianPower_Patch { private static bool Prefix(ref Player __instance, ref bool __result) { if (!Configuration.Current.Player.disableGuardianBuffAnimation || !Configuration.Current.Player.IsEnabled) { return true; } if ((Object)(object)__instance.m_guardianSE == (Object)null) { __result = false; return false; } if (__instance.m_guardianPowerCooldown > 0f) { ((Character)__instance).Message((MessageType)2, "$hud_powernotready", 0, (Sprite)null, false); __result = false; return false; } __instance.ActivateGuardianPower(); __result = true; return false; } } [HarmonyPatch(typeof(Player), "HaveRequirementItems", new Type[] { typeof(Recipe), typeof(bool), typeof(int), typeof(int) })] public static class Player_HaveRequirementItems_Transpiler { private static readonly MethodInfo Method_Inventory_CountItems = AccessTools.Method(typeof(Inventory), "CountItems", (Type[])null, (Type[])null); private static readonly MethodInfo Method_ComputeItemQuantity = AccessTools.Method(typeof(Player_HaveRequirementItems_Transpiler), "ComputeItemQuantity", (Type[])null, (Type[])null); private static readonly FieldInfo Field_Requirement_m_resItem = AccessTools.Field(typeof(Requirement), "m_resItem"); [HarmonyTranspiler] [UsedImplicitly] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Expected O, but got Unknown //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Expected O, but got Unknown //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Expected O, but got Unknown //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Expected O, but got Unknown //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Expected O, but got Unknown //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Expected O, but got Unknown //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Expected O, but got Unknown if (!Configuration.Current.CraftFromChest.IsEnabled) { return instructions; } try { CodeMatcher obj = new CodeMatcher(instructions, (ILGenerator)null).MatchStartForward((CodeMatch[])(object)new CodeMatch[10] { new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)null, (string)null), new CodeMatch((OpCode?)null, (object)null, (string)null), new CodeMatch((Func)((CodeInstruction i) => CodeInstructionExtensions.LoadsField(i, Field_Requirement_m_resItem, false)), (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)null, (string)null), new CodeMatch((OpCode?)null, (object)null, (string)null), new CodeMatch((OpCode?)null, (object)null, (string)null), new CodeMatch((Func)((CodeInstruction i) => CodeInstructionExtensions.Calls(i, Method_Inventory_CountItems)), (string)null) }).ThrowIfNotMatch("No match for this.m_inventory.CountItems(resource name, quality).", Array.Empty()); CodeInstruction val = obj.InstructionAt(2); CodeInstruction val2 = obj.InstructionAt(7); return obj.Advance(10).Insert((CodeInstruction[])(object)new CodeInstruction[4] { new CodeInstruction(val.opcode, val.operand), new CodeInstruction(val2.opcode, val2.operand), new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)Method_ComputeItemQuantity) }).InstructionEnumeration(); } catch (Exception exception) { PatchLog.Failed("Player_HaveRequirementItems_Transpiler", "Crafting will not count items in nearby chests.", exception); return instructions; } } private static int ComputeItemQuantity(int fromInventory, Requirement item, int quality, Player player) { CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); GameObject val = ((currentCraftingStation != null) ? ((Component)currentCraftingStation).gameObject : null); Stopwatch stopwatch; if (!Object.op_Implicit((Object)(object)val) || !Configuration.Current.CraftFromChest.checkFromWorkbench) { val = ((Component)player).gameObject; stopwatch = Inventory_NearbyChests_Cache.delta; } else { stopwatch = GameObjectAssistant.GetStopwatch(val); } int num = Helper.Clamp(Configuration.Current.CraftFromChest.lookupInterval, 1, 10) * 1000; if (!stopwatch.IsRunning || stopwatch.ElapsedMilliseconds > num) { Inventory_NearbyChests_Cache.chests = InventoryAssistant.GetNearbyChests(val, Helper.Clamp(Configuration.Current.CraftFromChest.range, 1f, 50f), !Configuration.Current.CraftFromChest.ignorePrivateAreaCheck); stopwatch.Restart(); } return fromInventory + InventoryAssistant.GetItemAmountInItemList(InventoryAssistant.GetNearbyChestItemsByContainerList(Inventory_NearbyChests_Cache.chests), item.m_resItem.m_itemData, quality); } } [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Piece), typeof(RequirementMode) })] public static class Player_HaveRequirements_Transpiler { private static MethodInfo method_Inventory_CountItems = AccessTools.Method(typeof(Inventory), "CountItems", (Type[])null, (Type[])null); private static MethodInfo method_ComputeItemQuantity = AccessTools.Method(typeof(Player_HaveRequirements_Transpiler), "ComputeItemQuantity", (Type[])null, (Type[])null); [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown if (!Configuration.Current.CraftFromChest.IsEnabled) { return instructions; } List list = instructions.ToList(); for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], method_Inventory_CountItems)) { list.Insert(++i, new CodeInstruction(OpCodes.Ldloc_2, (object)null)); list.Insert(++i, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Insert(++i, new CodeInstruction(OpCodes.Call, (object)method_ComputeItemQuantity)); } } return list.AsEnumerable(); } private static int ComputeItemQuantity(int fromInventory, Requirement item, Player player) { CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); GameObject val = ((currentCraftingStation != null) ? ((Component)currentCraftingStation).gameObject : null); Stopwatch stopwatch; if (!Object.op_Implicit((Object)(object)val) || !Configuration.Current.CraftFromChest.checkFromWorkbench) { val = ((Component)player).gameObject; stopwatch = Inventory_NearbyChests_Cache.delta; } else { stopwatch = GameObjectAssistant.GetStopwatch(val); } int num = Helper.Clamp(Configuration.Current.CraftFromChest.lookupInterval, 1, 10) * 1000; if (!stopwatch.IsRunning || stopwatch.ElapsedMilliseconds > num) { Inventory_NearbyChests_Cache.chests = InventoryAssistant.GetNearbyChests(val, Helper.Clamp(Configuration.Current.CraftFromChest.range, 1f, 50f), !Configuration.Current.CraftFromChest.ignorePrivateAreaCheck); stopwatch.Restart(); } return fromInventory + InventoryAssistant.GetItemAmountInItemList(InventoryAssistant.GetNearbyChestItemsByContainerList(Inventory_NearbyChests_Cache.chests), item.m_resItem.m_itemData); } } [HarmonyPatch(typeof(Player), "ConsumeResources", new Type[] { typeof(Requirement[]), typeof(int), typeof(int), typeof(int) })] public static class Player_ConsumeResources_Transpiler { private static readonly MethodInfo Method_Inventory_RemoveItem = AccessTools.Method(typeof(Inventory), "RemoveItem", new Type[4] { typeof(string), typeof(int), typeof(int), typeof(bool) }, (Type[])null); private static readonly MethodInfo Method_RemoveItemsFromInventoryAndNearbyChests = AccessTools.Method(typeof(Player_ConsumeResources_Transpiler), "RemoveItemsFromInventoryAndNearbyChests", (Type[])null, (Type[])null); private static readonly FieldInfo Field_Requirement_m_resItem = AccessTools.Field(typeof(Requirement), "m_resItem"); [HarmonyTranspiler] [UsedImplicitly] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Expected O, but got Unknown //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Expected O, but got Unknown //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Expected O, but got Unknown //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Expected O, but got Unknown //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Expected O, but got Unknown //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Expected O, but got Unknown //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Expected O, but got Unknown //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Expected O, but got Unknown if (!Configuration.Current.CraftFromChest.IsEnabled) { return instructions; } try { CodeMatcher obj = new CodeMatcher(instructions, (ILGenerator)null).MatchStartForward((CodeMatch[])(object)new CodeMatch[11] { new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)null, (string)null), new CodeMatch((OpCode?)null, (object)null, (string)null), new CodeMatch((Func)((CodeInstruction i) => CodeInstructionExtensions.LoadsField(i, Field_Requirement_m_resItem, false)), (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)null, (string)null), new CodeMatch((OpCode?)null, (object)null, (string)null), new CodeMatch((OpCode?)null, (object)null, (string)null), new CodeMatch((OpCode?)null, (object)null, (string)null), new CodeMatch((Func)((CodeInstruction i) => CodeInstructionExtensions.Calls(i, Method_Inventory_RemoveItem)), (string)null) }).ThrowIfNotMatch("No match for this.m_inventory.RemoveItem(resource name, amount, quality).", Array.Empty()); CodeInstruction val = obj.InstructionAt(2); CodeInstruction val2 = obj.InstructionAt(7); CodeInstruction val3 = obj.InstructionAt(8); return obj.Advance(1).RemoveInstructions(10).Insert((CodeInstruction[])(object)new CodeInstruction[4] { new CodeInstruction(val.opcode, val.operand), new CodeInstruction(val2.opcode, val2.operand), new CodeInstruction(val3.opcode, val3.operand), new CodeInstruction(OpCodes.Call, (object)Method_RemoveItemsFromInventoryAndNearbyChests) }) .InstructionEnumeration(); } catch (Exception exception) { PatchLog.Failed("Player_ConsumeResources_Transpiler", "Crafting will not take resources from nearby chests.", exception); return instructions; } } private static void RemoveItemsFromInventoryAndNearbyChests(Player player, Requirement item, int amount, int itemQuality) { CraftFromChestConfiguration craftFromChest = Configuration.Current.CraftFromChest; object obj; if (!craftFromChest.checkFromWorkbench) { obj = ((Component)player).gameObject; } else { CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); obj = ((currentCraftingStation != null) ? ((Component)currentCraftingStation).gameObject : null) ?? ((Component)player).gameObject; } GameObject target = (GameObject)obj; int num = ((Humanoid)player).m_inventory.CountItems(item.m_resItem.m_itemData.m_shared.m_name, -1, true); ((Humanoid)player).m_inventory.RemoveItem(item.m_resItem.m_itemData.m_shared.m_name, amount, itemQuality, true); amount -= num; if (amount > 0) { InventoryAssistant.RemoveItemInAmountFromAllNearbyChests(target, Helper.Clamp(craftFromChest.range, 1f, 50f), item.m_resItem.m_itemData, amount, !craftFromChest.ignorePrivateAreaCheck); } } } public static class EquipPatchState { public static bool shouldEquipItemsAfterAttack; public static bool shouldHideItemsAfterAttack; public static List items; } [HarmonyPatch(typeof(Player), "ToggleEquipped")] public static class Player_ToggleEquiped_Patch { private static void Postfix(Player __instance, bool __result, ItemData item) { if (Configuration.Current.Player.IsEnabled && Configuration.Current.Player.queueWeaponChanges && __result && item.IsEquipable() && ((Character)__instance).InAttack()) { if (EquipPatchState.items == null) { EquipPatchState.items = new List(); } if (!EquipPatchState.items.Contains(item)) { EquipPatchState.items.Add(item); } EquipPatchState.shouldEquipItemsAfterAttack = true; } } } [HarmonyPatch(typeof(Player), "FixedUpdate")] public static class Player_FixedUpdate_Patch { private static void Postfix(Player __instance) { if (!Configuration.Current.Player.IsEnabled || !Configuration.Current.Player.queueWeaponChanges) { return; } if (EquipPatchState.shouldEquipItemsAfterAttack && !((Character)__instance).InAttack() && ((Object)(object)((Character)__instance).m_nview == (Object)null || ((Object)(object)((Character)__instance).m_nview != (Object)null && ((Character)__instance).m_nview.IsOwner()))) { foreach (ItemData item in EquipPatchState.items) { float equipDuration = item.m_shared.m_equipDuration; item.m_shared.m_equipDuration = 0f; ((Humanoid)__instance).ToggleEquipped(item); item.m_shared.m_equipDuration = equipDuration; } EquipPatchState.shouldEquipItemsAfterAttack = false; EquipPatchState.items.Clear(); } if (EquipPatchState.shouldHideItemsAfterAttack && !((Character)__instance).InAttack()) { ((Humanoid)__instance).HideHandItems(false, true); EquipPatchState.shouldHideItemsAfterAttack = false; } } } [HarmonyPatch(typeof(Player), "HaveSeenTutorial")] public class Player_HaveSeenTutorial_Patch { [HarmonyPrefix] private static void Prefix(Player __instance, ref string name) { if (Configuration.Current.Player.IsEnabled && Configuration.Current.Player.skipTutorials && !__instance.m_shownTutorials.Contains(name)) { __instance.m_shownTutorials.Add(name); } } } [HarmonyPatch(typeof(Player), "IsEncumbered")] public static class Player_IsEncumbered_Patch { private static void Postfix(ref bool __result) { if (Configuration.Current.Player.IsEnabled && Configuration.Current.Player.disableEncumbered) { __result = false; } } } [HarmonyPatch(typeof(Player), "AutoPickup")] public static class Player_AutoPickup_Transpiler { private static MethodInfo method_Player_GetMaxCarryWeight = AccessTools.Method(typeof(Player), "GetMaxCarryWeight", (Type[])null, (Type[])null); private static MethodInfo method_GetMaxCarryWeight = AccessTools.Method(typeof(Player_AutoPickup_Transpiler), "GetMaxCarryWeight", (Type[])null, (Type[])null); [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { if (!Configuration.Current.Player.IsEnabled || !Configuration.Current.Player.autoPickUpWhenEncumbered) { return instructions; } List list = instructions.ToList(); for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], method_Player_GetMaxCarryWeight)) { list[i - 1].opcode = OpCodes.Nop; list[i].operand = method_GetMaxCarryWeight; break; } } return list.AsEnumerable(); } public static float GetMaxCarryWeight() { return 9999999f; } } [HarmonyPatch(typeof(Player), "GetFirstRequiredItem")] public static class Player_GetFirstRequiredItem_Transpiler { private static readonly FieldInfo Field_Humanoid_m_inventory = AccessTools.Field(typeof(Humanoid), "m_inventory"); [HarmonyTranspiler] public static IEnumerable Transpile(IEnumerable instructions) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown try { return new CodeMatcher(instructions, (ILGenerator)null).MatchStartForward((CodeMatch[])(object)new CodeMatch[2] { new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((Func)((CodeInstruction i) => CodeInstructionExtensions.LoadsField(i, Field_Humanoid_m_inventory, false)), (string)null) }).ThrowIfNotMatch("No match for this.m_inventory.", Array.Empty()).SetOpcodeAndAdvance(OpCodes.Ldarg_1) .RemoveInstruction() .InstructionEnumeration(); } catch (Exception exception) { PatchLog.Failed("Player_GetFirstRequiredItem_Transpiler", "Crafting will not find required items in nearby chests.", exception); return instructions; } } } [HarmonyPatch(typeof(Player), "UpdateTeleport")] public static class Player_UpdateTeleport_Patch { [HarmonyPrefix] private static void Prefix(ref float ___m_teleportTimer, ref bool ___m_teleporting, ref Vector3 ___m_teleportTargetPos) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) if ((Configuration.Current.Player.IsEnabled && Configuration.Current.Player.disableEightSecondTeleport && ZNetScene.instance.IsAreaReady(___m_teleportTargetPos)) & ___m_teleporting) { ___m_teleportTimer += Helper.Clamp(8.1f - ___m_teleportTimer, 0f, float.MaxValue); } } } [HarmonyPatch(typeof(PlayerProfile), "LoadPlayerFromDisk")] public static class PlayerProfile_LoadPlayerFromDisk_Patch { [UsedImplicitly] private static void Postfix(ref PlayerProfile __instance) { if (Configuration.Current.Player.IsEnabled && Configuration.Current.Player.skipIntro) { __instance.m_firstSpawn = false; } } } public static class ProcreationHelpers { public static bool IsValidAnimalType(string name) { if (!TameableHelpers.NamedTypes.TryGetValue(name, out var value)) { return false; } return Configuration.Current.Procreation.animalTypes.HasFlag(value); } public static bool IsHungerIgnored(Tameable instance) { if (Configuration.Current.Procreation.IsEnabled && Configuration.Current.Procreation.ignoreHunger) { return IsValidAnimalType(instance.m_character.m_name); } return false; } public static bool IsAlertedWithIgnore(Tameable tameable) { if (!IsValidAnimalType(tameable.m_character.m_name)) { return ((BaseAI)tameable.m_monsterAI).IsAlerted(); } return false; } private static string GetPregnantStatus(Procreation procreation) { long num = procreation.m_nview.GetZDO().GetLong(ZDOVars.s_pregnant, 0L); double totalSeconds = new TimeSpan(ZNet.instance.GetTime().Ticks - num).TotalSeconds; int num2 = (int)((double)procreation.m_pregnancyDuration - totalSeconds); string text = ((num2 > 0) ? ((num2 <= 120) ? (" ( " + num2 + " seconds left )") : (" ( " + num2 / 60 + " minutes left )")) : ((num2 <= -15) ? " ( Overdue )" : " ( Due to give birth )")); return string.Concat("\nPregnant" + text, ""); } public static void AddLoveInformation(Tameable instance, Procreation procreation, ref string result) { ProcreationConfiguration procreation2 = Configuration.Current.Procreation; if (procreation2.IsEnabled && procreation2.loveInformation && IsValidAnimalType(instance.m_character.m_name)) { int num = result.IndexOf('\n'); if (num > 0) { int num2 = procreation.m_nview.GetZDO().GetInt(ZDOVars.s_lovePoints, 0); string value = (procreation.IsPregnant() ? GetPregnantStatus(procreation) : ((num2 <= 0) ? "\nNot loved" : $"\nLoved ( {num2} / {procreation.m_requiredLovePoints} )")); result = result.Insert(num, value); } } } public static void AddGrowupInformation(Character character, Growup growup, ref string result) { ProcreationConfiguration procreation = Configuration.Current.Procreation; if (procreation.IsEnabled && procreation.offspringInformation && IsValidAnimalType(character.m_name)) { result = Localization.instance.Localize(character.m_name); int growTimeLeft = GrowupHelpers.GetGrowTimeLeft(growup); string text = result; string text2 = ((growTimeLeft > 120) ? (" ( Matures in " + growTimeLeft / 60 + " minutes )") : ((growTimeLeft <= 0) ? " ( Matured )" : (" ( Matures in " + growTimeLeft + " seconds )"))); result = text + text2; } } } [HarmonyPatch(typeof(Procreation), "Awake")] public static class Procreation_Awake_Patch { [UsedImplicitly] public static void Postfix(Procreation __instance) { ProcreationConfiguration procreation = Configuration.Current.Procreation; if (procreation.IsEnabled && ProcreationHelpers.IsValidAnimalType(__instance.m_character.m_name)) { __instance.m_requiredLovePoints = (int)Helper.applyModifierValue(__instance.m_requiredLovePoints, procreation.requiredLovePointsMultiplier); __instance.m_maxCreatures = (int)Helper.applyModifierValue(__instance.m_maxCreatures, procreation.creatureLimitMultiplier); Helper.applyModifierValueTo(ref __instance.m_partnerCheckRange, procreation.partnerCheckRangeMultiplier); Helper.applyModifierValueTo(ref __instance.m_pregnancyDuration, procreation.pregnancyDurationMultiplier); Helper.applyModifierValueTo(ref __instance.m_pregnancyChance, procreation.pregnancyChanceMultiplier); } } } [HarmonyPatch(typeof(Procreation), "Procreate")] public static class Procreation_Procreate_Patch { [UsedImplicitly] public static IEnumerable Transpiler(IEnumerable instructions, ILGenerator ilGenerator) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown ProcreationConfiguration procreation = Configuration.Current.Procreation; if (!procreation.IsEnabled || !procreation.ignoreAlerted) { return instructions; } List list = instructions.ToList(); try { MethodInfo methodInfo = AccessTools.Method(typeof(BaseAI), "IsAlerted", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(ProcreationHelpers), "IsAlertedWithIgnore", (Type[])null, (Type[])null); return new CodeMatcher((IEnumerable)list, ilGenerator).MatchStartForward((CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Callvirt, (object)methodInfo, (string)null) }).ThrowIfNotMatch("Could not find BaseAI.IsAlerted call", Array.Empty()).Advance(-1) .RemoveInstructions(2) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Call, (object)methodInfo2) }) .InstructionEnumeration(); } catch (Exception exception) { PatchLog.Failed("Procreation_Procreate_Patch", "`Procreation.ignoreAlerted` will not work.", exception); return list; } } } [HarmonyPatch(typeof(Recipe), "GetAmount")] public static class Recipe_GetAmount_Transpiler { private static readonly MethodInfo Method_Player_GetFirstRequiredItem = AccessTools.Method(typeof(Player), "GetFirstRequiredItem", (Type[])null, (Type[])null); private static readonly MethodInfo Method_GetFirstRequiredItemFromNearbyChests = AccessTools.Method(typeof(Recipe_GetAmount_Transpiler), "GetFirstRequiredItem", (Type[])null, (Type[])null); [UsedImplicitly] [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown if (!Configuration.Current.CraftFromChest.IsEnabled) { return instructions; } List list = instructions.ToList(); for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], Method_Player_GetFirstRequiredItem)) { list[i] = new CodeInstruction(OpCodes.Call, (object)Method_GetFirstRequiredItemFromNearbyChests); return list.AsEnumerable(); } } PatchLog.Failed("Recipe_GetAmount_Transpiler", "Recipe amounts will be unchanged."); return list.AsEnumerable(); } private static ItemData GetFirstRequiredItem(Player player, Inventory inventory, Recipe recipe, int qualityLevel, out int amount, out int extraAmount, int craftMultiplier) { ItemData firstRequiredItem = player.GetFirstRequiredItem(inventory, recipe, qualityLevel, ref amount, ref extraAmount, craftMultiplier); if (firstRequiredItem != null) { return firstRequiredItem; } object target; if (!Configuration.Current.CraftFromChest.checkFromWorkbench) { target = ((Component)player).gameObject; } else { CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); target = ((currentCraftingStation != null) ? ((Component)currentCraftingStation).gameObject : null) ?? ((Component)player).gameObject; } List nearbyChests = InventoryAssistant.GetNearbyChests((GameObject)target, Helper.Clamp(Configuration.Current.CraftFromChest.range, 1f, 50f), !Configuration.Current.CraftFromChest.ignorePrivateAreaCheck); Requirement[] resources = recipe.m_resources; foreach (Container item in nearbyChests) { if (!Object.op_Implicit((Object)(object)item)) { continue; } Requirement[] array = resources; foreach (Requirement val in array) { if (!Object.op_Implicit((Object)(object)val.m_resItem)) { continue; } int num = val.GetAmount(qualityLevel) * craftMultiplier; SharedData shared = val.m_resItem.m_itemData.m_shared; for (int j = 0; j <= shared.m_maxQuality; j++) { string name = shared.m_name; if (item.m_inventory.CountItems(name, j, true) >= num) { amount = num; extraAmount = val.m_extraAmountOnlyOneIngredient; return item.m_inventory.GetItem(name, j, false); } } } } amount = 0; extraAmount = 0; return null; } } public static class SapCollectorDeposit { [HarmonyPatch(typeof(SapCollector), "Awake")] public static class SapCollector_Awake_Patch { [UsedImplicitly] private static void Prefix(ref float ___m_secPerUnit, ref int ___m_maxLevel) { SapCollectorConfiguration sapCollector = Configuration.Current.SapCollector; if (sapCollector.IsEnabled) { ___m_secPerUnit = sapCollector.sapProductionSpeed; ___m_maxLevel = sapCollector.maximumSapPerCollector; } } } [HarmonyPatch(typeof(SapCollector), "GetHoverText")] public static class SapCollector_GetHoverText_Patch { [UsedImplicitly] private static void Postfix(SapCollector __instance, ref string __result) { SapCollectorConfiguration sapCollector = Configuration.Current.SapCollector; if (sapCollector.IsEnabled && sapCollector.showDuration && __instance.GetLevel() != __instance.m_maxLevel) { int num = (int)(__instance.m_secPerUnit - __instance.m_nview.GetZDO().GetFloat(ZDOVars.s_product, 0f)); string text = ((num >= 120) ? $"{num / 60} minutes" : $"{num} seconds"); __result = __result.Replace(" )", " )\n(" + text + ")"); } } } [HarmonyPatch(typeof(SapCollector), "RPC_Extract")] public static class SapCollector_RPC_Extract_Patch { [UsedImplicitly] private static void Prefix(SapCollector __instance) { SapCollectorConfiguration sapCollector = Configuration.Current.SapCollector; if (sapCollector.IsEnabled && sapCollector.autoDeposit && __instance.GetLevel() > 0) { Deposit(__instance); } } } [HarmonyPatch(typeof(SapCollector), "UpdateTick")] public static class SapCollector_UpdateTick_Patch { [UsedImplicitly] private static void Postfix(SapCollector __instance) { SapCollectorConfiguration sapCollector = Configuration.Current.SapCollector; if (sapCollector.IsEnabled && sapCollector.autoDeposit && __instance.GetLevel() == __instance.m_maxLevel) { Deposit(__instance); } } } private static void Deposit(SapCollector __instance) { //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) ZNetView nview = __instance.m_nview; if (nview == null || !nview.IsOwner()) { return; } List nearbyChests = InventoryAssistant.GetNearbyChests(((Component)__instance).gameObject, Helper.Clamp(Configuration.Current.SapCollector.autoDepositRange, 1f, 50f)); if (nearbyChests.Count == 0) { return; } int level = __instance.GetLevel(); while (__instance.GetLevel() > 0) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(((Object)((Component)__instance.m_spawnItem).gameObject).name); ZNetView.m_forceDisableInit = true; GameObject val = Object.Instantiate(itemPrefab); ZNetView.m_forceDisableInit = false; bool num = SpawnNearbyChest(val.GetComponent(), mustHaveItem: true, __instance, nearbyChests); Object.Destroy((Object)(object)val); if (!num) { return; } } if (__instance.GetLevel() < level) { __instance.m_spawnEffect.Create(__instance.m_spawnPoint.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); } } private static bool SpawnNearbyChest(ItemDrop item, bool mustHaveItem, SapCollector __instance, List nearbyChests) { foreach (Container nearbyChest in nearbyChests) { Inventory inventory = nearbyChest.GetInventory(); if ((!mustHaveItem || inventory.HaveItem(item.m_itemData.m_shared.m_name, true)) && inventory.AddItem(item.m_itemData)) { __instance.m_nview.GetZDO().Set("level", __instance.GetLevel() - 1); InventoryAssistant.ConveyContainerToNetwork(nearbyChest); return true; } } if (mustHaveItem) { return SpawnNearbyChest(item, mustHaveItem: false, __instance, nearbyChests); } return false; } } [HarmonyPatch(typeof(SEMan), "AddStatusEffect", new Type[] { typeof(StatusEffect), typeof(bool), typeof(int), typeof(float), typeof(short) })] public static class SEMan_AddStatusEffect_Patch { private static void Postfix(ref SEMan __instance, ref StatusEffect statusEffect, bool resetTime = false, int itemLevel = 0, float skillLevel = 0f, short variant = -1) { if (!Configuration.Current.Player.IsEnabled || !__instance.m_character.IsPlayer() || !((Object)statusEffect).name.StartsWith("GP_")) { return; } foreach (StatusEffect statusEffect3 in __instance.m_statusEffects) { StatusEffect statusEffect2 = __instance.GetStatusEffect(statusEffect.NameHash()); if (statusEffect3.m_name == statusEffect2.m_name) { statusEffect2.m_ttl = Configuration.Current.Player.guardianBuffDuration; } } } } public static class MuteGameInBackground { public static Toggle muteAudioToggle; public static bool CreateToggle() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: 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) foreach (ISettingsTab settingsTab in Settings.instance.SettingsTabs) { if (((object)settingsTab).GetType() == typeof(AudioSettings)) { Toggle continousMusic = ((AudioSettings)settingsTab).m_continousMusic; muteAudioToggle = Object.Instantiate(continousMusic, ((Component)continousMusic).transform.parent, false); ((Object)muteAudioToggle).name = "MuteGameInBackground"; ((Component)muteAudioToggle).GetComponentInChildren().text = "Mute game in background"; CanvasScaler componentInChildren = ((Component)((Component)muteAudioToggle).transform.root).GetComponentInChildren(); ((Component)muteAudioToggle).transform.Translate(Vector2.op_Implicit(new Vector2(0f, -40f * componentInChildren.scaleFactor))); return true; } } ValheimPlusPlugin.Logger.LogError((object)"Failed to create MuteGameInBackground toggle"); return false; } } [HarmonyPatch(typeof(Settings), "Awake")] public static class Settings_LoadSettings_Patch { [UsedImplicitly] private static void Postfix() { if (!((Object)(object)MuteGameInBackground.muteAudioToggle == (Object)null) || MuteGameInBackground.CreateToggle()) { MuteGameInBackground.muteAudioToggle.isOn = PlayerPrefs.GetInt("MuteGameInBackground", 0) == 1; } } } [HarmonyPatch(typeof(Settings), "OnOk")] public static class Settings_OnOk_Patch { [UsedImplicitly] private static void Postfix() { if ((Object)(object)MuteGameInBackground.muteAudioToggle != (Object)null) { PlayerPrefs.SetInt("MuteGameInBackground", MuteGameInBackground.muteAudioToggle.isOn ? 1 : 0); } } } [HarmonyPatch(typeof(SE_Rested), "UpdateTTL")] public static class Se_Rested_UpdateTtl_Patch { [UsedImplicitly] public static void Prefix(SE_Rested __instance) { PlayerConfiguration player = Configuration.Current.Player; if (player.IsEnabled) { __instance.m_TTLPerComfortLevel = player.restSecondsPerComfortLevel; } } } [HarmonyPatch(typeof(SE_Rested), "GetNearbyComfortPieces")] public static class Se_Rested_GetNearbyComfortPieces_Transpiler { [UsedImplicitly] public static IEnumerable Transpiler(IEnumerable instructions) { BuildingConfiguration building = Configuration.Current.Building; if (!building.IsEnabled || building.pieceComfortRadius == 10f) { return instructions; } List list = instructions.ToList(); for (int i = 0; i < list.Count; i++) { if (!(list[i].opcode != OpCodes.Ldc_R4)) { list[i].operand = Mathf.Clamp(building.pieceComfortRadius, 1f, 300f); return list; } } PatchLog.Failed("Se_Rested_GetNearbyComfortPieces_Transpiler", "`Building.pieceComfortRadius` will not work."); return list; } } public static class ShieldGeneratorFuel { [HarmonyPatch(typeof(ShieldGenerator), "Start")] public static class ShieldGenerator_Start_Patch { [UsedImplicitly] private static void Postfix(ShieldGenerator __instance) { if (Configuration.Current.ShieldGenerator.IsEnabled) { ZNetView nview = __instance.m_nview; if (nview != null && nview.IsValid() && Configuration.Current.ShieldGenerator.infiniteFuel) { __instance.SetFuel((float)__instance.m_maxFuel); } } } } [HarmonyPatch(typeof(ShieldGenerator), "OnProjectileHit")] public static class ShieldGenerator_OnProjectileHit_Patch { [UsedImplicitly] private static void Postfix(ShieldGenerator __instance) { UpdateFuel(__instance); } } [HarmonyPatch(typeof(ShieldGenerator), "RPC_Attack")] public static class ShieldGenerator_RPC_Attack_Patch { [UsedImplicitly] private static void Postfix(ShieldGenerator __instance) { UpdateFuel(__instance); } } [HarmonyPatch(typeof(ShieldGenerator), "Update")] public static class ShieldGenerator_Update_Patch { [UsedImplicitly] private static void Prefix(ShieldGenerator __instance) { ShieldGeneratorConfiguration shieldGenerator = Configuration.Current.ShieldGenerator; if (shieldGenerator.IsEnabled && !shieldGenerator.infiniteFuel && shieldGenerator.autoFuel) { Stopwatch stopwatch = GameObjectAssistant.GetStopwatch(((Component)__instance).gameObject); if (!stopwatch.IsRunning || stopwatch.ElapsedMilliseconds >= 1000) { stopwatch.Restart(); AddFuelFromNearbyChests(__instance); } } } } private static void UpdateFuel(ShieldGenerator __instance) { if (!Configuration.Current.ShieldGenerator.IsEnabled) { return; } ZNetView nview = __instance.m_nview; if (nview != null && nview.IsValid()) { if (Configuration.Current.ShieldGenerator.infiniteFuel) { __instance.SetFuel((float)__instance.m_maxFuel); } if (Configuration.Current.ShieldGenerator.autoFuel) { AddFuelFromNearbyChests(__instance); } } } private static void AddFuelFromNearbyChests(ShieldGenerator __instance) { int num = __instance.m_maxFuel - (int)Math.Ceiling(__instance.GetFuel()); if (num < 1) { return; } foreach (ItemDrop fuelItem in __instance.m_fuelItems) { ItemData itemData = fuelItem.m_itemData; int num2 = InventoryAssistant.RemoveItemInAmountFromAllNearbyChests(((Component)__instance).gameObject, Helper.Clamp(Configuration.Current.ShieldGenerator.autoRange, 1f, 50f), itemData, num, !Configuration.Current.ShieldGenerator.ignorePrivateAreaCheck); if (num2 < 1) { break; } for (int i = 0; i < num2; i++) { __instance.m_nview.InvokeRPC("RPC_AddFuel", Array.Empty()); } ValheimPlusPlugin.Logger.LogDebug((object)$"Added {num2} fuel({itemData.m_shared.m_name}) in {__instance.m_name}"); num -= num2; if (num < 1) { break; } } } } [HarmonyPatch(typeof(Ship), "Awake")] public static class Ship_Awake_Patch { [UsedImplicitly] public static void Postfix(Ship __instance) { ShipConfiguration ship = Configuration.Current.Ship; if (ship.IsEnabled) { Helper.applyModifierValueTo(ref __instance.m_force, ship.forwardSpeed); Helper.applyModifierValueTo(ref __instance.m_stearForce, ship.steerForce); Helper.applyModifierValueTo(ref __instance.m_backwardForce, ship.backwardSpeed); Helper.applyModifierValueTo(ref __instance.m_waterImpactDamage, ship.waterImpactDamage); Helper.applyModifierValueTo(ref __instance.m_rudderSpeed, ship.rudderSpeed); } } } [HarmonyPatch(typeof(Skills), "RaiseSkill")] public static class Skills_RaiseSkill_Patch { [UsedImplicitly] private static void Prefix(ref SkillType skillType, ref float factor) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected I4, but got Unknown //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected I4, but got Unknown ExperienceConfiguration experience = Configuration.Current.Experience; if (experience.IsEnabled) { SkillType val = skillType; float value = (val - 1) switch { 0 => experience.swords, 1 => experience.knives, 2 => experience.clubs, 3 => experience.polearms, 4 => experience.spears, 5 => experience.blocking, 6 => experience.axes, 7 => experience.bows, 8 => experience.elementalMagic, 9 => experience.bloodMagic, 10 => experience.unarmed, 11 => experience.pickaxes, 12 => experience.woodCutting, 13 => experience.crossbows, _ => (val - 100) switch { 0 => experience.jump, 1 => experience.sneak, 2 => experience.run, 3 => experience.swim, 4 => experience.fishing, 5 => experience.cooking, 6 => experience.farming, 7 => experience.crafting, 10 => experience.ride, _ => 0f, }, }; factor = Helper.applyModifierValue(factor, value); } } [UsedImplicitly] private static void Postfix(Skills __instance, SkillType skillType, float factor = 1f) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) HudConfiguration hud = Configuration.Current.Hud; if (hud.IsEnabled && hud.experienceGainedNotifications && (int)skillType != 0) { Skill skill = __instance.GetSkill(skillType); float value = skill.m_accumulator / (skill.GetNextLevelRequirement() / 100f); string text = $"Level {skill.m_level.tFloat(0)} {skill.m_info.m_skill} " + $"[{skill.m_accumulator.tFloat(2)}/{skill.GetNextLevelRequirement().tFloat(2)}] ({value.tFloat(0)}%)"; ((Character)__instance.m_player).Message((MessageType)1, text, 0, skill.m_info.m_icon, false); } } } [HarmonyPatch(typeof(Skills), "LowerAllSkills")] public static class Skills_LowerAllSkills_Patch { [UsedImplicitly] public static bool Prefix(ref float factor) { PlayerConfiguration player = Configuration.Current.Player; if (!player.IsEnabled) { return true; } if (player.deathPenaltyMultiplier <= -100f) { return false; } factor = Helper.applyModifierValue(factor, player.deathPenaltyMultiplier); return true; } } [HarmonyPatch(typeof(Smelter), "Awake")] public static class Smelter_Awake_Patch { private static void Prefix(Smelter __instance) { if (__instance.m_name.Equals(SmelterDefinitions.KilnName) && Configuration.Current.Kiln.IsEnabled) { __instance.m_maxOre = Configuration.Current.Kiln.maximumWood; __instance.m_secPerProduct = Configuration.Current.Kiln.productionSpeed; } else if (__instance.m_name.Equals(SmelterDefinitions.SmelterName) && Configuration.Current.Smelter.IsEnabled) { __instance.m_maxOre = Configuration.Current.Smelter.maximumOre; __instance.m_maxFuel = Configuration.Current.Smelter.maximumCoal; __instance.m_secPerProduct = Configuration.Current.Smelter.productionSpeed; __instance.m_fuelPerProduct = Configuration.Current.Smelter.coalUsedPerProduct; } else if (__instance.m_name.Equals(SmelterDefinitions.FurnaceName) && Configuration.Current.Furnace.IsEnabled) { __instance.m_maxOre = Configuration.Current.Furnace.maximumOre; __instance.m_maxFuel = Configuration.Current.Furnace.maximumCoal; __instance.m_secPerProduct = Configuration.Current.Furnace.productionSpeed; __instance.m_fuelPerProduct = Configuration.Current.Furnace.coalUsedPerProduct; if (Configuration.Current.Furnace.allowAllOres) { __instance.m_conversion.AddRange(FurnaceDefinitions.AdditionalConversions); } } else if (__instance.m_name.Equals(SmelterDefinitions.WindmillName) && Configuration.Current.Windmill.IsEnabled) { __instance.m_maxOre = Configuration.Current.Windmill.maximumBarley; __instance.m_secPerProduct = Configuration.Current.Windmill.productionSpeed; } else if (__instance.m_name.Equals(SmelterDefinitions.SpinningWheelName) && Configuration.Current.SpinningWheel.IsEnabled) { __instance.m_maxOre = Configuration.Current.SpinningWheel.maximumFlax; __instance.m_secPerProduct = Configuration.Current.SpinningWheel.productionSpeed; } else if (__instance.m_name.Equals(SmelterDefinitions.EitrRefineryName) && Configuration.Current.EitrRefinery.IsEnabled) { __instance.m_maxOre = Configuration.Current.EitrRefinery.maximumSoftTissue; __instance.m_maxFuel = Configuration.Current.EitrRefinery.maximumSap; __instance.m_secPerProduct = Configuration.Current.EitrRefinery.productionSpeed; } } } [HarmonyPatch(typeof(Smelter), "Spawn")] public static class Smelter_Spawn_Patch { private static bool Prefix(string ore, int stack, ref Smelter __instance) { Smelter smelter = __instance; if (!smelter.m_nview.IsOwner()) { return true; } if (__instance.m_name.Equals(SmelterDefinitions.KilnName) && Configuration.Current.Kiln.IsEnabled && Configuration.Current.Kiln.autoDeposit) { return spawn(Helper.Clamp(Configuration.Current.Kiln.autoRange, 1f, 50f), Configuration.Current.Kiln.ignorePrivateAreaCheck); } if (__instance.m_name.Equals(SmelterDefinitions.SmelterName) && Configuration.Current.Smelter.IsEnabled && Configuration.Current.Smelter.autoDeposit) { return spawn(Helper.Clamp(Configuration.Current.Smelter.autoRange, 1f, 50f), Configuration.Current.Smelter.ignorePrivateAreaCheck); } if (__instance.m_name.Equals(SmelterDefinitions.FurnaceName) && Configuration.Current.Furnace.IsEnabled && Configuration.Current.Furnace.autoDeposit) { return spawn(Helper.Clamp(Configuration.Current.Furnace.autoRange, 1f, 50f), Configuration.Current.Furnace.ignorePrivateAreaCheck); } if (__instance.m_name.Equals(SmelterDefinitions.WindmillName) && Configuration.Current.Windmill.IsEnabled && Configuration.Current.Windmill.autoDeposit) { return spawn(Helper.Clamp(Configuration.Current.Windmill.autoRange, 1f, 50f), Configuration.Current.Windmill.ignorePrivateAreaCheck); } if (__instance.m_name.Equals(SmelterDefinitions.SpinningWheelName) && Configuration.Current.SpinningWheel.IsEnabled && Configuration.Current.SpinningWheel.autoDeposit) { return spawn(Helper.Clamp(Configuration.Current.SpinningWheel.autoRange, 1f, 50f), Configuration.Current.SpinningWheel.ignorePrivateAreaCheck); } if (__instance.m_name.Equals(SmelterDefinitions.EitrRefineryName) && Configuration.Current.EitrRefinery.IsEnabled && Configuration.Current.EitrRefinery.autoDeposit) { return spawn(Helper.Clamp(Configuration.Current.EitrRefinery.autoRange, 1f, 50f), Configuration.Current.EitrRefinery.ignorePrivateAreaCheck); } return true; bool spawn(float autoDepositRange, bool ignorePrivateAreaCheck) { List nearbyChests = InventoryAssistant.GetNearbyChests(((Component)smelter).gameObject, autoDepositRange, !ignorePrivateAreaCheck); ItemDrop comp; if (nearbyChests.Count != 0) { if (autoDepositRange > 50f) { autoDepositRange = 50f; } else if (autoDepositRange < 1f) { autoDepositRange = 1f; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(((Object)((Component)smelter.GetItemConversion(ore).m_to).gameObject).name); ZNetView.m_forceDisableInit = true; GameObject val = Object.Instantiate(itemPrefab); ZNetView.m_forceDisableInit = false; comp = val.GetComponent(); comp.m_itemData.m_stack = stack; ItemDrop.OnCreateNew(comp, (smelter.m_nview.GetZDO().GetBool(ZDOVars.s_cheatedQueued, false) || smelter.m_nview.GetZDO().GetBool(ZDOVars.s_cheated, false)) && !PlayerProfile.s_bypassCheatChecks); bool result = spawnNearbyChest(mustHaveItem: true); Object.Destroy((Object)(object)val); return result; } return true; bool spawnNearbyChest(bool mustHaveItem) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) foreach (Container item in nearbyChests) { Inventory inventory = item.GetInventory(); if ((!mustHaveItem || inventory.HaveItem(comp.m_itemData.m_shared.m_name, true)) && inventory.AddItem(comp.m_itemData)) { smelter.m_produceEffects.Create(((Component)smelter).transform.position, ((Component)smelter).transform.rotation, (Transform)null, 1f, -1, default(ZDOID)); InventoryAssistant.ConveyContainerToNetwork(item); return false; } } if (mustHaveItem) { return spawnNearbyChest(mustHaveItem: false); } return true; } } } } [HarmonyPatch(typeof(Smelter), "UpdateSmelter")] public static class Smelter_UpdateSmelter_Patch { private static void Prefix(Smelter __instance) { if ((Object)(object)__instance == (Object)null || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || (Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsOwner()) { return; } Stopwatch stopwatch = GameObjectAssistant.GetStopwatch(((Component)__instance).gameObject); if (stopwatch.IsRunning && stopwatch.ElapsedMilliseconds < 1000) { return; } stopwatch.Restart(); float value = 0f; bool flag = false; bool flag2 = false; if (__instance.m_name.Equals(SmelterDefinitions.KilnName)) { if (!Configuration.Current.Kiln.IsEnabled || !Configuration.Current.Kiln.autoFuel) { return; } flag2 = true; value = Configuration.Current.Kiln.autoRange; flag = Configuration.Current.Kiln.ignorePrivateAreaCheck; } else if (__instance.m_name.Equals(SmelterDefinitions.SmelterName)) { if (!Configuration.Current.Smelter.IsEnabled || !Configuration.Current.Smelter.autoFuel) { return; } value = Configuration.Current.Smelter.autoRange; flag = Configuration.Current.Smelter.ignorePrivateAreaCheck; } else if (__instance.m_name.Equals(SmelterDefinitions.FurnaceName)) { if (!Configuration.Current.Furnace.IsEnabled || !Configuration.Current.Furnace.autoFuel) { return; } value = Configuration.Current.Furnace.autoRange; flag = Configuration.Current.Furnace.ignorePrivateAreaCheck; } else if (__instance.m_name.Equals(SmelterDefinitions.WindmillName)) { if (!Configuration.Current.Windmill.IsEnabled || !Configuration.Current.Windmill.autoFuel) { return; } value = Configuration.Current.Windmill.autoRange; flag = Configuration.Current.Windmill.ignorePrivateAreaCheck; } else if (__instance.m_name.Equals(SmelterDefinitions.SpinningWheelName)) { if (!Configuration.Current.SpinningWheel.IsEnabled || !Configuration.Current.SpinningWheel.autoFuel) { return; } value = Configuration.Current.SpinningWheel.autoRange; flag = Configuration.Current.SpinningWheel.ignorePrivateAreaCheck; } else if (__instance.m_name.Equals(SmelterDefinitions.EitrRefineryName)) { if (!Configuration.Current.EitrRefinery.IsEnabled || !Configuration.Current.EitrRefinery.autoFuel) { return; } value = Configuration.Current.EitrRefinery.autoRange; flag = Configuration.Current.EitrRefinery.ignorePrivateAreaCheck; } else { if (!__instance.m_name.Equals(SmelterDefinitions.HotTubName) || !Configuration.Current.HotTub.IsEnabled) { return; } if (Configuration.Current.HotTub.infiniteFuel) { __instance.SetFuel((float)__instance.m_maxFuel); return; } if (Configuration.Current.HotTub.autoFuel) { value = Configuration.Current.HotTub.autoRange; flag = Configuration.Current.HotTub.ignorePrivateAreaCheck; } } value = Helper.Clamp(value, 1f, 50f); int num = __instance.m_maxOre - __instance.GetQueueSize(); int num2 = __instance.m_maxFuel - (int)Math.Ceiling(__instance.GetFuel()); if (Object.op_Implicit((Object)(object)__instance.m_fuelItem) && num2 > 0) { ItemData itemData = __instance.m_fuelItem.m_itemData; int num3 = InventoryAssistant.RemoveItemInAmountFromAllNearbyChests(((Component)__instance).gameObject, value, itemData, num2, !flag); for (int i = 0; i < num3; i++) { __instance.m_nview.InvokeRPC("RPC_AddFuel", new object[0]); } if (num3 > 0) { ValheimPlusPlugin.Logger.LogDebug((object)("Added " + num3 + " fuel(" + itemData.m_shared.m_name + ") in " + __instance.m_name)); } } if (num <= 0) { return; } List nearbyChests = InventoryAssistant.GetNearbyChests(((Component)__instance).gameObject, value); foreach (Container item in nearbyChests) { foreach (ItemConversion item2 in __instance.m_conversion) { if (flag2) { if ((Configuration.Current.Kiln.dontProcessFineWood && item2.m_from.m_itemData.m_shared.m_name.Equals(WoodDefinitions.FineWoodName)) || (Configuration.Current.Kiln.dontProcessRoundLog && item2.m_from.m_itemData.m_shared.m_name.Equals(WoodDefinitions.RoundLogName))) { continue; } int num4 = ((Configuration.Current.Kiln.stopAutoFuelThreshold >= 0) ? Configuration.Current.Kiln.stopAutoFuelThreshold : 0); if (num4 > 0 && InventoryAssistant.GetItemAmountInItemList(InventoryAssistant.GetNearbyChestItemsByContainerList(nearbyChests), item2.m_to.m_itemData) >= num4) { return; } } ItemData oreItem = item2.m_from.m_itemData; bool flag3 = item.GetInventory().GetAllItems().Any((ItemData val) => val.m_shared.m_name == oreItem.m_shared.m_name && val.m_cheated); int num5 = InventoryAssistant.RemoveItemFromChest(item, oreItem, num); if (num5 > 0) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(((Object)((Component)item2.m_from).gameObject).name); for (int num6 = 0; num6 < num5; num6++) { __instance.m_nview.InvokeRPC("RPC_AddOre", new object[2] { ((Object)itemPrefab).name, flag3 }); } num -= num5; if (num5 > 0) { ValheimPlusPlugin.Logger.LogDebug((object)("Added " + num5 + " ores(" + oreItem.m_shared.m_name + ") in " + __instance.m_name)); } if (num == 0) { return; } } } } } } [HarmonyPatch(typeof(Smelter), "FindCookableItem")] public static class Smelter_FindCookableItem_Transpiler { private static MethodInfo method_PreventUsingSpecificWood = AccessTools.Method(typeof(Smelter_FindCookableItem_Transpiler), "PreventUsingSpecificWood", (Type[])null, (Type[])null); [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown if (!Configuration.Current.Kiln.IsEnabled) { return instructions; } int num = -1; List list = instructions.ToList(); for (int i = 0; i < list.Count; i++) { if (list[i].opcode == OpCodes.Stloc_1) { list.Insert(++i, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Insert(++i, new CodeInstruction(OpCodes.Ldloc_1, (object)null)); list.Insert(++i, new CodeInstruction(OpCodes.Call, (object)method_PreventUsingSpecificWood)); num = i; } else if (num != -1 && list[i].opcode == OpCodes.Brfalse) { list.Insert(++num, new CodeInstruction(OpCodes.Brtrue, list[i].operand)); return list.AsEnumerable(); } } PatchLog.Failed("Smelter_FindCookableItem_Transpiler", "Smelters will not take ore from nearby chests."); return instructions; } private static bool PreventUsingSpecificWood(Smelter smelter, ItemConversion itemConversion) { if (smelter.m_name.Equals(SmelterDefinitions.KilnName) && ((Configuration.Current.Kiln.dontProcessFineWood && itemConversion.m_from.m_itemData.m_shared.m_name.Equals(WoodDefinitions.FineWoodName)) || (Configuration.Current.Kiln.dontProcessRoundLog && itemConversion.m_from.m_itemData.m_shared.m_name.Equals(WoodDefinitions.RoundLogName)))) { return true; } return false; } } [HarmonyPatch(typeof(Smelter), "UpdateSmelter")] public static class Smelter_UpdaterSmelter_Transpiler { private static MethodInfo method_Windmill_GetPowerOutput = AccessTools.Method(typeof(Windmill), "GetPowerOutput", (Type[])null, (Type[])null); private static MethodInfo method_GetPowerOutput = AccessTools.Method(typeof(Smelter_UpdaterSmelter_Transpiler), "GetPowerOutput", (Type[])null, (Type[])null); [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { if (!Configuration.Current.Windmill.IsEnabled || !Configuration.Current.Windmill.ignoreWindIntensity) { return instructions; } List list = instructions.ToList(); for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], method_Windmill_GetPowerOutput)) { list[i].operand = method_GetPowerOutput; return list.AsEnumerable(); } } return instructions; } private static float GetPowerOutput(Windmill __instance) { return 1f; } } public static class SmelterDefinitions { public static readonly string KilnName = "$piece_charcoalkiln"; public static readonly string SmelterName = "$piece_smelter"; public static readonly string FurnaceName = "$piece_blastfurnace"; public static readonly string WindmillName = "$piece_windmill"; public static readonly string SpinningWheelName = "$piece_spinningwheel"; public static readonly string EitrRefineryName = "$piece_eitrrefinery"; public static readonly string HotTubName = "$piece_bathtub"; } public static class FurnaceDefinitions { public static readonly string CopperOrePrefabName = "CopperOre"; public static readonly string CopperScrapPrefabName = "CopperScrap"; public static readonly string ScrapIronPrefabName = "IronScrap"; public static readonly string SilverOrePrefabName = "SilverOre"; public static readonly string TinOrePrefabName = "TinOre"; public static readonly string CopperPrefabName = "Copper"; public static readonly string IronPrefabName = "Iron"; public static readonly string SilverPrefabName = "Silver"; public static readonly string TinPrefabName = "Tin"; public static readonly List AdditionalConversions = new List { new ItemConversion { m_from = ObjectDB.instance.GetItemPrefab(CopperOrePrefabName).GetComponent(), m_to = ((Component)ObjectDB.instance.GetItemPrefab(CopperPrefabName).GetComponent()).GetComponent() }, new ItemConversion { m_from = ObjectDB.instance.GetItemPrefab(CopperScrapPrefabName).GetComponent(), m_to = ((Component)ObjectDB.instance.GetItemPrefab(CopperPrefabName).GetComponent()).GetComponent() }, new ItemConversion { m_from = ObjectDB.instance.GetItemPrefab(ScrapIronPrefabName).GetComponent(), m_to = ((Component)ObjectDB.instance.GetItemPrefab(IronPrefabName).GetComponent()).GetComponent() }, new ItemConversion { m_from = ObjectDB.instance.GetItemPrefab(SilverOrePrefabName).GetComponent(), m_to = ((Component)ObjectDB.instance.GetItemPrefab(SilverPrefabName).GetComponent()).GetComponent() }, new ItemConversion { m_from = ObjectDB.instance.GetItemPrefab(TinOrePrefabName).GetComponent(), m_to = ((Component)ObjectDB.instance.GetItemPrefab(TinPrefabName).GetComponent()).GetComponent() } }; } public static class WoodDefinitions { public static readonly string FineWoodName = "$item_finewood"; public static readonly string RoundLogName = "$item_roundlog"; } public static class ChangeSteamServerVariables { public static void Prefix(ref int cPlayersMax) { if (Configuration.Current.Server.IsEnabled) { int maxPlayers = Configuration.Current.Server.maxPlayers; if (maxPlayers >= 1) { cPlayersMax = maxPlayers; } } } } [HarmonyPatch(typeof(Talker), "Awake")] public static class Chat_Awake_Patch { private static bool Prefix(ref Talker __instance) { if (Configuration.Current.Chat.IsEnabled) { __instance.m_visperDistance = Configuration.Current.Chat.defaultWhisperDistance; __instance.m_normalDistance = Configuration.Current.Chat.defaultNormalDistance; __instance.m_shoutDistance = Configuration.Current.Chat.defaultShoutDistance; } return true; } } public enum TameableMortalityTypes { [UsedImplicitly] Normal, Essential, Immortal } [Flags] public enum AnimalType { [UsedImplicitly] None = 0, Boar = 1, Wolf = 2, Lox = 4, Hen = 8, Asksvin = 0x10, All = 0x1F } public static class TameableHelpers { public static readonly Dictionary NamedTypes = new Dictionary { { "$enemy_asksvin", AnimalType.Asksvin }, { "$enemy_asksvin_hatchling", AnimalType.Asksvin }, { "$enemy_boar", AnimalType.Boar }, { "$enemy_boarpiggy", AnimalType.Boar }, { "$enemy_wolf", AnimalType.Wolf }, { "$enemy_wolfcub", AnimalType.Wolf }, { "$enemy_lox", AnimalType.Lox }, { "$enemy_loxcalf", AnimalType.Lox }, { "$enemy_hen", AnimalType.Hen }, { "$enemy_chicken", AnimalType.Hen } }; public static bool IsValidAnimalType(string name) { if (!NamedTypes.TryGetValue(name, out var value)) { return false; } return Configuration.Current.Tameable.animalTypes.HasFlag(value); } public static bool IsHungerIgnored(Tameable instance) { TameableConfiguration tameable = Configuration.Current.Tameable; if (!tameable.IsEnabled || !tameable.ignoreHunger || !IsValidAnimalType(instance.m_character.m_name)) { return false; } return instance.m_nview.GetZDO().GetFloat(ZDOVars.s_tameTimeLeft, 0f) > 0f; } public static bool IsAlertedWithIgnore(Tameable tameable) { if (!IsValidAnimalType(tameable.m_character.m_name)) { return ((BaseAI)tameable.m_monsterAI).IsAlerted(); } return false; } } [HarmonyPatch(typeof(Tameable), "GetHoverText")] public static class Tameable_GetHoverText_Patch { [UsedImplicitly] public static void Postfix(Tameable __instance, ref string __result) { if (Configuration.Current.Tameable.IsEnabled && Configuration.Current.Tameable.stunInformation && __instance.m_character.m_nview.GetZDO().GetBool("isRecoveringFromStun", false)) { __result = __result.Insert(__result.IndexOf(" )", StringComparison.Ordinal), ", Stunned"); } Procreation component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { ProcreationHelpers.AddLoveInformation(__instance, component, ref __result); } } } [HarmonyPatch(typeof(Tameable), "IsHungry")] public static class Tameable_IsHungry_Patch { [UsedImplicitly] private static void Postfix(Tameable __instance, ref bool __result) { if (__result) { bool flag = __instance.m_character.IsTamed(); __result = !(flag ? ProcreationHelpers.IsHungerIgnored(__instance) : TameableHelpers.IsHungerIgnored(__instance)); } } } [HarmonyPatch(typeof(Tameable), "Awake")] public static class Tameable_Awake_Patch { [UsedImplicitly] public static void Postfix(Tameable __instance) { TameableConfiguration tameable = Configuration.Current.Tameable; if (tameable.IsEnabled && TameableHelpers.IsValidAnimalType(__instance.m_character.m_name)) { Helper.applyModifierValueTo(ref __instance.m_tamingTime, tameable.tameTimeMultiplier); Helper.applyModifierValueTo(ref __instance.m_tamingSpeedMultiplierRange, tameable.tameBoostRangeMultiplier); Helper.applyModifierValueTo(ref __instance.m_tamingBoostMultiplier, tameable.tameBoostMultiplier); float num = default(float); if (__instance.m_nview.GetZDO().GetFloat(ZDOVars.s_tameTimeLeft, ref num) && num > __instance.m_tamingTime) { __instance.m_nview.GetZDO().Set(ZDOVars.s_tameTimeLeft, __instance.m_tamingTime); } } } } [HarmonyPatch(typeof(Tameable))] public static class Tameable_Alerted_Patches { [UsedImplicitly] private static IEnumerable TargetMethods() { yield return AccessTools.Method(typeof(Tameable), "TamingUpdate", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Tameable), "GetStatusString", (Type[])null, (Type[])null); } [UsedImplicitly] public static IEnumerable Transpiler(IEnumerable instructions, ILGenerator ilGenerator) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown TameableConfiguration tameable = Configuration.Current.Tameable; if (!tameable.IsEnabled || !tameable.ignoreAlerted) { return instructions; } List list = instructions.ToList(); try { MethodInfo methodInfo = AccessTools.Method(typeof(BaseAI), "IsAlerted", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(TameableHelpers), "IsAlertedWithIgnore", (Type[])null, (Type[])null); return new CodeMatcher((IEnumerable)list, ilGenerator).MatchStartForward((CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Callvirt, (object)methodInfo, (string)null) }).ThrowIfNotMatch("Could not find BaseAI.IsAlerted call", Array.Empty()).Advance(-1) .RemoveInstructions(2) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Call, (object)methodInfo2) }) .InstructionEnumeration(); } catch (Exception exception) { PatchLog.Failed("Tameable_Alerted_Patches", "Tamed creature hover text will be unchanged.", exception); return list; } } } [HarmonyPatch(typeof(TeleportWorld), "Teleport", new Type[] { typeof(Player) })] public static class TeleportWorld_Teleport_Patch { private static bool Prefix(ref TeleportWorld __instance, ref Player player) { if (Configuration.Current.Game.IsEnabled && Configuration.Current.Game.disablePortals) { MessageHud.instance.ShowMessage((MessageType)2, "Portals have been disabled on this Server.", 0, (Sprite)null, false, true); return false; } return true; } } [HarmonyPatch(typeof(TeleportWorld), "GetHoverText")] public static class TeleportWorld_bigPortalText_Patch { private static void Postfix(TeleportWorld __instance, string __result) { string text = __instance.GetText(); if (Configuration.Current.Game.IsEnabled && Configuration.Current.Game.bigPortalNames) { __result = Localization.instance.Localize("$piece_portal $piece_portal_tag:" + " " + "[" + text + "]"); MessageHud.instance.ShowMessage((MessageType)2, __result, 0, (Sprite)null, false, true); } } } [HarmonyPatch(typeof(Terminal), "AddString", new Type[] { typeof(PlatformUserID), typeof(string), typeof(Type), typeof(bool) })] public static class Terminal_AddString_Transpiler { private static readonly MethodInfo Method_String_ToUpper = AccessTools.Method(typeof(string), "ToUpper", (Type[])null, (Type[])null); private static readonly MethodInfo Method_String_ToLowerInvariant = AccessTools.Method(typeof(string), "ToLowerInvariant", (Type[])null, (Type[])null); [UsedImplicitly] [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown ChatConfiguration chat = Configuration.Current.Chat; if (!chat.IsEnabled || chat.forcedCase) { return instructions; } List list = instructions.ToList(); try { return new CodeMatcher((IEnumerable)list, generator).MatchStartForward((CodeMatch[])(object)new CodeMatch[3] { CodeMatch.op_Implicit(OpCodes.Ldarg_2), new CodeMatch((OpCode?)OpCodes.Callvirt, (object)Method_String_ToLowerInvariant, (string)null), CodeMatch.op_Implicit(OpCodes.Starg_S) }).ThrowIfNotMatch("No match for code that sets whispers to lower case.", Array.Empty()).RemoveInstructions(3) .Start() .MatchStartForward((CodeMatch[])(object)new CodeMatch[3] { CodeMatch.op_Implicit(OpCodes.Ldarg_2), new CodeMatch((OpCode?)OpCodes.Callvirt, (object)Method_String_ToUpper, (string)null), CodeMatch.op_Implicit(OpCodes.Starg_S) }) .ThrowIfNotMatch("No match for code that sets shouts to upper case.", Array.Empty()) .RemoveInstructions(3) .InstructionEnumeration(); } catch (Exception exception) { PatchLog.Failed("Terminal_AddString_Transpiler", "The `Chat.forcedCase` setting will not work.", exception); return list; } } } public static class TraderExtensions { public static bool SellsItem(this Trader trader, string itemName) { return trader.m_items.Any((TradeItem item) => ((Object)item.m_prefab).name == itemName); } public static TradeItem GetTradeItem(this Trader trader, string itemName) { return ((IEnumerable)trader.m_items).FirstOrDefault((Func)((TradeItem item) => item.m_prefab.m_itemData.m_shared.m_name == itemName)); } } [HarmonyPatch(typeof(Trader), "Start")] public static class Trader_Start_Patch { [UsedImplicitly] public static void Postfix(Trader __instance) { switch (__instance.m_name) { case "$npc_haldor": AddHaldorItems(__instance); break; case "$npc_hildir": AddHildirItems(__instance); break; case "$npc_bogwitch": AddBogWitchItems(__instance); break; } } private static void AddHaldorItems(Trader haldor) { if (Configuration.Current.Egg.IsEnabled) { TradeItem tradeItem = haldor.GetTradeItem("$item_chicken_egg"); tradeItem.m_requiredGlobalKey = (Configuration.Current.Egg.soldByDefault ? "" : "defeated_goblinking"); tradeItem.m_price = Configuration.Current.Egg.sellPrice; } } private static void AddHildirItems(Trader hildir) { } private static void AddBogWitchItems(Trader bogWitch) { } } [HarmonyPatch(typeof(Turret), "Awake")] public static class Turret_Awake_Patch { [UsedImplicitly] private static void Prefix(Turret __instance) { TurretConfiguration turret = Configuration.Current.Turret; if (turret.IsEnabled) { if (turret.ignorePlayers) { __instance.m_targetPlayers = false; } __instance.m_turnRate = Helper.applyModifierValue(__instance.m_turnRate, turret.turnRate); __instance.m_attackCooldown = Helper.applyModifierValue(__instance.m_attackCooldown, turret.attackCooldown); __instance.m_viewDistance = Helper.applyModifierValue(__instance.m_viewDistance, turret.viewDistance); } } } [HarmonyPatch(typeof(Turret), "ShootProjectile")] public static class Turret_ShootProjectile_Patch { private static readonly FieldInfo Field_Turret_M_MaxAmmo = AccessTools.Field(typeof(Turret), "m_maxAmmo"); private static readonly FieldInfo Field_Attack_M_ProjectileVel = AccessTools.Field(typeof(Attack), "m_projectileVel"); private static readonly FieldInfo Field_Attack_M_ProjectileAccuracy = AccessTools.Field(typeof(Attack), "m_projectileAccuracy"); [UsedImplicitly] [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Expected O, but got Unknown //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Expected O, but got Unknown //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Expected O, but got Unknown //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Expected O, but got Unknown //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown TurretConfiguration turret = Configuration.Current.Turret; if (!turret.IsEnabled) { return instructions; } bool unlimitedAmmo = turret.unlimitedAmmo; bool flag = turret.projectileVelocity != 0f; bool flag2 = turret.projectileAccuracy != 0f; if (!unlimitedAmmo && !flag && !flag2) { return instructions; } List list = instructions.ToList(); int num = -1; int num2 = -1; int num3 = -1; Label? label = default(Label?); for (int i = 0; i < list.Count; i++) { if (unlimitedAmmo && i + 2 < list.Count && CodeInstructionExtensions.LoadsField(list[i], Field_Turret_M_MaxAmmo, false) && list[i + 1].opcode == OpCodes.Ldc_I4_0 && CodeInstructionExtensions.Branches(list[i + 2], ref label)) { list[i + 1] = new CodeInstruction(OpCodes.Ldc_I4, (object)int.MaxValue); num = i + 1; } if (flag && CodeInstructionExtensions.LoadsField(list[i], Field_Attack_M_ProjectileVel, false)) { float num4 = Helper.applyModifierValue(1f, turret.projectileVelocity); list.InsertRange(i + 1, (IEnumerable)(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Ldc_R4, (object)num4), new CodeInstruction(OpCodes.Mul, (object)null) }); num2 = i; } if (flag2 && CodeInstructionExtensions.LoadsField(list[i], Field_Attack_M_ProjectileAccuracy, false)) { float num5 = Helper.applyModifierValue(1f, 0f - turret.projectileAccuracy); list.InsertRange(i + 1, (IEnumerable)(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Ldc_R4, (object)num5), new CodeInstruction(OpCodes.Mul, (object)null) }); num3 = i; } } if (unlimitedAmmo && num == -1) { PatchLog.Failed("Turret_ShootProjectile_Patch", "`Turret.unlimitedAmmo` will not work."); } if (flag && num2 == -1) { PatchLog.Failed("Turret_ShootProjectile_Patch", "`Turret.projectileVelocity` will not work."); } if (flag2 && num3 == -1) { PatchLog.Failed("Turret_ShootProjectile_Patch", "`Turret.projectileAccuracy` will not work."); } return list.AsEnumerable(); } } internal class WagonModifications { [HarmonyPatch(typeof(Vagon), "UpdateMass")] public static class ModifyWagonMass { private static bool Prefix(ref Vagon __instance) { if (!__instance.m_nview.IsOwner()) { return false; } if ((Object)(object)__instance.m_container == (Object)null) { return false; } float num = 0f; num = ((!Configuration.Current.Wagon.IsEnabled) ? __instance.m_container.GetInventory().GetTotalWeight() : Helper.applyModifierValue(__instance.m_container.GetInventory().GetTotalWeight(), Configuration.Current.Wagon.wagonExtraMassFromItems)); if (Configuration.Current.Wagon.IsEnabled) { __instance.m_baseMass = Configuration.Current.Wagon.wagonBaseMass; } else { __instance.m_baseMass = 20f; } float mass = __instance.m_baseMass + num * __instance.m_itemWeightMassFactor; __instance.SetMass(mass); return false; } } } internal class WardPrivateArea { [HarmonyPatch(typeof(PrivateArea), "Awake")] public static class ModifyWardRange { private static void Prefix(ref PrivateArea __instance) { if (Configuration.Current.Ward.IsEnabled && Configuration.Current.Ward.wardRange > 0f) { __instance.m_radius = Configuration.Current.Ward.wardRange; Helper.ResizeChildEffectArea((MonoBehaviour)(object)__instance, (Type)4, (Configuration.Current.Ward.wardEnemySpawnRange > 0f) ? Configuration.Current.Ward.wardEnemySpawnRange : Configuration.Current.Ward.wardRange); } } } } [HarmonyPatch(typeof(WearNTear), "UpdateWear")] public static class WearNTear_UpdateWear_Patch { [UsedImplicitly] private static void Prefix(float time, ref float ___m_rainTimer) { if (Configuration.Current.Building.IsEnabled && Configuration.Current.Building.noWeatherDamage) { ___m_rainTimer = time; } } } [HarmonyPatch(typeof(WearNTear), "HaveSupport")] public static class WearNTear_HaveSupport_Patch { private static void Postfix(ref bool __result) { if (Configuration.Current.StructuralIntegrity.IsEnabled && Configuration.Current.StructuralIntegrity.disableStructuralIntegrity) { __result = true; } } } [HarmonyPatch(typeof(WearNTear), "ApplyDamage")] public static class WearNTear_ApplyDamage_Patch { private static readonly HashSet UpdateWearMethodNames = new HashSet { "UpdateWear", "DMD" }; private static bool Prefix(ref WearNTear __instance, ref float damage) { StackTrace stackTrace = new StackTrace(); string name = stackTrace.GetFrame(2).GetMethod().Name; if (!Configuration.Current.StructuralIntegrity.IsEnabled || !Object.op_Implicit((Object)(object)__instance.m_piece) || !__instance.m_piece.IsPlacedByPlayer() || UpdateWearMethodNames.Contains(name)) { return true; } if (__instance.m_piece.m_name.StartsWith("$ship")) { if (Configuration.Current.StructuralIntegrity.disableDamageToPlayerBoats || (Configuration.Current.StructuralIntegrity.disableWaterDamageToPlayerBoats && stackTrace.GetFrame(15).GetMethod().Name == "UpdateWaterForce")) { return false; } return true; } if (__instance.m_piece.m_name.StartsWith("$tool_cart")) { if (Configuration.Current.StructuralIntegrity.disableDamageToPlayerCarts || (Configuration.Current.StructuralIntegrity.disableWaterDamageToPlayerCarts && stackTrace.GetFrame(15).GetMethod().Name == "UpdateWaterForce")) { return false; } return true; } return !Configuration.Current.StructuralIntegrity.disableDamageToPlayerStructures; } } [HarmonyPatch(typeof(WearNTear), "GetMaterialProperties")] public static class WearNTear_GetMaterialProperties_Patch { private static readonly Dictionary> Multipliers = new Dictionary> { [(MaterialType)0] = () => Configuration.Current.StructuralIntegrity.wood, [(MaterialType)1] = () => Configuration.Current.StructuralIntegrity.stone, [(MaterialType)2] = () => Configuration.Current.StructuralIntegrity.iron, [(MaterialType)3] = () => Configuration.Current.StructuralIntegrity.hardWood, [(MaterialType)4] = () => Configuration.Current.StructuralIntegrity.marble, [(MaterialType)5] = () => Configuration.Current.StructuralIntegrity.ashstone, [(MaterialType)6] = () => Configuration.Current.StructuralIntegrity.ancient, [(MaterialType)7] = () => Configuration.Current.StructuralIntegrity.ice, [(MaterialType)8] = () => Configuration.Current.StructuralIntegrity.timberwood }; [UsedImplicitly] private static void Postfix(ref WearNTear __instance, ref float horizontalLoss, ref float verticalLoss) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) if (Configuration.Current.StructuralIntegrity.IsEnabled) { Func value; if (Configuration.Current.StructuralIntegrity.disableStructuralIntegrity) { verticalLoss = 0f; horizontalLoss = 0f; } else if (Multipliers.TryGetValue(__instance.m_materialType, out value)) { float num = Helper.Clamp(value(), 0f, 100f); verticalLoss -= verticalLoss / 100f * num; horizontalLoss -= horizontalLoss / 100f * num; } } } } [HarmonyPatch(typeof(WispSpawner), "Start")] internal static class WispSpawnerModification { private static readonly FieldRef m_maxSpawned = AccessTools.FieldRefAccess("m_maxSpawned"); private static readonly FieldRef m_spawnChance = AccessTools.FieldRefAccess("m_spawnChance"); private static readonly FieldRef m_spawnInterval = AccessTools.FieldRefAccess("m_spawnInterval"); private static readonly FieldRef m_onlySpawnAtNight = AccessTools.FieldRefAccess("m_onlySpawnAtNight"); [HarmonyPrefix] private static void Prefix(WispSpawner __instance) { if (Configuration.Current.WispSpawner.IsEnabled) { m_onlySpawnAtNight.Invoke(__instance) = Configuration.Current.WispSpawner.onlySpawnAtNight; m_maxSpawned.Invoke(__instance) = Configuration.Current.WispSpawner.maximumWisps; m_spawnChance.Invoke(__instance) = Helper.applyModifierValue(m_spawnChance.Invoke(__instance), Configuration.Current.WispSpawner.wispSpawnChanceMultiplier); m_spawnInterval.Invoke(__instance) = Helper.applyModifierValue(m_spawnInterval.Invoke(__instance), Configuration.Current.WispSpawner.wispSpawnIntervalMultiplier); } } } [HarmonyPatch(typeof(ZNet))] public class HookZNet { [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(ZNet), "GetOtherPublicPlayers", new Type[] { typeof(List) })] public static void GetOtherPublicPlayers(object instance, List playerList) { throw new NotImplementedException(); } } [HarmonyPatch(typeof(ZNet), "SendPeriodicData")] public static class PeriodicDataHandler { private static void Postfix() { RpcQueue.SendNextRpc(); } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] public static class ZNet_RPC_PeerInfo_Transpiler { private static MethodInfo method_ZNet_GetNrOfPlayers = AccessTools.Method(typeof(ZNet), "GetNrOfPlayers", (Type[])null, (Type[])null); [HarmonyTranspiler] public static IEnumerable Transpiler(IEnumerable instructions) { if (!Configuration.Current.Server.IsEnabled) { return instructions; } List list = instructions.ToList(); for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], method_ZNet_GetNrOfPlayers)) { list[i + 1].operand = Configuration.Current.Server.maxPlayers; return list.AsEnumerable(); } } PatchLog.Failed("ZNet_RPC_PeerInfo_Transpiler", "`Server.maxPlayers` will not work."); return instructions; } } [HarmonyPatch(typeof(ZNet), "Awake")] public static class ZNet_Awake_Patch { private static void Postfix() { BepInExConfig.RegisterForServerSync(); ConfigurationManagerWatcher.SetInWorld(inWorld: true); } } [HarmonyPatch(typeof(ZNet), "Shutdown")] public static class ZNet_Shutdown_Patch { private static void Prefix(ref ZNet __instance) { ConfigurationManagerWatcher.SetInWorld(inWorld: false); if (!__instance.IsServer()) { if (Configuration.Current.Map.IsEnabled && Configuration.Current.Map.shareMapProgression) { VPlusMapSync.ShouldSyncOnSpawn = true; } } else if (Configuration.Current.Map.IsEnabled && Configuration.Current.Map.shareMapProgression) { VPlusMapSync.SaveMapDataToDisk(); } } } [HarmonyPatch(typeof(ZNet), "SetPublicReferencePosition")] public static class PreventPublicPositionToggle { private static void Postfix(ref bool pub, ref bool ___m_publicReferencePosition) { if (Configuration.Current.Map.IsEnabled && Configuration.Current.Map.preventPlayerFromTurningOffPublicPosition) { ___m_publicReferencePosition = true; } } } [HarmonyPatch(typeof(ZNet), "RPC_ServerSyncedPlayerData")] public static class PlayerPositionWatcher { private static void Postfix(ref ZNet __instance, ZRpc rpc) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) if (!__instance.IsServer() || !Configuration.Current.Map.IsEnabled || !Configuration.Current.Map.shareMapProgression) { return; } ZNetPeer peer = __instance.GetPeer(rpc); if (peer == null) { return; } Vector3 refPos = peer.m_refPos; int num = default(int); int num2 = default(int); Minimap.instance.WorldToPixel(refPos, ref num, ref num2); int num3 = (int)Mathf.Ceil(Mathf.Min(Configuration.Current.Map.exploreRadius, 10000f) / Minimap.instance.m_pixelSize); for (int i = num2 - num3; i <= num2 + num3; i++) { for (int j = num - num3; j <= num + num3; j++) { if (j >= 0 && i >= 0 && j < Minimap.instance.m_textureSize && i < Minimap.instance.m_textureSize) { Vector2 val = new Vector2((float)(j - num), (float)(i - num2)); if ((double)((Vector2)(ref val)).magnitude <= (double)num3) { VPlusMapSync.ServerMapData[i * Minimap.instance.m_textureSize + j] = true; } } } } } } public static class ZPlayFabMatchmakingHelper { private const int OriginalMaxPlayers = 10; private const int PatchedMinPlayers = 1; private const int PatchedMaxPlayers = 32; private static bool alreadyWarned; public static bool isMaxPlayersDefault { get { ServerConfiguration server = Configuration.Current.Server; if (server.IsEnabled) { return server.maxPlayers == 10; } return true; } } public static int ConfiguredMaxPlayers(int originalMaxPlayers) { ServerConfiguration server = Configuration.Current.Server; int num = Helper.Clamp(server.maxPlayers, 1, 32); bool flag = false; if (!alreadyWarned && server.maxPlayers != num) { ValheimPlusPlugin.Logger.LogWarning((object)($"maxPlayers must be between {1} and {32}," + $" but was {server.maxPlayers}, using {num} instead.")); flag = true; } if (originalMaxPlayers == 10) { return num; } bool flag2 = num == 32; if (!alreadyWarned && flag2) { ValheimPlusPlugin.Logger.LogWarning((object)($"Couldn't set maxPlayers to {32} because the dedicated server (this machine)" + $" takes up a slot. This server will support {31} players instead.")); flag = true; } if (!flag2) { num++; } alreadyWarned |= flag; return num; } } [HarmonyPatch(typeof(ZPlayFabMatchmaking), "CreateLobby")] public static class ZPlayFabMatchmaking_CreateLobby_Transpiler { private static readonly FieldInfo Field_CreateLobbyRequest_MaxPlayers = AccessTools.Field(typeof(CreateLobbyRequest), "MaxPlayers"); [HarmonyTranspiler] [UsedImplicitly] public static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown if (ZPlayFabMatchmakingHelper.isMaxPlayersDefault) { return instructions; } List list = instructions.ToList(); try { CodeMatcher val = new CodeMatcher((IEnumerable)list, generator); int num = ZPlayFabMatchmakingHelper.ConfiguredMaxPlayers((sbyte)val.MatchStartForward((CodeMatch[])(object)new CodeMatch[2] { new CodeMatch((OpCode?)OpCodes.Ldc_I4_S, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Stfld, (object)Field_CreateLobbyRequest_MaxPlayers, (string)null) }).ThrowIfNotMatch("No match for code that sets MaxPlayers.", Array.Empty()).Operand); return val.SetOperandAndAdvance((object)num).InstructionEnumeration(); } catch (Exception exception) { PatchLog.Failed("ZPlayFabMatchmaking_CreateLobby_Transpiler", "`Server.maxPlayers` will not work for the lobby.", exception); return list; } } } [HarmonyPatch(typeof(ZPlayFabMatchmaking), "CreateAndJoinNetwork")] public static class ZPlayFabMatchmaking_CreateAndJoinNetwork_Transpiler { private static readonly MethodInfo PropertySetter_PlayFabNetworkConfiguration_MaxPlayerCount = AccessTools.PropertySetter(typeof(PlayFabNetworkConfiguration), "MaxPlayerCount"); [HarmonyTranspiler] [UsedImplicitly] public static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown if (ZPlayFabMatchmakingHelper.isMaxPlayersDefault) { return instructions; } List list = instructions.ToList(); try { CodeMatcher val = new CodeMatcher((IEnumerable)list, generator); int num = ZPlayFabMatchmakingHelper.ConfiguredMaxPlayers((sbyte)val.MatchStartForward((CodeMatch[])(object)new CodeMatch[2] { new CodeMatch((OpCode?)OpCodes.Ldc_I4_S, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Callvirt, (object)PropertySetter_PlayFabNetworkConfiguration_MaxPlayerCount, (string)null) }).ThrowIfNotMatch("No match for code that sets MaxPlayerCount.", Array.Empty()).Operand); return val.SetOperandAndAdvance((object)num).InstructionEnumeration(); } catch (Exception exception) { PatchLog.Failed("ZPlayFabMatchmaking_CreateAndJoinNetwork_Transpiler", "`Server.maxPlayers` will not work for the network.", exception); return list; } } } } namespace ValheimPlus.FirstPerson { [HarmonyPatch] public static class VPlusFirstPerson { [StructLayout(LayoutKind.Sequential, Size = 1)] public struct DynamicPerson { public static bool isFirstPerson = false; public static Vector3 noVPFP_3rdOffset = Vector3.zero; public static Vector3 noVPFP_fpsOffset = Vector3.zero; } [StructLayout(LayoutKind.Sequential, Size = 1)] public struct CameraConstants { public static float zoomSens = 10f; public static float minDistance = 1f; public static float maxDistance = 8f; public static float nearClipPlaneMax = 0.02f; public static float nearClipPlaneMin = 0.01f; } [HarmonyPatch(typeof(Character), "SetVisible")] public static class Character_SetVisible_Patch { private static bool Prefix(ref Character __instance, bool visible) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (Configuration.Current.FirstPerson.IsEnabled) { if ((Object)(object)__instance.m_lodGroup == (Object)null) { return false; } if (__instance.m_lodVisible == visible) { return false; } if (__instance.IsPlayer() && !visible) { return false; } __instance.m_lodVisible = visible; if (__instance.m_lodVisible) { __instance.m_lodGroup.localReferencePoint = __instance.m_originalLocalRef; return false; } __instance.m_lodGroup.localReferencePoint = new Vector3(999999f, 999999f, 999999f); return false; } return true; } } [HarmonyPatch(typeof(Player), "TestGhostClipping")] public static class Player_TestGhostClipping_Patch { private static bool Prefix() { if (Configuration.Current.FirstPerson.IsEnabled) { return false; } return true; } } [HarmonyPatch(typeof(GameCamera), "Awake")] public static class GameCamera_Awake_Patch { private static void Postfix(ref GameCamera __instance) { if (Configuration.Current.FirstPerson.IsEnabled) { CameraConstants.zoomSens = __instance.m_zoomSens; CameraConstants.minDistance = __instance.m_minDistance; CameraConstants.maxDistance = __instance.m_maxDistance; } } } [HarmonyPatch(typeof(GameCamera), "UpdateCamera")] public static class GameCamera_Update_Patch { private static void SetupFP(ref GameCamera __instance, ref Player localPlayer) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) DynamicPerson.noVPFP_3rdOffset = __instance.m_3rdOffset; DynamicPerson.noVPFP_fpsOffset = __instance.m_fpsOffset; __instance.m_3rdOffset = Vector3.zero; __instance.m_fpsOffset = Vector3.zero; __instance.m_minDistance = 0f; __instance.m_maxDistance = 0f; __instance.m_zoomSens = 0f; __instance.m_nearClipPlaneMax = CameraConstants.nearClipPlaneMax; __instance.m_nearClipPlaneMin = CameraConstants.nearClipPlaneMin; __instance.m_fov = Configuration.Current.FirstPerson.defaultFOV; ((Character)localPlayer).m_head.localScale = Vector3.zero; ((Character)localPlayer).m_eye.localScale = Vector3.zero; } private static void Postfix(ref GameCamera __instance, float dt) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) if (!Configuration.Current.FirstPerson.IsEnabled) { return; } if (__instance.m_freeFly) { __instance.UpdateFreeFly(dt); __instance.UpdateCameraShake(dt); return; } Player localPlayer = Player.m_localPlayer; if (Input.GetKeyDown(Configuration.Current.FirstPerson.hotkey)) { DynamicPerson.isFirstPerson = !DynamicPerson.isFirstPerson; if (DynamicPerson.isFirstPerson) { SetupFP(ref __instance, ref localPlayer); } else { __instance.m_3rdOffset = DynamicPerson.noVPFP_3rdOffset; __instance.m_fpsOffset = DynamicPerson.noVPFP_fpsOffset; __instance.m_minDistance = CameraConstants.minDistance; __instance.m_maxDistance = CameraConstants.maxDistance; __instance.m_zoomSens = CameraConstants.zoomSens; __instance.m_fov = 65f; ((Character)localPlayer).m_head.localScale = Vector3.one; ((Character)localPlayer).m_eye.localScale = Vector3.one; } } __instance.m_camera.fieldOfView = __instance.m_fov; __instance.m_skyCamera.fieldOfView = __instance.m_fov; if (!Object.op_Implicit((Object)(object)localPlayer)) { return; } if ((!Object.op_Implicit((Object)(object)Chat.instance) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !InventoryGui.IsVisible() && !StoreGui.IsVisible() && !Menu.IsVisible() && !Minimap.IsOpen() && !((Character)localPlayer).InCutscene() && !((Character)localPlayer).InPlaceMode()) { if (DynamicPerson.isFirstPerson) { if (Input.GetKeyDown(Configuration.Current.FirstPerson.raiseFOVHotkey)) { GameCamera obj = __instance; obj.m_fov += 1f; ((Terminal)Console.instance).AddString($"Changed fov to: {__instance.m_fov}"); } else if (Input.GetKeyDown(Configuration.Current.FirstPerson.lowerFOVHotkey)) { GameCamera obj2 = __instance; obj2.m_fov -= 1f; ((Terminal)Console.instance).AddString($"Changed fov to: {__instance.m_fov}"); } } else { _ = __instance.m_minDistance; float axis = Input.GetAxis("Mouse ScrollWheel"); GameCamera obj3 = __instance; obj3.m_distance -= axis * __instance.m_zoomSens; float num = (((Object)(object)localPlayer.GetControlledShip() != (Object)null) ? __instance.m_maxDistanceBoat : __instance.m_maxDistance); __instance.m_distance = Mathf.Clamp(__instance.m_distance, 0f, num); } } if (((Character)localPlayer).IsDead() && Object.op_Implicit((Object)(object)localPlayer.GetRagdoll())) { ((Component)__instance).transform.LookAt(localPlayer.GetRagdoll().GetAverageBodyPosition()); } else if (DynamicPerson.isFirstPerson) { ((Component)__instance).transform.position = ((Character)localPlayer).m_head.position + new Vector3(0f, 0.2f, 0f); } else { Vector3 position = default(Vector3); Quaternion rotation = default(Quaternion); __instance.GetCameraPosition(dt, ref position, ref rotation); ((Component)__instance).transform.position = position; ((Component)__instance).transform.rotation = rotation; } __instance.UpdateCameraShake(dt); } } static VPlusFirstPerson() { } } } namespace ValheimPlus.Configurations { public abstract class BaseConfig { private readonly ConfigurationManagerAttributes attributes = new ConfigurationManagerAttributes(); private readonly ConfigurationManagerAttributes enabledAttributes = new ConfigurationManagerAttributes { Order = int.MaxValue }; private readonly List syncRegistrations = new List(); private string sectionName; private ConfigEntry enabledEntry; public bool IsEnabled => enabledEntry?.Value ?? false; protected virtual bool ClientSide => false; public abstract void Bind(ConfigFile config); protected void BindEnabled(ConfigFile config, string section, bool defaultValue, string description) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown sectionName = section; enabledEntry = config.Bind(section, "enabled", defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { enabledAttributes })); if (!ClientSide) { syncRegistrations.Add(delegate { ConfigSyncGlue.Register(enabledEntry, synchronized: true); }); } } protected ConfigEntry Bind(ConfigFile config, string section, string key, T defaultValue, string description) { return Bind(config, section, key, defaultValue, description, local: false, null); } protected ConfigEntry Bind(ConfigFile config, string section, string key, T defaultValue, T min, T max, string description) where T : IComparable { return Bind(config, section, key, defaultValue, description, local: false, (AcceptableValueBase)(object)new AcceptableValueRange(min, max)); } protected ConfigEntry BindLocal(ConfigFile config, string section, string key, T defaultValue, string description) { return Bind(config, section, key, defaultValue, description, local: true, null); } private ConfigEntry Bind(ConfigFile config, string section, string key, T defaultValue, string description, bool local, AcceptableValueBase range) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown sectionName = section; ConfigEntry entry = config.Bind(section, key, defaultValue, new ConfigDescription(description, range, new object[1] { attributes })); if (!local && !ClientSide && typeof(T) != typeof(KeyCode)) { syncRegistrations.Add(delegate { ConfigSyncGlue.Register(entry, synchronized: true); }); } return entry; } internal int RegisterForServerSync() { foreach (Action syncRegistration in syncRegistrations) { syncRegistration(); } return syncRegistrations.Count; } internal void SetEditable(bool editable, string lockNote) { attributes.ReadOnly = !editable; enabledAttributes.ReadOnly = !editable; attributes.Category = (editable ? null : (sectionName + " (" + lockNote + ")")); enabledAttributes.Category = attributes.Category; } } public abstract class ClientConfig : BaseConfig { protected override bool ClientSide => true; } public static class BepInExConfig { private enum LegacyMode { None, Migrate, Override } private const string RetiredSuffix = ".migrated"; private static readonly List Sections = new List(); private static readonly Dictionary AppliedValues = new Dictionary(); private static bool serverSyncRegistered; private static bool syncedOnce; public static ConfigFile Config { get; private set; } public static void Load(ConfigFile config) { Config = config; LegacyMode legacyMode = DetectLegacyMode(config); IniData val = ((legacyMode == LegacyMode.None) ? null : ReadLegacyIni(legacyMode)); if (val == null) { legacyMode = LegacyMode.None; } config.SaveOnConfigSet = false; try { Configuration.Current = BindSections(config); if (val != null) { ImportLegacyValues(config, val); } config.Save(); } finally { config.SaveOnConfigSet = true; } LogChangedSettings("differ from their default"); switch (legacyMode) { case LegacyMode.Migrate: RetireLegacyIni(config); break; case LegacyMode.Override: WarnLegacyOverride(config); break; } SetUpServerSync(); ConfigurationManagerWatcher.Install(config, Sections, legacyMode == LegacyMode.Override); } private static void SetUpServerSync() { ConfigSyncGlue.Initialize("org.bepinex.plugins.valheim_plus", "Valheim Plus", "0.10.1.0", "0.10.1.0"); ConfigSyncGlue.SourceOfTruthChanged += delegate(bool isSourceOfTruth) { if (isSourceOfTruth) { ReapplyPatches("Config source changed"); } }; ConfigSyncGlue.ConfigApplied += delegate { if (syncedOnce) { ValheimPlusPlugin.Logger.LogInfo((object)"Config arrived while in a world, so patches were left alone."); } else { syncedOnce = true; ReapplyPatches("Received config from the server"); } }; ConfigSyncGlue.RegisterLocking((ConfigEntry)(object)Config["Server", "serverSyncsConfig"]); } internal static void ReapplyPatches(string reason) { ValheimPlusPlugin.Logger.LogInfo((object)(reason + ", re-applying patches.")); LogChangedSettings("changed since patches were last applied"); ValheimPlusPlugin.UnpatchSelf(); ValheimPlusPlugin.PatchAll(); ConfigurationManagerWatcher.MarkClean(); } public static void RegisterForServerSync() { syncedOnce = ZNet.m_isServer; if (serverSyncRegistered) { return; } if (ZNet.m_isServer && !Configuration.Current.Server.serverSyncsConfig) { ValheimPlusPlugin.Logger.LogWarning((object)"serverSyncsConfig is off, so this server will not push its config to clients."); return; } serverSyncRegistered = true; int num = 0; foreach (BaseConfig section in Sections) { num += section.RegisterForServerSync(); } ValheimPlusPlugin.Logger.LogInfo((object)$"Registered {num} settings for server sync."); } private static LegacyMode DetectLegacyMode(ConfigFile config) { if (!File.Exists(ConfigurationExtra.ConfigIniPath)) { return LegacyMode.None; } if (!File.Exists(config.ConfigFilePath)) { return LegacyMode.Migrate; } return LegacyMode.Override; } private static IniData ReadLegacyIni(LegacyMode mode) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) try { if (mode == LegacyMode.Migrate) { ValheimPlusPlugin.Logger.LogInfo((object)("Found a legacy config at '" + ConfigurationExtra.ConfigIniPath + "', importing its values.")); } return new FileIniDataParser().ReadFile(ConfigurationExtra.ConfigIniPath); } catch (Exception arg) { ValheimPlusPlugin.Logger.LogError((object)$"Could not read the legacy config, so defaults will be used instead: {arg}"); return null; } } private static void LogChangedSettings(string description) { List list = new List(); foreach (ConfigDefinition key in Config.Keys) { ConfigEntryBase val = Config[key]; object value; object obj = (AppliedValues.TryGetValue(key, out value) ? value : val.DefaultValue); AppliedValues[key] = val.BoxedValue; if (!object.Equals(val.BoxedValue, obj)) { list.Add($" [{key.Section}] {key.Key}: {obj} -> {val.BoxedValue}"); } } ValheimPlusPlugin.Logger.LogInfo((object)$"{list.Count} settings {description}:"); foreach (string item in list) { ValheimPlusPlugin.Logger.LogInfo((object)item); } } private static Configuration BindSections(ConfigFile config) { Configuration configuration = new Configuration(); Sections.Clear(); PropertyInfo[] properties = typeof(Configuration).GetProperties(); foreach (PropertyInfo propertyInfo in properties) { if (typeof(BaseConfig).IsAssignableFrom(propertyInfo.PropertyType)) { BaseConfig baseConfig = (BaseConfig)Activator.CreateInstance(propertyInfo.PropertyType); baseConfig.Bind(config); propertyInfo.SetValue(configuration, baseConfig, null); Sections.Add(baseConfig); } } return configuration; } private static void ImportLegacyValues(ConfigFile config, IniData legacy) { int num = 0; List list = new List(); foreach (ConfigDefinition item in config.Keys.ToList()) { KeyDataCollection val = legacy[item.Section]; if (val != null && val.ContainsKey(item.Key)) { ConfigEntryBase val2 = config[item]; object obj = ConvertIniValue(val, item.Key, val2.SettingType, val2.DefaultValue); if (obj == null) { list.Add(item.Section + "." + item.Key); continue; } val2.BoxedValue = obj; num++; } } ValheimPlusPlugin.Logger.LogInfo((object)$"Imported {num} settings from the legacy config."); if (list.Count > 0) { ValheimPlusPlugin.Logger.LogWarning((object)("These settings kept their default because their type is not understood: " + string.Join(", ", list.ToArray()))); } } private static object ConvertIniValue(KeyDataCollection data, string key, Type type, object fallback) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) if (type == typeof(bool)) { return data.GetBool(key); } if (type == typeof(int)) { return data.GetInt(key, (int)fallback); } if (type == typeof(float)) { return data.GetFloat(key, (float)fallback); } if (type == typeof(KeyCode)) { return data.GetKeyCode(key, (KeyCode)fallback); } if (type == typeof(string)) { return data[key]; } if (type.IsEnum) { if (!type.IsDefined(typeof(FlagsAttribute), inherit: false)) { return data.GetEnumValue(key, fallback); } return data.GetFlags(key, fallback); } return null; } private static void WarnLegacyOverride(ConfigFile config) { ValheimPlusPlugin.Logger.LogWarning((object)("'" + ConfigurationExtra.ConfigIniPath + "' is present, so its values are overriding your settings. This file is deprecated: a future release will read it only when 'useLegacyConfigFile' is enabled, and a later release will stop reading it entirely. The result has been written to '" + config.ConfigFilePath + "' - switch to generating that file and delete the old one. Settings cannot be edited in-game while it exists.")); } private static void RetireLegacyIni(ConfigFile config) { string text = ConfigurationExtra.ConfigIniPath + ".migrated"; try { File.Move(ConfigurationExtra.ConfigIniPath, text); ValheimPlusPlugin.Logger.LogWarning((object)("Settings now live in '" + config.ConfigFilePath + "'. The old config was kept as '" + text + "' and is no longer read.")); } catch (Exception ex) { ValheimPlusPlugin.Logger.LogWarning((object)("Settings now live in '" + config.ConfigFilePath + "', but '" + ConfigurationExtra.ConfigIniPath + "' could not be renamed and is now unused: " + ex.Message)); } } } internal static class ConfigSyncGlue { private const string HandleRpcName = "HandleConfigSyncRPC"; private static readonly Harmony Harmony = new Harmony("mod.valheim_plus.serversync"); private static ConfigSync configSync; public static event Action SourceOfTruthChanged; public static event Action ConfigApplied; public static void Initialize(string guid, string displayName, string version, string minimumVersion) { //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_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown configSync = new ConfigSync(guid) { DisplayName = displayName, CurrentVersion = version, MinimumRequiredVersion = minimumVersion }; configSync.SourceOfTruthChanged += delegate(bool value) { ConfigSyncGlue.SourceOfTruthChanged?.Invoke(value); }; HookConfigApplied(); } private static void HookConfigApplied() { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ConfigSync), "HandleConfigSyncRPC", (Type[])null, (Type[])null) ?? throw new MissingMethodException("ConfigSync", "HandleConfigSyncRPC"); Harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ConfigSyncGlue), "ConfigAppliedPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } catch (Exception exception) { PatchLog.Failed("HookConfigApplied", "A server's settings will not take effect until the game is restarted.", exception); } } [UsedImplicitly] private static void ConfigAppliedPostfix(bool __result) { if (__result) { ConfigSyncGlue.ConfigApplied?.Invoke(); } } public static void SetModRequired(bool required) { if (configSync != null) { configSync.ModRequired = required; } } public static void Register(ConfigEntry entry, bool synchronized) { if (configSync != null) { ((OwnConfigEntryBase)configSync.AddConfigEntry(entry)).SynchronizedConfig = synchronized; } } public static void RegisterLocking(ConfigEntry entry) { if (configSync != null) { configSync.AddLockingConfigEntry(entry); } } } public class Configuration { public static Configuration Current { get; set; } public AdvancedBuildingModeConfiguration AdvancedBuildingMode { get; set; } public AdvancedEditingModeConfiguration AdvancedEditingMode { get; set; } public BedConfiguration Bed { get; set; } public BeehiveConfiguration Beehive { get; set; } public BuildingConfiguration Building { get; set; } public InventoryConfiguration Inventory { get; set; } public ItemsConfiguration Items { get; set; } public FermenterConfiguration Fermenter { get; set; } public FireSourceConfiguration FireSource { get; set; } public FoodConfiguration Food { get; set; } public SmelterConfiguration Smelter { get; set; } public FurnaceConfiguration Furnace { get; set; } public HotkeyConfiguration Hotkeys { get; set; } public KilnConfiguration Kiln { get; set; } public WindmillConfiguration Windmill { get; set; } public SpinningWheelConfiguration SpinningWheel { get; set; } public EitrRefineryConfiguration EitrRefinery { get; set; } public MapConfiguration Map { get; set; } public PlayerConfiguration Player { get; set; } public ServerConfiguration Server { get; set; } public StaminaConfiguration Stamina { get; set; } public StaminaUsageConfiguration StaminaUsage { get; set; } public EitrUsageConfiguration EitrUsage { get; set; } public HealthUsageConfiguration HealthUsage { get; set; } public WorkbenchConfiguration Workbench { get; set; } public TimeConfiguration Time { get; set; } public WardConfiguration Ward { get; set; } public StructuralIntegrityConfiguration StructuralIntegrity { get; set; } public TameableConfiguration Tameable { get; set; } public ProcreationConfiguration Procreation { get; set; } public HudConfiguration Hud { get; set; } public ExperienceConfiguration Experience { get; set; } public CameraConfiguration Camera { get; set; } public GameConfiguration Game { get; set; } public WagonConfiguration Wagon { get; set; } public GatherConfiguration Gathering { get; set; } public PickableConfiguration Pickable { get; set; } public DurabilityConfiguration Durability { get; set; } public ArmorConfiguration Armor { get; set; } public FreePlacementRotationConfiguration FreePlacementRotation { get; set; } public ShieldConfiguration Shields { get; set; } public FirstPersonConfiguration FirstPerson { get; internal set; } public GridAlignmentConfiguration GridAlignment { get; set; } public CraftFromChestConfiguration CraftFromChest { get; set; } public PlayerProjectileConfiguration PlayerProjectile { get; set; } public MonsterProjectileConfiguration MonsterProjectile { get; set; } public GameClockConfiguration GameClock { get; set; } public BrightnessConfiguration Brightness { get; set; } public ChatConfiguration Chat { get; set; } public LootDropConfiguration LootDrop { get; set; } public WispSpawnerConfiguration WispSpawner { get; set; } public DemisterConfiguration Demister { get; set; } public HotTubConfiguration HotTub { get; set; } public ShieldGeneratorConfiguration ShieldGenerator { get; set; } public TurretConfiguration Turret { get; set; } public AutoStackConfiguration AutoStack { get; set; } public OvenConfiguration Oven { get; set; } public SapCollectorConfiguration SapCollector { get; set; } public ShipConfiguration Ship { get; set; } public EggConfiguration Egg { get; set; } } public class ConfigurationExtra { public static string ConfigIniPath; static ConfigurationExtra() { string? directoryName = Path.GetDirectoryName(Paths.BepInExConfigPath); char directorySeparatorChar = Path.DirectorySeparatorChar; ConfigIniPath = directoryName + directorySeparatorChar + "valheim_plus.cfg"; } } public static class IniDataExtensions { public static float GetFloat(this KeyDataCollection data, string key, float defaultVal) { if (float.TryParse(data[key], NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat, out var result)) { return result; } ValheimPlusPlugin.Logger.LogWarning((object)$" [Float] Could not read {key}, using default value of {defaultVal}"); return defaultVal; } public static bool GetBool(this KeyDataCollection data, string key) { return new string[5] { "y", "yes", "true", "1", "enabled" }.Contains((data[key] ?? "").ToLower()); } public static int GetInt(this KeyDataCollection data, string key, int defaultVal) { if (int.TryParse(data[key], NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat, out var result)) { return result; } ValheimPlusPlugin.Logger.LogWarning((object)$" [Int] Could not read {key}, using default value of {defaultVal}"); return defaultVal; } public static object GetEnumValue(this KeyDataCollection data, string key, object defaultVal) { Type type = defaultVal.GetType(); try { return Enum.Parse(type, data[key], ignoreCase: true); } catch { ValheimPlusPlugin.Logger.LogWarning((object)$" [{type}] Could not read {key}, using default value of {defaultVal}"); return defaultVal; } } public static object GetFlags(this KeyDataCollection data, string key, object defaultVal) { Type type = defaultVal.GetType(); List list = new List(); List list2 = data[key].Split(new char[1] { ',' }).ToList(); list2.ForEach(delegate(string x) { x.Trim(); }); foreach (string item2 in list2) { try { object item = Enum.Parse(type, item2, ignoreCase: true); list.Add(item); } catch { ValheimPlusPlugin.Logger.LogWarning((object)(" [" + type.Name + "] Unrecognized value `" + item2 + "` in " + key)); } } int value = list.Aggregate(0, (int num, object flag) => num | (int)flag); try { return Enum.ToObject(type, value); } catch { ValheimPlusPlugin.Logger.LogWarning((object)$" [{type}] Could not read {key}, using default value of {defaultVal}"); return defaultVal; } } public static KeyCode GetKeyCode(this KeyDataCollection data, string key, KeyCode defaultVal) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (Enum.TryParse(data[key].Trim(), out KeyCode result)) { return result; } ValheimPlusPlugin.Logger.LogWarning((object)$" [KeyCode] Could not read {key}, using default value of {defaultVal}"); return defaultVal; } } internal static class ConfigurationManagerWatcher { internal const string ConfigurationManagerGuid = "com.bepis.bepinex.configurationmanager"; internal const string ShudnalConfigurationManagerGuid = "_shudnal.ConfigurationManager"; private static readonly List Sections = new List(); private static object plugin; private static PropertyInfo displayingWindow; private static MethodInfo buildSettingList; private static bool atMainMenu = true; private static bool legacyOverride; private static bool readyForEdit = true; private static bool windowShown; private static bool dirty; public static bool ReadyForEdit => readyForEdit; public static bool BlocksGameInput { get { if (windowShown) { return !atMainMenu; } return false; } } public static void Install(ConfigFile config, List sections, bool legacyOverrideActive) { Sections.Clear(); Sections.AddRange(sections); legacyOverride = legacyOverrideActive; config.SettingChanged += delegate { dirty = true; }; ApplyReadyForEdit(force: true); PluginInfo val = FindPlugin("com.bepis.bepinex.configurationmanager") ?? FindPlugin("_shudnal.ConfigurationManager"); if (val == null) { ValheimPlusPlugin.Logger.LogInfo((object)"Configuration Manager is not installed. Settings can still be changed by editing the config file, which takes effect on the next launch."); return; } try { plugin = val.Instance; displayingWindow = plugin.GetType().GetProperty("DisplayingWindow"); buildSettingList = plugin.GetType().GetMethod("BuildSettingList", Type.EmptyTypes); EventInfo eventInfo = plugin.GetType().GetEvent("DisplayingWindowChanged"); if (displayingWindow == null || eventInfo == null) { ValheimPlusPlugin.Logger.LogWarning((object)"Configuration Manager is installed but does not look the way we expect, so changed settings will only apply on the next launch."); return; } Action action = OnDisplayingWindowChanged; eventInfo.AddEventHandler(plugin, Delegate.CreateDelegate(eventInfo.EventHandlerType, action.Target, action.Method)); ValheimPlusPlugin.Logger.LogInfo((object)(readyForEdit ? "Configuration Manager found, settings are editable at the main menu." : "Configuration Manager found, but the legacy config file is overriding settings, so they are read-only.")); } catch (Exception ex) { ValheimPlusPlugin.Logger.LogWarning((object)("Could not hook into Configuration Manager: " + ex.Message)); } } private static PluginInfo FindPlugin(string guid) { if (!Chainloader.PluginInfos.TryGetValue(guid, out var value) || !((Object)(object)((value != null) ? value.Instance : null) != (Object)null)) { return null; } return value; } public static void SetInWorld(bool inWorld) { atMainMenu = !inWorld; ApplyReadyForEdit(force: false); } public static void MarkClean() { dirty = false; } private static void ApplyReadyForEdit(bool force) { bool flag = atMainMenu && !legacyOverride; if (!force && flag == readyForEdit) { return; } readyForEdit = flag; string lockNote = (legacyOverride ? "read-only, legacy cfg" : "read-only in a world"); foreach (BaseConfig section in Sections) { section.SetEditable(flag, lockNote); } if (!force) { RefreshOpenWindow(); } } private static void RefreshOpenWindow() { if (plugin == null || displayingWindow == null) { return; } try { if ((bool)displayingWindow.GetValue(plugin, null)) { if (buildSettingList != null) { buildSettingList.Invoke(plugin, null); } else { displayingWindow.SetValue(plugin, false, null); } } } catch (Exception ex) { ValheimPlusPlugin.Logger.LogWarning((object)("Could not refresh the Configuration Manager window: " + ex.Message)); } } private static void OnDisplayingWindowChanged(object sender, object args) { windowShown = (bool)displayingWindow.GetValue(plugin, null); if (!windowShown && dirty) { if (!readyForEdit) { ValheimPlusPlugin.Logger.LogInfo((object)"Settings changed while they are read-only, so patches were left alone."); } else { BepInExConfig.ReapplyPatches("Configuration changed"); } } } } } namespace ValheimPlus.Configurations.Sections { public class AdvancedBuildingModeConfiguration : BaseConfig { private const string Section = "AdvancedBuildingMode"; private ConfigEntry enterAdvancedBuildingModeEntry; private ConfigEntry exitAdvancedBuildingModeEntry; private ConfigEntry copyObjectRotationEntry; private ConfigEntry pasteObjectRotationEntry; private ConfigEntry increaseScrollSpeedEntry; private ConfigEntry decreaseScrollSpeedEntry; public KeyCode enterAdvancedBuildingMode => enterAdvancedBuildingModeEntry.Value; public KeyCode exitAdvancedBuildingMode => exitAdvancedBuildingModeEntry.Value; public KeyCode copyObjectRotation => copyObjectRotationEntry.Value; public KeyCode pasteObjectRotation => pasteObjectRotationEntry.Value; public KeyCode increaseScrollSpeed => increaseScrollSpeedEntry.Value; public KeyCode decreaseScrollSpeed => decreaseScrollSpeedEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "AdvancedBuildingMode", defaultValue: false, "https://docs.unity3d.com/ScriptReference/KeyCode.html <- a list of keycodes\nChange false to true to enable this section, if you set this to false the mode will not be accessible."); enterAdvancedBuildingModeEntry = Bind(config, "AdvancedBuildingMode", "enterAdvancedBuildingMode", (KeyCode)282, "Enter the advanced building mode with this key when building"); exitAdvancedBuildingModeEntry = Bind(config, "AdvancedBuildingMode", "exitAdvancedBuildingMode", (KeyCode)284, "Exit the advanced building mode with this key when building"); copyObjectRotationEntry = Bind(config, "AdvancedBuildingMode", "copyObjectRotation", (KeyCode)263, "Copy the object rotation of the currently selected object in ABM"); pasteObjectRotationEntry = Bind(config, "AdvancedBuildingMode", "pasteObjectRotation", (KeyCode)264, "Apply the copied object rotation to the currently selected object in ABM"); increaseScrollSpeedEntry = Bind(config, "AdvancedBuildingMode", "increaseScrollSpeed", (KeyCode)270, "Increases the amount an object rotates and moves. Holding Shift will increase in increments of 10 instead of 1."); decreaseScrollSpeedEntry = Bind(config, "AdvancedBuildingMode", "decreaseScrollSpeed", (KeyCode)269, "Decreases the amount an object rotates and moves. Holding Shift will decrease in increments of 10 instead of 1."); } } public class AdvancedEditingModeConfiguration : BaseConfig { private const string Section = "AdvancedEditingMode"; private ConfigEntry enterAdvancedEditingModeEntry; private ConfigEntry resetAdvancedEditingModeEntry; private ConfigEntry abortAndExitAdvancedEditingModeEntry; private ConfigEntry confirmPlacementOfAdvancedEditingModeEntry; private ConfigEntry copyObjectRotationEntry; private ConfigEntry pasteObjectRotationEntry; private ConfigEntry increaseScrollSpeedEntry; private ConfigEntry decreaseScrollSpeedEntry; public KeyCode enterAdvancedEditingMode => enterAdvancedEditingModeEntry.Value; public KeyCode resetAdvancedEditingMode => resetAdvancedEditingModeEntry.Value; public KeyCode abortAndExitAdvancedEditingMode => abortAndExitAdvancedEditingModeEntry.Value; public KeyCode confirmPlacementOfAdvancedEditingMode => confirmPlacementOfAdvancedEditingModeEntry.Value; public KeyCode copyObjectRotation => copyObjectRotationEntry.Value; public KeyCode pasteObjectRotation => pasteObjectRotationEntry.Value; public KeyCode increaseScrollSpeed => increaseScrollSpeedEntry.Value; public KeyCode decreaseScrollSpeed => decreaseScrollSpeedEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "AdvancedEditingMode", defaultValue: false, "https://docs.unity3d.com/ScriptReference/KeyCode.html <- a list of keycodes\nChange false to true to enable this section, if you set this to false the mode will not be accessible."); enterAdvancedEditingModeEntry = Bind(config, "AdvancedEditingMode", "enterAdvancedEditingMode", (KeyCode)256, "Enter the advanced editing mode with this key"); resetAdvancedEditingModeEntry = Bind(config, "AdvancedEditingMode", "resetAdvancedEditingMode", (KeyCode)288, "Reset the object to its original position and rotation"); abortAndExitAdvancedEditingModeEntry = Bind(config, "AdvancedEditingMode", "abortAndExitAdvancedEditingMode", (KeyCode)289, "Exit the advanced editing mode with this key and reset the object"); confirmPlacementOfAdvancedEditingModeEntry = Bind(config, "AdvancedEditingMode", "confirmPlacementOfAdvancedEditingMode", (KeyCode)271, "Confirm the placement of the object and place it"); copyObjectRotationEntry = Bind(config, "AdvancedEditingMode", "copyObjectRotation", (KeyCode)263, "Copy the object rotation of the currently selected object in AEM"); pasteObjectRotationEntry = Bind(config, "AdvancedEditingMode", "pasteObjectRotation", (KeyCode)264, "Apply the copied object rotation to the currently selected object in AEM"); increaseScrollSpeedEntry = Bind(config, "AdvancedEditingMode", "increaseScrollSpeed", (KeyCode)270, "Increases the amount an object rotates and moves. Holding Shift will increase in increments of 10 instead of 1."); decreaseScrollSpeedEntry = Bind(config, "AdvancedEditingMode", "decreaseScrollSpeed", (KeyCode)269, "Decreases the amount an object rotates and moves. Holding Shift will decrease in increments of 10 instead of 1."); } } public class ArmorConfiguration : BaseConfig { private const string Section = "Armor"; private ConfigEntry helmetsEntry; private ConfigEntry chestsEntry; private ConfigEntry legsEntry; private ConfigEntry capesEntry; public float helmets => helmetsEntry.Value; public float chests => chestsEntry.Value; public float legs => legsEntry.Value; public float capes => capesEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Armor", defaultValue: false, "Change false to true to enable this section. This section contains modifiers.\nModifiers are increases and reduction in percent declared by 50, or -50."); helmetsEntry = Bind(config, "Armor", "helmets", 0f, "Each of these values increase or reduce the armor of the specific item type by %.\nThe value 50 will increase the armor from 14 to 21. The value -50 will reduce the armor from 14 to 7."); chestsEntry = Bind(config, "Armor", "chests", 0f, "Each of these values increase or reduce the armor of the specific item type by %.\nThe value 50 will increase the armor from 14 to 21. The value -50 will reduce the armor from 14 to 7."); legsEntry = Bind(config, "Armor", "legs", 0f, "Each of these values increase or reduce the armor of the specific item type by %.\nThe value 50 will increase the armor from 14 to 21. The value -50 will reduce the armor from 14 to 7."); capesEntry = Bind(config, "Armor", "capes", 0f, "Each of these values increase or reduce the armor of the specific item type by %.\nThe value 50 will increase the armor from 14 to 21. The value -50 will reduce the armor from 14 to 7."); } } public class AutoStackConfiguration : BaseConfig { private const string Section = "AutoStack"; private ConfigEntry autoStackAllRangeEntry; private ConfigEntry autoStackAllIgnorePrivateAreaCheckEntry; private ConfigEntry autoStackAllIgnoreEquipmentEntry; private ConfigEntry ignoreAmmoEntry; private ConfigEntry ignoreFoodEntry; private ConfigEntry ignoreMeadEntry; public float autoStackAllRange => autoStackAllRangeEntry.Value; public bool autoStackAllIgnorePrivateAreaCheck => autoStackAllIgnorePrivateAreaCheckEntry.Value; public bool autoStackAllIgnoreEquipment => autoStackAllIgnoreEquipmentEntry.Value; public bool ignoreAmmo => ignoreAmmoEntry.Value; public bool ignoreFood => ignoreFoodEntry.Value; public bool ignoreMead => ignoreMeadEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "AutoStack", defaultValue: false, "Set to true to automatically perform the \"Stack All\" action on all chests in range."); autoStackAllRangeEntry = Bind(config, "AutoStack", "autoStackAllRange", 10f, 1f, 50f, "Defines the range to search chests for the \"Stack All\" action."); autoStackAllIgnorePrivateAreaCheckEntry = Bind(config, "AutoStack", "autoStackAllIgnorePrivateAreaCheck", defaultValue: false, "This option prevents to \"Stack All\" into chests from warded areas if the player doesnt have access to it."); autoStackAllIgnoreEquipmentEntry = Bind(config, "AutoStack", "autoStackAllIgnoreEquipment", defaultValue: false, "Set to true to prevent equipable items to be stored automatically."); ignoreAmmoEntry = Bind(config, "AutoStack", "ignoreAmmo", defaultValue: false, "Set to true to prevent arrows and bolts to be stored automatically."); ignoreFoodEntry = Bind(config, "AutoStack", "ignoreFood", defaultValue: false, "Set to true to prevent food items to be stored automatically."); ignoreMeadEntry = Bind(config, "AutoStack", "ignoreMead", defaultValue: false, "Set to true to prevent mead to be stored automatically."); } } public class BedConfiguration : BaseConfig { private const string Section = "Bed"; private ConfigEntry sleepWithoutSpawnEntry; private ConfigEntry unclaimedBedsOnlyEntry; public bool sleepWithoutSpawn => sleepWithoutSpawnEntry.Value; public bool unclaimedBedsOnly => unclaimedBedsOnlyEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Bed", defaultValue: false, "Change false to true to enable this section"); sleepWithoutSpawnEntry = Bind(config, "Bed", "sleepWithoutSpawn", defaultValue: false, "Change false to true to enable sleeping without setting bed as spawn.\nWhen hovering over a bed you will be presented with a Hot-Key 'LShift+E'. This Hot-Key will allow for you to sleep on any bed without having to set a spawn-point."); unclaimedBedsOnlyEntry = Bind(config, "Bed", "unclaimedBedsOnly", defaultValue: false, "Change false to true to enable sleeping on only unclaimed beds without setting bed as spawn.\nWith this option enabled only beds that are not claimed by other players can be slept on without setting spawn-point using 'Shift+E'"); } } public class BeehiveConfiguration : BaseConfig { private const string Section = "Beehive"; private ConfigEntry honeyProductionSpeedEntry; private ConfigEntry maximumHoneyPerBeehiveEntry; private ConfigEntry autoDepositEntry; private ConfigEntry autoDepositRangeEntry; private ConfigEntry showDurationEntry; public float honeyProductionSpeed => honeyProductionSpeedEntry.Value; public int maximumHoneyPerBeehive => maximumHoneyPerBeehiveEntry.Value; public bool autoDeposit => autoDepositEntry.Value; public float autoDepositRange => autoDepositRangeEntry.Value; public bool showDuration => showDurationEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Beehive", defaultValue: false, "Change false to true to enable this section."); honeyProductionSpeedEntry = Bind(config, "Beehive", "honeyProductionSpeed", 1200f, "Configure the speed at which the bees produce honey in seconds, 1200 seconds are 24 ingame hours."); maximumHoneyPerBeehiveEntry = Bind(config, "Beehive", "maximumHoneyPerBeehive", 4, "Configure the maximum amount of honey in beehives."); autoDepositEntry = Bind(config, "Beehive", "autoDeposit", defaultValue: false, "Instead of dropping the items, they will be placed inside the nearest nearby chests."); autoDepositRangeEntry = Bind(config, "Beehive", "autoDepositRange", 10f, 1f, 50f, "The range of the chest detection for the auto deposit feature.\nMaximum is 50"); showDurationEntry = Bind(config, "Beehive", "showDuration", defaultValue: false, "Display the minutes and seconds until the beehive produces honey on crosshair hover."); } } public class BrightnessConfiguration : BaseConfig { private const string Section = "Brightness"; private ConfigEntry nightBrightnessMultiplierEntry; public float nightBrightnessMultiplier => nightBrightnessMultiplierEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Brightness", defaultValue: false, "Change false to true to enable this section."); nightBrightnessMultiplierEntry = Bind(config, "Brightness", "nightBrightnessMultiplier", 0f, "Changes how bright it looks at night. A value between 5 and 10 will result in nearly double in brightness at night."); } } public class BuildingConfiguration : BaseConfig { private const string Section = "Building"; private ConfigEntry noInvalidPlacementRestrictionEntry; private ConfigEntry noMysticalForcesPreventPlacementRestrictionEntry; private ConfigEntry noWeatherDamageEntry; private ConfigEntry maximumPlacementDistanceEntry; private ConfigEntry pieceComfortRadiusEntry; private ConfigEntry alwaysDropResourcesEntry; private ConfigEntry alwaysDropExcludedResourcesEntry; private ConfigEntry enableAreaRepairEntry; private ConfigEntry areaRepairRadiusEntry; public bool noInvalidPlacementRestriction => noInvalidPlacementRestrictionEntry.Value; public bool noMysticalForcesPreventPlacementRestriction => noMysticalForcesPreventPlacementRestrictionEntry.Value; public bool noWeatherDamage => noWeatherDamageEntry.Value; public float maximumPlacementDistance => maximumPlacementDistanceEntry.Value; public float pieceComfortRadius => pieceComfortRadiusEntry.Value; public bool alwaysDropResources => alwaysDropResourcesEntry.Value; public bool alwaysDropExcludedResources => alwaysDropExcludedResourcesEntry.Value; public bool enableAreaRepair => enableAreaRepairEntry.Value; public float areaRepairRadius => areaRepairRadiusEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Building", defaultValue: false, "Change false to true to enable this section."); noInvalidPlacementRestrictionEntry = Bind(config, "Building", "noInvalidPlacementRestriction", defaultValue: false, "Remove some of the Invalid placement messages, most notably provides the ability to place objects into other objects"); noMysticalForcesPreventPlacementRestrictionEntry = Bind(config, "Building", "noMysticalForcesPreventPlacementRestriction", defaultValue: false, "Removes the \"Mystical forces\" building prevention and allows destruction of build objects in those areas with the hammer."); noWeatherDamageEntry = Bind(config, "Building", "noWeatherDamage", defaultValue: false, "Removes the weather damage from rain and water erosion."); maximumPlacementDistanceEntry = Bind(config, "Building", "maximumPlacementDistance", 8f, "The maximum range in meters that you can place build objects at inside the hammer build mode."); pieceComfortRadiusEntry = Bind(config, "Building", "pieceComfortRadius", 10f, 1f, 300f, "The radius, in meters, in which a piece must be to contribute to the comfort level."); alwaysDropResourcesEntry = Bind(config, "Building", "alwaysDropResources", defaultValue: false, "When destroying a building piece, setting this to true will ensure it always drops full resources.\nWe recommend to enable this if you use this section."); alwaysDropExcludedResourcesEntry = Bind(config, "Building", "alwaysDropExcludedResources", defaultValue: false, "When destroying a building piece, setting this to true will ensure it always drops pieces that the devs have marked as \"do not drop\".\nWe recommend to enable this if you use this section."); enableAreaRepairEntry = Bind(config, "Building", "enableAreaRepair", defaultValue: false, "Setting this to true will cause repairing with the hammer to repair in a radius instead of a single piece."); areaRepairRadiusEntry = Bind(config, "Building", "areaRepairRadius", 7.5f, "Sets the area repair radius of enableAreaRepair. A value of 7.5 would mean your repair radius is 7.5 meters.\nRequires enableAreaRepair=true"); } } public class CameraConfiguration : BaseConfig { private const string Section = "Camera"; private ConfigEntry cameraMaximumZoomDistanceEntry; private ConfigEntry cameraBoatMaximumZoomDistanceEntry; private ConfigEntry cameraFOVEntry; public float cameraMaximumZoomDistance => cameraMaximumZoomDistanceEntry.Value; public float cameraBoatMaximumZoomDistance => cameraBoatMaximumZoomDistanceEntry.Value; public float cameraFOV => cameraFOVEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Camera", defaultValue: false, "Change false to true to enable this section."); cameraMaximumZoomDistanceEntry = Bind(config, "Camera", "cameraMaximumZoomDistance", 6f, "The maximum zoom distance to your character in-game.\nDefault is 6"); cameraBoatMaximumZoomDistanceEntry = Bind(config, "Camera", "cameraBoatMaximumZoomDistance", 6f, "The maximum zoom distance to your character when in a boat.\nDefault is 6"); cameraFOVEntry = BindLocal(config, "Camera", "cameraFOV", 65f, "The in-game camera FOV.\nDefault is 65"); } } public class ChatConfiguration : BaseConfig { private const string Section = "Chat"; private ConfigEntry shoutDistanceEntry; private ConfigEntry pingDistanceEntry; private ConfigEntry forcedCaseEntry; private ConfigEntry outOfRangeShoutsDisplayInChatWindowEntry; private ConfigEntry defaultWhisperDistanceEntry; private ConfigEntry defaultNormalDistanceEntry; private ConfigEntry defaultShoutDistanceEntry; public float shoutDistance => shoutDistanceEntry.Value; public float pingDistance => pingDistanceEntry.Value; public bool forcedCase => forcedCaseEntry.Value; public bool outOfRangeShoutsDisplayInChatWindow => outOfRangeShoutsDisplayInChatWindowEntry.Value; public float defaultWhisperDistance => defaultWhisperDistanceEntry.Value; public float defaultNormalDistance => defaultNormalDistanceEntry.Value; public float defaultShoutDistance => defaultShoutDistanceEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Chat", defaultValue: false, "Change false to true to enable this section."); shoutDistanceEntry = Bind(config, "Chat", "shoutDistance", 0f, "If the player is outside of this range in meters in comparison to the creator of the shout you will not see the message on the map or in the chat. If this is set to 0, its disabled."); pingDistanceEntry = Bind(config, "Chat", "pingDistance", 0f, "If the player is outside of this range in meters in comparison to the creator of the ping on the map you will not see the ping on the map. If this is set to 0, its disabled."); forcedCaseEntry = Bind(config, "Chat", "forcedCase", defaultValue: true, "Disable the forced upper and lower case conversions for in-game text messages of all types."); outOfRangeShoutsDisplayInChatWindowEntry = Bind(config, "Chat", "outOfRangeShoutsDisplayInChatWindow", defaultValue: true, "With this option enabled you will see the shout message in your chat window even if you are outside of shoutDistance."); defaultWhisperDistanceEntry = Bind(config, "Chat", "defaultWhisperDistance", 4f, "This value determines the range in meters that you can see whisper text messages by default."); defaultNormalDistanceEntry = Bind(config, "Chat", "defaultNormalDistance", 15f, "This value determines the range in meters that you can see normal text messages by default."); defaultShoutDistanceEntry = Bind(config, "Chat", "defaultShoutDistance", 70f, "This value determines the range in meters that you can see shout text messages by default."); } } public class CraftFromChestConfiguration : BaseConfig { private const string Section = "CraftFromChest"; private ConfigEntry rangeEntry; private ConfigEntry disableCookingStationEntry; private ConfigEntry checkFromWorkbenchEntry; private ConfigEntry ignorePrivateAreaCheckEntry; private ConfigEntry lookupIntervalEntry; private ConfigEntry allowCraftingFromCartsEntry; private ConfigEntry allowCraftingFromShipsEntry; public float range => rangeEntry.Value; public bool disableCookingStation => disableCookingStationEntry.Value; public bool checkFromWorkbench => checkFromWorkbenchEntry.Value; public bool ignorePrivateAreaCheck => ignorePrivateAreaCheckEntry.Value; public int lookupInterval => lookupIntervalEntry.Value; public bool allowCraftingFromCarts => allowCraftingFromCartsEntry.Value; public bool allowCraftingFromShips => allowCraftingFromShipsEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "CraftFromChest", defaultValue: false, "Change false to true to enable this section.\nThis feature allows you to craft from nearby chests when in range."); rangeEntry = Bind(config, "CraftFromChest", "range", 20f, 1f, 50f, "The range of the chest detection in meters."); disableCookingStationEntry = Bind(config, "CraftFromChest", "disableCookingStation", defaultValue: false, "Change false to true to disable this feature when using a Cooking Station."); checkFromWorkbenchEntry = Bind(config, "CraftFromChest", "checkFromWorkbench", defaultValue: true, "If in a workbench area, uses it as reference point when scanning for chests."); ignorePrivateAreaCheckEntry = Bind(config, "CraftFromChest", "ignorePrivateAreaCheck", defaultValue: false, "This option prevents crafting to pull items from warded areas if the player doesnt have access to it."); lookupIntervalEntry = Bind(config, "CraftFromChest", "lookupInterval", 3, 1, 10, "The interval in seconds that the feature scans your nearby chests.\nWe recommend not going below 3 seconds."); allowCraftingFromCartsEntry = Bind(config, "CraftFromChest", "allowCraftingFromCarts", defaultValue: false, "Allows the system to use and see contents of carts for crafting. Might also allow use of other modded containers or vehicles not accessible otherwise."); allowCraftingFromShipsEntry = Bind(config, "CraftFromChest", "allowCraftingFromShips", defaultValue: false, "Allows the system to use and see contents of ships for crafting. Might also allow use of other modded containers or vehicles not accessible otherwise."); } } public class DemisterConfiguration : BaseConfig { private const string Section = "Demister"; private ConfigEntry wispLightEntry; private ConfigEntry wispTorchEntry; private ConfigEntry MistwalkerEntry; public float wispLight => wispLightEntry.Value; public float wispTorch => wispTorchEntry.Value; public float Mistwalker => MistwalkerEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Demister", defaultValue: false, "Change false to true to enable this section."); wispLightEntry = Bind(config, "Demister", "wispLight", 10f, "This value determines the range of Wisp Light demister field."); wispTorchEntry = Bind(config, "Demister", "wispTorch", 12f, "This value determines the range of Wisp Torch demister field."); MistwalkerEntry = Bind(config, "Demister", "mistwalker", 5f, "This value determines the range of Mistwalker demister field."); } } public class DurabilityConfiguration : BaseConfig { private const string Section = "Durability"; private ConfigEntry axesEntry; private ConfigEntry pickaxesEntry; private ConfigEntry hammerEntry; private ConfigEntry cultivatorEntry; private ConfigEntry hoeEntry; private ConfigEntry weaponsEntry; private ConfigEntry armorEntry; private ConfigEntry bowsEntry; private ConfigEntry shieldsEntry; private ConfigEntry torchEntry; public float axes => axesEntry.Value; public float pickaxes => pickaxesEntry.Value; public float hammer => hammerEntry.Value; public float cultivator => cultivatorEntry.Value; public float hoe => hoeEntry.Value; public float weapons => weaponsEntry.Value; public float armor => armorEntry.Value; public float bows => bowsEntry.Value; public float shields => shieldsEntry.Value; public float torch => torchEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Durability", defaultValue: false, "Change false to true to enable this section. This section contains modifiers.\nModifiers are increases and reduction in percent declared by 50, or -50."); axesEntry = Bind(config, "Durability", "axes", 0f, "Each of these values increase or reduce the durability of the specific item type by %.\nThe value 50 will increase the durability from 100 to 150. The value -50 will reduce the durability from 100 to 50."); pickaxesEntry = Bind(config, "Durability", "pickaxes", 0f, "Each of these values increase or reduce the durability of the specific item type by %.\nThe value 50 will increase the durability from 100 to 150. The value -50 will reduce the durability from 100 to 50."); hammerEntry = Bind(config, "Durability", "hammer", 0f, "Each of these values increase or reduce the durability of the specific item type by %.\nThe value 50 will increase the durability from 100 to 150. The value -50 will reduce the durability from 100 to 50."); cultivatorEntry = Bind(config, "Durability", "cultivator", 0f, "Each of these values increase or reduce the durability of the specific item type by %.\nThe value 50 will increase the durability from 100 to 150. The value -50 will reduce the durability from 100 to 50."); hoeEntry = Bind(config, "Durability", "hoe", 0f, "Each of these values increase or reduce the durability of the specific item type by %.\nThe value 50 will increase the durability from 100 to 150. The value -50 will reduce the durability from 100 to 50."); weaponsEntry = Bind(config, "Durability", "weapons", 0f, "Each of these values increase or reduce the durability of the specific item type by %.\nThe value 50 will increase the durability from 100 to 150. The value -50 will reduce the durability from 100 to 50."); armorEntry = Bind(config, "Durability", "armor", 0f, "Each of these values increase or reduce the durability of the specific item type by %.\nThe value 50 will increase the durability from 100 to 150. The value -50 will reduce the durability from 100 to 50."); bowsEntry = Bind(config, "Durability", "bows", 0f, "Each of these values increase or reduce the durability of the specific item type by %.\nThe value 50 will increase the durability from 100 to 150. The value -50 will reduce the durability from 100 to 50."); shieldsEntry = Bind(config, "Durability", "shields", 0f, "Each of these values increase or reduce the durability of the specific item type by %.\nThe value 50 will increase the durability from 100 to 150. The value -50 will reduce the durability from 100 to 50."); torchEntry = Bind(config, "Durability", "torch", 0f, "Each of these values increase or reduce the durability of the specific item type by %.\nThe value 50 will increase the durability from 100 to 150. The value -50 will reduce the durability from 100 to 50."); } } public class EggConfiguration : BaseConfig { private const string Section = "Egg"; private ConfigEntry showHatchTimeEntry; private ConfigEntry hatchTimeEntry; private ConfigEntry growTimeEntry; private ConfigEntry requireShelterEntry; private ConfigEntry canStackEntry; private ConfigEntry soldByDefaultEntry; private ConfigEntry sellPriceEntry; public bool showHatchTime => showHatchTimeEntry.Value; public float hatchTime => hatchTimeEntry.Value; public float growTime => growTimeEntry.Value; public bool requireShelter => requireShelterEntry.Value; public bool canStack => canStackEntry.Value; public bool soldByDefault => soldByDefaultEntry.Value; public int sellPrice => sellPriceEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Egg", defaultValue: false, "Change false to true to enable this section."); showHatchTimeEntry = Bind(config, "Egg", "showHatchTime", defaultValue: false, "If set to true the time until the egg hatches will be displayed on hover."); hatchTimeEntry = Bind(config, "Egg", "hatchTime", 300f, "This value determines the time it takes for an egg to initially hatch into a chicken in seconds.\nA value of 300 means 5 minutes."); growTimeEntry = Bind(config, "Egg", "growTime", 3000f, "This value determines the time it takes for a chicken to grow into an adult in seconds.\nA value of 3000 means 50 minutes."); requireShelterEntry = Bind(config, "Egg", "requireShelter", defaultValue: true, "This value determines whether or not an egg requires a roof and fire to grow.\nIf set to false, eggs will grow anywhere."); canStackEntry = Bind(config, "Egg", "canStack", defaultValue: false, "This value determines whether or not eggs can grow in a stack on the ground.\nIf set to true eggs will grow as many chickens as there are eggs in the dropped stack."); soldByDefaultEntry = Bind(config, "Egg", "soldByDefault", defaultValue: false, "If set to true eggs are sold by Haldor without any requirements."); sellPriceEntry = Bind(config, "Egg", "sellPrice", 1500, "This value determines the cost of an egg sold by Haldor"); } } public class EitrRefineryConfiguration : BaseConfig { private const string Section = "EitrRefinery"; private ConfigEntry maximumSapEntry; private ConfigEntry maximumSoftTissueEntry; private ConfigEntry productionSpeedEntry; private ConfigEntry autoDepositEntry; private ConfigEntry autoFuelEntry; private ConfigEntry ignorePrivateAreaCheckEntry; private ConfigEntry autoRangeEntry; public int maximumSap => maximumSapEntry.Value; public int maximumSoftTissue => maximumSoftTissueEntry.Value; public float productionSpeed => productionSpeedEntry.Value; public bool autoDeposit => autoDepositEntry.Value; public bool autoFuel => autoFuelEntry.Value; public bool ignorePrivateAreaCheck => ignorePrivateAreaCheckEntry.Value; public float autoRange => autoRangeEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "EitrRefinery", defaultValue: false, "Change false to true to enable this section."); maximumSapEntry = Bind(config, "EitrRefinery", "maximumSap", 20, "Maximum amount of sap in an Eitr Refinery."); maximumSoftTissueEntry = Bind(config, "EitrRefinery", "maximumSoftTissue", 20, "Maximum amount of soft tissue in an Eitr Refinery."); productionSpeedEntry = Bind(config, "EitrRefinery", "productionSpeed", 40f, "The time it takes for the Eitr Refinery to produce a single eitr in seconds."); autoDepositEntry = Bind(config, "EitrRefinery", "autoDeposit", defaultValue: true, "Instead of dropping the items, they will be placed inside the nearest nearby chests."); autoFuelEntry = Bind(config, "EitrRefinery", "autoFuel", defaultValue: true, "The Eitr Refinery will pull sap and soft tissue from nearby chests to be automatically added to it when it's empty."); ignorePrivateAreaCheckEntry = Bind(config, "EitrRefinery", "ignorePrivateAreaCheck", defaultValue: true, "This option prevents the Eitr Refinery to pull items from warded areas if it isn't placed inside of it.\nFor convenience, we recommend this to be set to true."); autoRangeEntry = Bind(config, "EitrRefinery", "autoRange", 10f, 1f, 50f, "The range of the chest detection for the auto deposit and auto fuel features.\nMaximum is 50"); } } public class EitrUsageConfiguration : BaseConfig { private const string Section = "EitrUsage"; private ConfigEntry bloodMagicEntry; private ConfigEntry elementalMagicEntry; public float bloodMagic => bloodMagicEntry.Value; public float elementalMagic => elementalMagicEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "EitrUsage", defaultValue: false, "Change false to true to enable this section. This section contains modifiers.\nModifiers are increases and reduction in percent declared by 50, or -50."); bloodMagicEntry = Bind(config, "EitrUsage", "bloodMagic", 0f, "Each of these values change the respective tool in Eitr usage by increases and reduction in percent declared by 50, or -50."); elementalMagicEntry = Bind(config, "EitrUsage", "elementalMagic", 0f, "Each of these values change the respective tool in Eitr usage by increases and reduction in percent declared by 50, or -50."); } } public class ExperienceConfiguration : BaseConfig { private const string Section = "Experience"; private ConfigEntry swordsEntry; private ConfigEntry knivesEntry; private ConfigEntry clubsEntry; private ConfigEntry polearmsEntry; private ConfigEntry spearsEntry; private ConfigEntry blockingEntry; private ConfigEntry axesEntry; private ConfigEntry bowsEntry; private ConfigEntry elementalMagicEntry; private ConfigEntry bloodMagicEntry; private ConfigEntry unarmedEntry; private ConfigEntry pickaxesEntry; private ConfigEntry woodCuttingEntry; private ConfigEntry crossbowsEntry; private ConfigEntry jumpEntry; private ConfigEntry sneakEntry; private ConfigEntry runEntry; private ConfigEntry swimEntry; private ConfigEntry fishingEntry; private ConfigEntry cookingEntry; private ConfigEntry farmingEntry; private ConfigEntry craftingEntry; private ConfigEntry rideEntry; public float swords => swordsEntry.Value; public float knives => knivesEntry.Value; public float clubs => clubsEntry.Value; public float polearms => polearmsEntry.Value; public float spears => spearsEntry.Value; public float blocking => blockingEntry.Value; public float axes => axesEntry.Value; public float bows => bowsEntry.Value; public float elementalMagic => elementalMagicEntry.Value; public float bloodMagic => bloodMagicEntry.Value; public float unarmed => unarmedEntry.Value; public float pickaxes => pickaxesEntry.Value; public float woodCutting => woodCuttingEntry.Value; public float crossbows => crossbowsEntry.Value; public float jump => jumpEntry.Value; public float sneak => sneakEntry.Value; public float run => runEntry.Value; public float swim => swimEntry.Value; public float fishing => fishingEntry.Value; public float cooking => cookingEntry.Value; public float farming => farmingEntry.Value; public float crafting => craftingEntry.Value; public float ride => rideEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Experience", defaultValue: false, "Change false to true to enable this section. This section contains modifiers.\nModifiers are increases and reduction in percent declared by 50, or -50. The value 50 will increase experience gained by 50%, -50 will reduce experience gained by 50%."); swordsEntry = Bind(config, "Experience", "swords", 0f, "The modifier value for the experience gained of swords."); knivesEntry = Bind(config, "Experience", "knives", 0f, "The modifier value for the experience gained of knives."); clubsEntry = Bind(config, "Experience", "clubs", 0f, "The modifier value for the experience gained of clubs."); polearmsEntry = Bind(config, "Experience", "polearms", 0f, "The modifier value for the experience gained of polearms."); spearsEntry = Bind(config, "Experience", "spears", 0f, "The modifier value for the experience gained of spears."); blockingEntry = Bind(config, "Experience", "blocking", 0f, "The modifier value for the experience gained of blocking."); axesEntry = Bind(config, "Experience", "axes", 0f, "The modifier value for the experience gained of axes."); bowsEntry = Bind(config, "Experience", "bows", 0f, "The modifier value for the experience gained of bows."); elementalMagicEntry = Bind(config, "Experience", "elementalMagic", 0f, "The modifier value for the experience gained of elemental magic."); bloodMagicEntry = Bind(config, "Experience", "bloodMagic", 0f, "The modifier value for the experience gained of blood magic."); unarmedEntry = Bind(config, "Experience", "unarmed", 0f, "The modifier value for the experience gained of unarmed."); pickaxesEntry = Bind(config, "Experience", "pickaxes", 0f, "The modifier value for the experience gained of mining."); woodCuttingEntry = Bind(config, "Experience", "woodCutting", 0f, "The modifier value for the experience gained of wood cutting."); crossbowsEntry = Bind(config, "Experience", "crossbows", 0f, "The modifier value for the experience gained of crossbows."); jumpEntry = Bind(config, "Experience", "jump", 0f, "The modifier value for the experience gained of jumping."); sneakEntry = Bind(config, "Experience", "sneak", 0f, "The modifier value for the experience gained of sneaking."); runEntry = Bind(config, "Experience", "run", 0f, "The modifier value for the experience gained of running."); swimEntry = Bind(config, "Experience", "swim", 0f, "The modifier value for the experience gained of swimming."); fishingEntry = Bind(config, "Experience", "fishing", 0f, "The modifier value for the experience gained of fishing."); cookingEntry = Bind(config, "Experience", "cooking", 0f, "The modifier value for the experience gained of cooking."); farmingEntry = Bind(config, "Experience", "farming", 0f, "The modifier value for the experience gained of farming."); craftingEntry = Bind(config, "Experience", "crafting", 0f, "The modifier value for the experience gained of crafting."); rideEntry = Bind(config, "Experience", "ride", 0f, "The modifier value for the experience gained of riding."); } } public class FermenterConfiguration : BaseConfig { private const string Section = "Fermenter"; private ConfigEntry fermenterDurationEntry; private ConfigEntry fermenterItemsProducedEntry; private ConfigEntry showDurationEntry; private ConfigEntry autoDepositEntry; private ConfigEntry autoFuelEntry; private ConfigEntry ignorePrivateAreaCheckEntry; private ConfigEntry autoRangeEntry; public float fermenterDuration => fermenterDurationEntry.Value; public int fermenterItemsProduced => fermenterItemsProducedEntry.Value; public bool showDuration => showDurationEntry.Value; public bool autoDeposit => autoDepositEntry.Value; public bool autoFuel => autoFuelEntry.Value; public bool ignorePrivateAreaCheck => ignorePrivateAreaCheckEntry.Value; public float autoRange => autoRangeEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Fermenter", defaultValue: false, "Change false to true to enable this section."); fermenterDurationEntry = Bind(config, "Fermenter", "fermenterDuration", 2400f, "Configure the time that the fermenter takes to produce its product, 2400 seconds are 48 ingame hours."); fermenterItemsProducedEntry = Bind(config, "Fermenter", "fermenterItemsProduced", 6, "Configure the total amount of produced items from a fermenter."); showDurationEntry = Bind(config, "Fermenter", "showDuration", defaultValue: false, "Display the minutes and seconds until the fermenter is done on crosshair hover."); autoDepositEntry = Bind(config, "Fermenter", "autoDeposit", defaultValue: false, "Instead of dropping the items, they will be placed inside the nearest nearby chests."); autoFuelEntry = Bind(config, "Fermenter", "autoFuel", defaultValue: false, "Automatically pull meads from nearby chests to be placed inside the Fermenter as soon as its empty."); ignorePrivateAreaCheckEntry = Bind(config, "Fermenter", "ignorePrivateAreaCheck", defaultValue: true, "This option prevents the fermenter to pull items from warded areas if it isn't placed inside of it.\nFor convenience, we recommend this to be set to true."); autoRangeEntry = Bind(config, "Fermenter", "autoRange", 10f, 1f, 50f, "The range of the chest detection for the auto deposit and auto fuel features\nMaximum is 50"); } } public class FireSourceConfiguration : BaseConfig { private const string Section = "FireSource"; private ConfigEntry torchesEntry; private ConfigEntry firesEntry; private ConfigEntry autoFuelEntry; private ConfigEntry ignorePrivateAreaCheckEntry; private ConfigEntry autoRangeEntry; public bool torches => torchesEntry.Value; public bool fires => firesEntry.Value; public bool autoFuel => autoFuelEntry.Value; public bool ignorePrivateAreaCheck => ignorePrivateAreaCheckEntry.Value; public float autoRange => autoRangeEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "FireSource", defaultValue: false, "Change false to true to enable this section."); torchesEntry = Bind(config, "FireSource", "torches", defaultValue: false, "If set to true, torch-type fire sources will have infinite fuel.\nApplies to: wood torches, iron torches, green torches, sconces and brazier."); firesEntry = Bind(config, "FireSource", "fires", defaultValue: false, "If set to true, non torch-type fire sources will have infinite fuel."); autoFuelEntry = Bind(config, "FireSource", "autoFuel", defaultValue: false, "Automatically pull wood from nearby chests to be placed inside the Fire as soon as its empty."); ignorePrivateAreaCheckEntry = Bind(config, "FireSource", "ignorePrivateAreaCheck", defaultValue: true, "This option prevents the Fire to pull items from warded areas if it isn't placed inside of it.\nFor convenience, we recommend this to be set to true."); autoRangeEntry = Bind(config, "FireSource", "autoRange", 10f, 1f, 50f, "The range of the chest detection for the auto fuel features.\nMaximum is 50"); } } public class FirstPersonConfiguration : ClientConfig { private const string Section = "FirstPerson"; private ConfigEntry hotkeyEntry; private ConfigEntry raiseFOVHotkeyEntry; private ConfigEntry defaultFOVEntry; private ConfigEntry lowerFOVHotkeyEntry; public KeyCode hotkey => hotkeyEntry.Value; public KeyCode raiseFOVHotkey => raiseFOVHotkeyEntry.Value; public float defaultFOV => defaultFOVEntry.Value; public KeyCode lowerFOVHotkey => lowerFOVHotkeyEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "FirstPerson", defaultValue: false, "Change false to true to enable this section."); hotkeyEntry = Bind(config, "FirstPerson", "hotkey", (KeyCode)291, "Hotkey to enable First Person."); raiseFOVHotkeyEntry = Bind(config, "FirstPerson", "raiseFOVHotkey", (KeyCode)280, "Hotkey to raise Field Of View."); defaultFOVEntry = Bind(config, "FirstPerson", "defaultFOV", 65f, "Default Field Of View to use."); lowerFOVHotkeyEntry = Bind(config, "FirstPerson", "lowerFOVHotkey", (KeyCode)281, "Hotkey to lower Field Of View."); } } public class FoodConfiguration : BaseConfig { private const string Section = "Food"; private ConfigEntry foodDurationMultiplierEntry; private ConfigEntry disableFoodDegradationEntry; public float foodDurationMultiplier => foodDurationMultiplierEntry.Value; public bool disableFoodDegradation => disableFoodDegradationEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Food", defaultValue: false, "Change false to true to enable this section."); foodDurationMultiplierEntry = Bind(config, "Food", "foodDurationMultiplier", 0f, "Increase or reduce the time that food lasts by %.\nThe value 50 would cause food to run out 50% slower, -50% would cause the food to run out 50% faster."); disableFoodDegradationEntry = Bind(config, "Food", "disableFoodDegradation", defaultValue: false, "This option prevents food degrading over time - in other words, it retains its maximum benefit until it runs out instead of reducing its effect over time."); } } public class FreePlacementRotationConfiguration : BaseConfig { private const string Section = "FreePlacementRotation"; private ConfigEntry rotateYEntry; private ConfigEntry rotateXEntry; private ConfigEntry rotateZEntry; private ConfigEntry copyRotationParallelEntry; private ConfigEntry copyRotationPerpendicularEntry; public KeyCode rotateY => rotateYEntry.Value; public KeyCode rotateX => rotateXEntry.Value; public KeyCode rotateZ => rotateZEntry.Value; public KeyCode copyRotationParallel => copyRotationParallelEntry.Value; public KeyCode copyRotationPerpendicular => copyRotationPerpendicularEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "FreePlacementRotation", defaultValue: false, "Change false to true to enable this section, if you set this to false the mode will not be accessible."); rotateYEntry = Bind(config, "FreePlacementRotation", "rotateY", (KeyCode)308, "Rotates placement marker by 1 degree with keep ability to attach to nearly pieces."); rotateXEntry = Bind(config, "FreePlacementRotation", "rotateX", (KeyCode)99, "Rotates placement marker by 1 degree with keep ability to attach to nearly pieces."); rotateZEntry = Bind(config, "FreePlacementRotation", "rotateZ", (KeyCode)118, "Rotates placement marker by 1 degree with keep ability to attach to nearly pieces."); copyRotationParallelEntry = Bind(config, "FreePlacementRotation", "copyRotationParallel", (KeyCode)102, "Copy rotation of placement marker from target piece in front of you."); copyRotationPerpendicularEntry = Bind(config, "FreePlacementRotation", "copyRotationPerpendicular", (KeyCode)103, "Set rotation to be perpendicular to piece in front of you."); } } public class FurnaceConfiguration : BaseConfig { private const string Section = "Furnace"; private ConfigEntry maximumOreEntry; private ConfigEntry maximumCoalEntry; private ConfigEntry coalUsedPerProductEntry; private ConfigEntry productionSpeedEntry; private ConfigEntry autoDepositEntry; private ConfigEntry autoFuelEntry; private ConfigEntry ignorePrivateAreaCheckEntry; private ConfigEntry autoRangeEntry; private ConfigEntry allowAllOresEntry; public int maximumOre => maximumOreEntry.Value; public int maximumCoal => maximumCoalEntry.Value; public int coalUsedPerProduct => coalUsedPerProductEntry.Value; public float productionSpeed => productionSpeedEntry.Value; public bool autoDeposit => autoDepositEntry.Value; public bool autoFuel => autoFuelEntry.Value; public bool ignorePrivateAreaCheck => ignorePrivateAreaCheckEntry.Value; public float autoRange => autoRangeEntry.Value; public bool allowAllOres => allowAllOresEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Furnace", defaultValue: false, "Change false to true to enable this section."); maximumOreEntry = Bind(config, "Furnace", "maximumOre", 10, "Maximum amount of ore in a Furnace."); maximumCoalEntry = Bind(config, "Furnace", "maximumCoal", 20, "Maximum amount of coal in a Furnace."); coalUsedPerProductEntry = Bind(config, "Furnace", "coalUsedPerProduct", 2, "The total amount of coal used to produce a single smelted ingot."); productionSpeedEntry = Bind(config, "Furnace", "productionSpeed", 30f, "The time it takes for the Furnace to produce a single ingot in seconds."); autoDepositEntry = Bind(config, "Furnace", "autoDeposit", defaultValue: false, "Instead of dropping the items, they will be placed inside the nearest nearby chests."); autoFuelEntry = Bind(config, "Furnace", "autoFuel", defaultValue: false, "The Furnace will pull coal and raw materials from nearby chests to be automatically added to it when its empty."); ignorePrivateAreaCheckEntry = Bind(config, "Furnace", "ignorePrivateAreaCheck", defaultValue: true, "This option prevents the Furnace to pull items from warded areas if it isn't placed inside of it.\nFor convenience, we recommend this to be set to true."); autoRangeEntry = Bind(config, "Furnace", "autoRange", 10f, 1f, 50f, "The range of the chest detection for the auto deposit and auto fuel features.\nMaximum is 50"); allowAllOresEntry = Bind(config, "Furnace", "allowAllOres", defaultValue: false, "This option allows all ores inside the Furnace."); } } public class GameClockConfiguration : BaseConfig { private const string Section = "GameClock"; private ConfigEntry useAMPMEntry; private ConfigEntry textFontSizeEntry; private ConfigEntry textRedChannelEntry; private ConfigEntry textGreenChannelEntry; private ConfigEntry textBlueChannelEntry; private ConfigEntry textTransparencyChannelEntry; public bool useAMPM => useAMPMEntry.Value; public int textFontSize => textFontSizeEntry.Value; public int textRedChannel => textRedChannelEntry.Value; public int textGreenChannel => textGreenChannelEntry.Value; public int textBlueChannel => textBlueChannelEntry.Value; public int textTransparencyChannel => textTransparencyChannelEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "GameClock", defaultValue: false, "Change false to true to enable this section."); useAMPMEntry = Bind(config, "GameClock", "useAMPM", defaultValue: false, "Change time formatting from 24hr to AM-PM."); textFontSizeEntry = Bind(config, "GameClock", "textFontSize", 34, "Change font size of time text."); textRedChannelEntry = Bind(config, "GameClock", "textRedChannel", 248, 0, 255, "Change how red the time text is (51/255)."); textGreenChannelEntry = Bind(config, "GameClock", "textGreenChannel", 105, 0, 255, "Change how green the time text is (51/255)."); textBlueChannelEntry = Bind(config, "GameClock", "textBlueChannel", 0, 0, 255, "Change how blue the time text is (51/255)."); textTransparencyChannelEntry = Bind(config, "GameClock", "textTransparencyChannel", 255, 0, 255, "Change how transparent the time text is (255 is solid with no transparency)."); } } public class GameConfiguration : BaseConfig { private const string Section = "Game"; private ConfigEntry gameDifficultyDamageScaleEntry; private ConfigEntry gameDifficultyHealthScaleEntry; private ConfigEntry extraPlayerCountNearbyEntry; private ConfigEntry setFixedPlayerCountToEntry; private ConfigEntry difficultyScaleRangeEntry; private ConfigEntry disablePortalsEntry; private ConfigEntry disableConsoleEntry; private ConfigEntry bigPortalNamesEntry; private ConfigEntry disableFogEntry; public float gameDifficultyDamageScale => gameDifficultyDamageScaleEntry.Value; public float gameDifficultyHealthScale => gameDifficultyHealthScaleEntry.Value; public int extraPlayerCountNearby => extraPlayerCountNearbyEntry.Value; public int setFixedPlayerCountTo => setFixedPlayerCountToEntry.Value; public int difficultyScaleRange => difficultyScaleRangeEntry.Value; public bool disablePortals => disablePortalsEntry.Value; public bool disableConsole => disableConsoleEntry.Value; public bool bigPortalNames => bigPortalNamesEntry.Value; public bool disableFog => disableFogEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Game", defaultValue: false, "Change false to true to enable this section."); gameDifficultyDamageScaleEntry = Bind(config, "Game", "gameDifficultyDamageScale", 4f, "The games damage multiplier per person nearby in difficultyScaleRange(m) radius.\nDefault is 4% monster damage increase per player in radius."); gameDifficultyHealthScaleEntry = Bind(config, "Game", "gameDifficultyHealthScale", 30f, "The games health multiplier per person nearby in difficultyScaleRange(m) radius.\nDefault is 30% monster health increase per player in radius."); extraPlayerCountNearbyEntry = Bind(config, "Game", "extraPlayerCountNearby", 0, "Adds additional players to the difficulty calculation in multiplayer unrelated to the actual amount.\nThis option is disabled if its set to 0."); setFixedPlayerCountToEntry = Bind(config, "Game", "setFixedPlayerCountTo", 0, "Sets the nearby player count always to this value + extraPlayerCountNearby.\nThis option is disabled if its set to 0."); difficultyScaleRangeEntry = Bind(config, "Game", "difficultyScaleRange", 200, "The range in meters at which other players count towards nearby players for the difficulty scale."); disablePortalsEntry = Bind(config, "Game", "disablePortals", defaultValue: false, "If you set this to true, all portals will be disabled."); disableConsoleEntry = Bind(config, "Game", "disableConsole", defaultValue: false, "If you set this to true the console will be force disabled in-game."); bigPortalNamesEntry = Bind(config, "Game", "bigPortalNames", defaultValue: false, "If you set this to true, portal names will be displayed in big text in center of screen."); disableFogEntry = Bind(config, "Game", "disableFog", defaultValue: false, "Remove dense fog from the game."); } } public class GatherConfiguration : BaseConfig { private const string Section = "Gathering"; private ConfigEntry woodEntry; private ConfigEntry fineWoodEntry; private ConfigEntry coreWoodEntry; private ConfigEntry elderBarkEntry; private ConfigEntry yggdrasilWoodEntry; private ConfigEntry stoneEntry; private ConfigEntry blackMarbleEntry; private ConfigEntry tinOreEntry; private ConfigEntry copperOreEntry; private ConfigEntry copperScrapEntry; private ConfigEntry ironScrapEntry; private ConfigEntry silverOreEntry; private ConfigEntry chitinEntry; private ConfigEntry featherEntry; private ConfigEntry dropChanceEntry; private ConfigEntry graustenEntry; private ConfigEntry blackwoodEntry; private ConfigEntry flametalOreEntry; private ConfigEntry proustitePowderEntry; public float wood => woodEntry.Value; public float fineWood => fineWoodEntry.Value; public float coreWood => coreWoodEntry.Value; public float elderBark => elderBarkEntry.Value; public float yggdrasilWood => yggdrasilWoodEntry.Value; public float stone => stoneEntry.Value; public float blackMarble => blackMarbleEntry.Value; public float tinOre => tinOreEntry.Value; public float copperOre => copperOreEntry.Value; public float copperScrap => copperScrapEntry.Value; public float ironScrap => ironScrapEntry.Value; public float silverOre => silverOreEntry.Value; public float chitin => chitinEntry.Value; public float feather => featherEntry.Value; public float dropChance => dropChanceEntry.Value; public float grausten => graustenEntry.Value; public float blackwood => blackwoodEntry.Value; public float flametalOre => flametalOreEntry.Value; public float proustitePowder => proustitePowderEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Gathering", defaultValue: false, "Change false to true to enable this section. This section contains modifiers. Modifiers are increases and reduction in percent declared by 50, or -50."); woodEntry = Bind(config, "Gathering", "wood", 0f, "Each of these values increase or reduce the dropped items from destroyed objects with tools (Stones, Trees, Resource nodes, etc.) by %.\nThe value 50 will increase the dropped wood from trees from 10 to 15. The value -50 will reduce the amount of dropped wood from 10 to 5."); fineWoodEntry = Bind(config, "Gathering", "fineWood", 0f, "Each of these values increase or reduce the dropped items from destroyed objects with tools (Stones, Trees, Resource nodes, etc.) by %.\nThe value 50 will increase the dropped wood from trees from 10 to 15. The value -50 will reduce the amount of dropped wood from 10 to 5."); coreWoodEntry = Bind(config, "Gathering", "coreWood", 0f, "Each of these values increase or reduce the dropped items from destroyed objects with tools (Stones, Trees, Resource nodes, etc.) by %.\nThe value 50 will increase the dropped wood from trees from 10 to 15. The value -50 will reduce the amount of dropped wood from 10 to 5."); elderBarkEntry = Bind(config, "Gathering", "elderBark", 0f, "Each of these values increase or reduce the dropped items from destroyed objects with tools (Stones, Trees, Resource nodes, etc.) by %.\nThe value 50 will increase the dropped wood from trees from 10 to 15. The value -50 will reduce the amount of dropped wood from 10 to 5."); yggdrasilWoodEntry = Bind(config, "Gathering", "yggdrasilWood", 0f, "Each of these values increase or reduce the dropped items from destroyed objects with tools (Stones, Trees, Resource nodes, etc.) by %.\nThe value 50 will increase the dropped wood from trees from 10 to 15. The value -50 will reduce the amount of dropped wood from 10 to 5."); stoneEntry = Bind(config, "Gathering", "stone", 0f, "Each of these values increase or reduce the dropped items from destroyed objects with tools (Stones, Trees, Resource nodes, etc.) by %.\nThe value 50 will increase the dropped wood from trees from 10 to 15. The value -50 will reduce the amount of dropped wood from 10 to 5."); blackMarbleEntry = Bind(config, "Gathering", "blackMarble", 0f, "Each of these values increase or reduce the dropped items from destroyed objects with tools (Stones, Trees, Resource nodes, etc.) by %.\nThe value 50 will increase the dropped wood from trees from 10 to 15. The value -50 will reduce the amount of dropped wood from 10 to 5."); tinOreEntry = Bind(config, "Gathering", "tinOre", 0f, "Each of these values increase or reduce the dropped items from destroyed objects with tools (Stones, Trees, Resource nodes, etc.) by %.\nThe value 50 will increase the dropped wood from trees from 10 to 15. The value -50 will reduce the amount of dropped wood from 10 to 5."); copperOreEntry = Bind(config, "Gathering", "copperOre", 0f, "Each of these values increase or reduce the dropped items from destroyed objects with tools (Stones, Trees, Resource nodes, etc.) by %.\nThe value 50 will increase the dropped wood from trees from 10 to 15. The value -50 will reduce the amount of dropped wood from 10 to 5."); copperScrapEntry = Bind(config, "Gathering", "copperScrap", 0f, "copperScrap doesn't increase drop rate from looting, ex. killing Dvergrs."); ironScrapEntry = Bind(config, "Gathering", "ironScrap", 0f, "copperScrap doesn't increase drop rate from looting, ex. killing Dvergrs."); silverOreEntry = Bind(config, "Gathering", "silverOre", 0f, "copperScrap doesn't increase drop rate from looting, ex. killing Dvergrs."); chitinEntry = Bind(config, "Gathering", "chitin", 0f, "copperScrap doesn't increase drop rate from looting, ex. killing Dvergrs."); featherEntry = Bind(config, "Gathering", "feather", 0f, "feather will also affect the drops from shooting gulls/crows, as well as drops from trees."); dropChanceEntry = Bind(config, "Gathering", "dropChance", 0f, "Modify the chance to drop resources from resource nodes affected by this category. This only works on resource nodes that do not have guaranteed drops.\nAs example by default scrap piles in dungeons have a 20% chance to drop a item, if you set this option to 200, you will then have a 60% chance to drop iron."); graustenEntry = Bind(config, "Gathering", "grausten", 0f, "Each of these values increase or reduce the dropped items from destroyed objects with tools (Stones, Trees, Resource nodes, etc.) by %.\nThe value 50 will increase the dropped wood from trees from 10 to 15. The value -50 will reduce the amount of dropped wood from 10 to 5."); blackwoodEntry = Bind(config, "Gathering", "blackwood", 0f, "Each of these values increase or reduce the dropped items from destroyed objects with tools (Stones, Trees, Resource nodes, etc.) by %.\nThe value 50 will increase the dropped wood from trees from 10 to 15. The value -50 will reduce the amount of dropped wood from 10 to 5."); flametalOreEntry = Bind(config, "Gathering", "flametalOre", 0f, "Ashlands"); proustitePowderEntry = Bind(config, "Gathering", "proustitePowder", 0f, "Ashlands"); } } public class GridAlignmentConfiguration : BaseConfig { private const string Section = "GridAlignment"; private ConfigEntry alignEntry; private ConfigEntry alignToggleEntry; private ConfigEntry changeDefaultAlignmentEntry; public KeyCode align => alignEntry.Value; public KeyCode alignToggle => alignToggleEntry.Value; public KeyCode changeDefaultAlignment => changeDefaultAlignmentEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "GridAlignment", defaultValue: false, "Change false to true to enable this section.\nThis offers a global fixed grid system to make precise placements."); alignEntry = Bind(config, "GridAlignment", "align", (KeyCode)308, "Key to enable grid alignment."); alignToggleEntry = Bind(config, "GridAlignment", "alignToggle", (KeyCode)288, "Key to toggle grid alignment."); changeDefaultAlignmentEntry = Bind(config, "GridAlignment", "changeDefaultAlignment", (KeyCode)287, "Key to change the default alignment."); } } public class HealthUsageConfiguration : BaseConfig { private const string Section = "HealthUsage"; private ConfigEntry bloodMagicEntry; public float bloodMagic => bloodMagicEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "HealthUsage", defaultValue: false, "Change false to true to enable this section. This section contains modifiers.\nModifiers are increases and reduction in percent declared by 50, or -50."); bloodMagicEntry = Bind(config, "HealthUsage", "bloodMagic", 0f, "Each of these values change the respective tool in health usage by increases and reduction in percent declared by 50, or -50."); } } public class HotkeyConfiguration : BaseConfig { private const string Section = "Hotkeys"; private ConfigEntry rollForwardsEntry; private ConfigEntry rollBackwardsEntry; public KeyCode rollForwards => rollForwardsEntry.Value; public KeyCode rollBackwards => rollBackwardsEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Hotkeys", defaultValue: false, "https://docs.unity3d.com/ScriptReference/KeyCode.html <- a list of keycodes\nChange false to true to enable this section."); rollForwardsEntry = Bind(config, "Hotkeys", "rollForwards", (KeyCode)290, "Roll forwards on hot key pressed."); rollBackwardsEntry = Bind(config, "Hotkeys", "rollBackwards", (KeyCode)291, "Roll backwards on hot key pressed."); } } public class HotTubConfiguration : BaseConfig { private const string Section = "HotTub"; private ConfigEntry infiniteFuelEntry; private ConfigEntry autoFuelEntry; private ConfigEntry ignorePrivateAreaCheckEntry; private ConfigEntry autoRangeEntry; public bool infiniteFuel => infiniteFuelEntry.Value; public bool autoFuel => autoFuelEntry.Value; public bool ignorePrivateAreaCheck => ignorePrivateAreaCheckEntry.Value; public float autoRange => autoRangeEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "HotTub", defaultValue: false, "Change false to true to enable this section."); infiniteFuelEntry = Bind(config, "HotTub", "infiniteFuel", defaultValue: false, "If set to true, the hot tub will stay at max fuel level, without consuming any fuel."); autoFuelEntry = Bind(config, "HotTub", "autoFuel", defaultValue: false, "The hot tub will fuel itself from nearby chests."); ignorePrivateAreaCheckEntry = Bind(config, "HotTub", "ignorePrivateAreaCheck", defaultValue: true, "This option allows the hot tub to fuel itself from chests that it doesn't share a warded area with.\nFor convenience, we recommend this to be set to true."); autoRangeEntry = Bind(config, "HotTub", "autoRange", 10f, 1f, 50f, "The range of the chest detection for the auto fuel feature.\nMaximum is 50"); } } public class HudConfiguration : ClientConfig { private const string Section = "Hud"; private ConfigEntry showRequiredItemsEntry; private ConfigEntry experienceGainedNotificationsEntry; private ConfigEntry removeDamageFlashEntry; private ConfigEntry displayBowAmmoCountsEntry; public bool showRequiredItems => showRequiredItemsEntry.Value; public bool experienceGainedNotifications => experienceGainedNotificationsEntry.Value; public bool removeDamageFlash => removeDamageFlashEntry.Value; public int displayBowAmmoCounts => displayBowAmmoCountsEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Hud", defaultValue: false, "Change false to true to enable this section."); showRequiredItemsEntry = Bind(config, "Hud", "showRequiredItems", defaultValue: false, "Shows the required amount of items AND the amount of items in your inventory in build mode and while crafting.\nThis is enabled when the CraftFromChest section is enabled."); experienceGainedNotificationsEntry = Bind(config, "Hud", "experienceGainedNotifications", defaultValue: false, "Shows small notifications about all skill experienced gained in the top left corner."); removeDamageFlashEntry = Bind(config, "Hud", "removeDamageFlash", defaultValue: false, "Set to true to remove the red screen flash overlay when the player takes damage."); displayBowAmmoCountsEntry = Bind(config, "Hud", "displayBowAmmoCounts", 0, "If bow is in hotbar, display current ammo & total ammo under hotbar icon - never (0), when equipped (1), or always (2)."); } } public class InventoryConfiguration : BaseConfig { private const string Section = "Inventory"; private ConfigEntry inventoryFillTopToBottomEntry; private ConfigEntry mergeWithExistingStacksEntry; private ConfigEntry playerInventoryRowsEntry; private ConfigEntry woodChestColumnsEntry; private ConfigEntry woodChestRowsEntry; private ConfigEntry personalChestColumnsEntry; private ConfigEntry personalChestRowsEntry; private ConfigEntry ironChestColumnsEntry; private ConfigEntry ironChestRowsEntry; private ConfigEntry blackmetalChestColumnsEntry; private ConfigEntry blackmetalChestRowsEntry; private ConfigEntry cartInventoryColumnsEntry; private ConfigEntry cartInventoryRowsEntry; private ConfigEntry karveInventoryColumnsEntry; private ConfigEntry karveInventoryRowsEntry; private ConfigEntry longboatInventoryColumnsEntry; private ConfigEntry longboatInventoryRowsEntry; public bool inventoryFillTopToBottom => inventoryFillTopToBottomEntry.Value; public bool mergeWithExistingStacks => mergeWithExistingStacksEntry.Value; public int playerInventoryRows => Math.Min(9, Math.Max(4, playerInventoryRowsEntry.Value)); public int woodChestColumns => woodChestColumnsEntry.Value; public int woodChestRows => woodChestRowsEntry.Value; public int personalChestColumns => personalChestColumnsEntry.Value; public int personalChestRows => personalChestRowsEntry.Value; public int ironChestColumns => ironChestColumnsEntry.Value; public int ironChestRows => ironChestRowsEntry.Value; public int blackmetalChestColumns => blackmetalChestColumnsEntry.Value; public int blackmetalChestRows => blackmetalChestRowsEntry.Value; public int cartInventoryColumns => cartInventoryColumnsEntry.Value; public int cartInventoryRows => cartInventoryRowsEntry.Value; public int karveInventoryColumns => karveInventoryColumnsEntry.Value; public int karveInventoryRows => karveInventoryRowsEntry.Value; public int longboatInventoryColumns => longboatInventoryColumnsEntry.Value; public int longboatInventoryRows => longboatInventoryRowsEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Inventory", defaultValue: false, "Change false to true to enable this section."); inventoryFillTopToBottomEntry = Bind(config, "Inventory", "inventoryFillTopToBottom", defaultValue: false, "By default tools and weapons go into inventories top to bottom and other materials bottom to top.\nSet to true to make all items go into the inventory top to bottom."); mergeWithExistingStacksEntry = Bind(config, "Inventory", "mergeWithExistingStacks", defaultValue: false, "By default items go to their original position when picking up your tombstone.\nSet to true to make all stacks try to merge with an existing stack first."); playerInventoryRowsEntry = Bind(config, "Inventory", "playerInventoryRows", 4, 4, 9, "Player inventory number of rows. Acts as a minimum: rows gained in-game are kept.\n(default 4, min 4, max 9)"); woodChestColumnsEntry = Bind(config, "Inventory", "woodChestColumns", 5, 3, 8, "Wood chest number of columns\n(default 5, 3 min, 8 max)"); woodChestRowsEntry = Bind(config, "Inventory", "woodChestRows", 2, 2, 10, "Wood chest number of rows (more than 4 rows will add a scrollbar).\n(default 2, min 2, 10 max)"); personalChestColumnsEntry = Bind(config, "Inventory", "personalChestColumns", 3, 3, 8, "Personal chest number of columns.\n(default 3, 3 min, 8 max)"); personalChestRowsEntry = Bind(config, "Inventory", "personalChestRows", 2, 2, 20, "Personal chest number of rows\n(default 2, 2 min, 20 max)"); ironChestColumnsEntry = Bind(config, "Inventory", "ironChestColumns", 6, 3, 8, "Iron chest number of columns.\n(default 6, min 3, max 8)"); ironChestRowsEntry = Bind(config, "Inventory", "ironChestRows", 4, 3, 20, "Iron chest number of rows (more than 4 rows will add a scrollbar)\n(default 4, min 3, max 20)"); blackmetalChestColumnsEntry = Bind(config, "Inventory", "blackmetalChestColumns", 8, 3, 8, "Blackmetal chests already have 8 columns by default but now you can lower it\n(default 8, min 3, max 8)"); blackmetalChestRowsEntry = Bind(config, "Inventory", "blackmetalChestRows", 4, 3, 20, "Blackmetal number of rows (more than 4 rows will add a scrollbar)\n(default 4, min 3, max 20)"); cartInventoryColumnsEntry = Bind(config, "Inventory", "cartInventoryColumns", 8, 6, 8, "Cart (Wagon) inventory number of columns\n(default 8, min 6, max 8)"); cartInventoryRowsEntry = Bind(config, "Inventory", "cartInventoryRows", 3, 3, 30, "Cart (Wagon) inventory number of rows (more than 4 rows will add a scrollbar)\n(default 3, min 3, max 30)"); karveInventoryColumnsEntry = Bind(config, "Inventory", "karveInventoryColumns", 2, 2, 8, "Karve (small boat) inventory number of columns\n(default 2, min 2, max 8)"); karveInventoryRowsEntry = Bind(config, "Inventory", "karveInventoryRows", 2, 2, 30, "Karve (small boat) inventory number of rows (more than 4 rows will add a scrollbar)\n(default 2, min 2, max 30)"); longboatInventoryColumnsEntry = Bind(config, "Inventory", "longboatInventoryColumns", 8, 6, 8, "Longboat (large boat) inventory number of columns\n(default 8, min 6, max 8)"); longboatInventoryRowsEntry = Bind(config, "Inventory", "longboatInventoryRows", 3, 3, 30, "Longboat (large boat) inventory number of rows (more than 4 rows will add a scrollbar)\n(default 3, min 3, max 30)"); } } public class ItemsConfiguration : BaseConfig { private const string Section = "Items"; private ConfigEntry noTeleportPreventionEntry; private ConfigEntry baseItemWeightReductionEntry; private ConfigEntry itemStackMultiplierEntry; private ConfigEntry droppedItemOnGroundDurationInSecondsEntry; private ConfigEntry itemsFloatInWaterEntry; public bool noTeleportPrevention => noTeleportPreventionEntry.Value; public float baseItemWeightReduction => baseItemWeightReductionEntry.Value; public float itemStackMultiplier => itemStackMultiplierEntry.Value; public float droppedItemOnGroundDurationInSeconds => droppedItemOnGroundDurationInSecondsEntry.Value; public bool itemsFloatInWater => itemsFloatInWaterEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Items", defaultValue: false, "Change false to true to enable this section."); noTeleportPreventionEntry = Bind(config, "Items", "noTeleportPrevention", defaultValue: false, "Enables you to teleport with ores and other usually teleport restricted objects."); baseItemWeightReductionEntry = Bind(config, "Items", "baseItemWeightReduction", 0f, "Increase or reduce item weight by a modifier in percent.\nThe value -50 will reduce item weight of every object by 50%, 50 will increase the weight of every item by 50%."); itemStackMultiplierEntry = Bind(config, "Items", "itemStackMultiplier", 0f, "Increase or reduce the size of all maximum item stacks by a modifier in percent.\nThe value 50 would set a usual item stack of 100 to be 150.\nThe value -50 would set a usual item stack of 100 to be 50."); droppedItemOnGroundDurationInSecondsEntry = Bind(config, "Items", "droppedItemOnGroundDurationInSeconds", 3600f, 0f, 3600f, "Set duration that dropped items stay on the ground before they are despawning. Game default is 3600 seconds."); itemsFloatInWaterEntry = Bind(config, "Items", "itemsFloatInWater", defaultValue: false, "Items dropped always float in water."); } } public class KilnConfiguration : BaseConfig { private const string Section = "Kiln"; private ConfigEntry productionSpeedEntry; private ConfigEntry maximumWoodEntry; private ConfigEntry dontProcessFineWoodEntry; private ConfigEntry dontProcessRoundLogEntry; private ConfigEntry autoDepositEntry; private ConfigEntry autoFuelEntry; private ConfigEntry stopAutoFuelThresholdEntry; private ConfigEntry ignorePrivateAreaCheckEntry; private ConfigEntry autoRangeEntry; public float productionSpeed => productionSpeedEntry.Value; public int maximumWood => maximumWoodEntry.Value; public bool dontProcessFineWood => dontProcessFineWoodEntry.Value; public bool dontProcessRoundLog => dontProcessRoundLogEntry.Value; public bool autoDeposit => autoDepositEntry.Value; public bool autoFuel => autoFuelEntry.Value; public int stopAutoFuelThreshold => stopAutoFuelThresholdEntry.Value; public bool ignorePrivateAreaCheck => ignorePrivateAreaCheckEntry.Value; public float autoRange => autoRangeEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Kiln", defaultValue: false, "Change false to true to enable this section."); productionSpeedEntry = Bind(config, "Kiln", "productionSpeed", 15f, "The time it takes for the Kiln to produce a single piece of coal in seconds."); maximumWoodEntry = Bind(config, "Kiln", "maximumWood", 25, "Maximum amount of wood in a Kiln."); dontProcessFineWoodEntry = Bind(config, "Kiln", "dontProcessFineWood", defaultValue: false, "Change false to true to disable Fine Wood processing."); dontProcessRoundLogEntry = Bind(config, "Kiln", "dontProcessRoundLog", defaultValue: false, "Change false to true to disabled Round Log processing."); autoDepositEntry = Bind(config, "Kiln", "autoDeposit", defaultValue: false, "Instead of dropping the items, they will be placed inside the nearest nearby chests."); autoFuelEntry = Bind(config, "Kiln", "autoFuel", defaultValue: false, "The Kiln will pull wood from nearby chests to be automatically added to it when its empty.\nThis option respects the dontProcessFineWood and dontProcessRoundLog settings."); stopAutoFuelThresholdEntry = Bind(config, "Kiln", "stopAutoFuelThreshold", 0, "Stops autoFuel (looking for fuel) when there is at leasts this quantity of Coal in nearby chests\n(ignored if set to 0)"); ignorePrivateAreaCheckEntry = Bind(config, "Kiln", "ignorePrivateAreaCheck", defaultValue: true, "This option prevents the Kiln to pull items from warded areas if it isn't placed inside of it.\nFor convenience, we recommend this to be set to true."); autoRangeEntry = Bind(config, "Kiln", "autoRange", 10f, 1f, 50f, "The range of the chest detection for the auto deposit and fuel features.\nMaximum is 50"); } } public class LootDropConfiguration : BaseConfig { private const string Section = "LootDrop"; private ConfigEntry lootDropAmountMultiplierEntry; private ConfigEntry lootDropChanceMultiplierEntry; public float lootDropAmountMultiplier => lootDropAmountMultiplierEntry.Value; public float lootDropChanceMultiplier => lootDropChanceMultiplierEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "LootDrop", defaultValue: false, "Change false to true to enable this section, if you set this to false the mode will not be accesible"); lootDropAmountMultiplierEntry = Bind(config, "LootDrop", "lootDropAmountMultiplier", 0f, "Change the amount of loot dropped when creatures or monsters are slain.\nA value of -100 will eliminate all drops, 0 will have no effect, 100 will double drops, 200 will triple and so on."); lootDropChanceMultiplierEntry = Bind(config, "LootDrop", "lootDropChanceMultiplier", 0f, "Change the chance of loot dropping when creatures or monsters are slain.\nA value of -100 will eliminate all drops, 0 will have no effect, 100 will double the percent of getting a drop, 200 will triple and so on.\nExample: If a drop has a 40% chance, setting this to 200 will make that chance 80%,\nand setting it to 300 will make it 100% (120% technically, but anything above 100% acts as 100%)"); } } public class MapConfiguration : BaseConfig { private const string Section = "Map"; private ConfigEntry shareMapProgressionEntry; private ConfigEntry exploreRadiusEntry; private ConfigEntry preventPlayerFromTurningOffPublicPositionEntry; private ConfigEntry shareAllPinsEntry; private ConfigEntry displayCartsAndBoatsEntry; public bool shareMapProgression => shareMapProgressionEntry.Value; public float exploreRadius => exploreRadiusEntry.Value; public bool preventPlayerFromTurningOffPublicPosition => preventPlayerFromTurningOffPublicPositionEntry.Value; public bool shareAllPins => shareAllPinsEntry.Value; public bool displayCartsAndBoats => displayCartsAndBoatsEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Map", defaultValue: false, "Change false to true to enable this section."); shareMapProgressionEntry = Bind(config, "Map", "shareMapProgression", defaultValue: false, "With this enabled you will receive the same exploration progression as other players on the server.\nThis will also enable the option for the server to sync everyones exploration progression on connecting to the server."); exploreRadiusEntry = Bind(config, "Map", "exploreRadius", 100f, "The radius of the map that you explore when moving."); preventPlayerFromTurningOffPublicPositionEntry = Bind(config, "Map", "preventPlayerFromTurningOffPublicPosition", defaultValue: false, "Prevents you and other people on the server to turn off their map sharing option."); shareAllPinsEntry = Bind(config, "Map", "shareAllPins", defaultValue: false, "This option automatically shares created pins with everyone playing on the server."); displayCartsAndBoatsEntry = Bind(config, "Map", "displayCartsAndBoats", defaultValue: false, "Display carts and boats on the map"); } } public class MonsterProjectileConfiguration : BaseConfig { private const string Section = "MonsterProjectile"; private ConfigEntry monsterMaxChargeVelocityMultiplierEntry; private ConfigEntry monsterMaxChargeAccuracyMultiplierEntry; public float monsterMaxChargeVelocityMultiplier => monsterMaxChargeVelocityMultiplierEntry.Value; public float monsterMaxChargeAccuracyMultiplier => monsterMaxChargeAccuracyMultiplierEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "MonsterProjectile", defaultValue: false, "Change false to true to enable this section."); monsterMaxChargeVelocityMultiplierEntry = Bind(config, "MonsterProjectile", "monsterMaxChargeVelocityMultiplier", 0f, "Value of 10 would increase the projectile velocity from 50 to 55."); monsterMaxChargeAccuracyMultiplierEntry = Bind(config, "MonsterProjectile", "monsterMaxChargeAccuracyMultiplier", 0f, "Value of (+)10 increase in accuracy will change the variance of projectile 1 degree to 0.9 degree at the point of projectile release."); } } public class OvenConfiguration : BaseConfig { private const string Section = "Oven"; private ConfigEntry infiniteFuelEntry; private ConfigEntry autoFuelEntry; private ConfigEntry ignorePrivateAreaCheckEntry; private ConfigEntry autoRangeEntry; public bool infiniteFuel => infiniteFuelEntry.Value; public bool autoFuel => autoFuelEntry.Value; public bool ignorePrivateAreaCheck => ignorePrivateAreaCheckEntry.Value; public float autoRange => autoRangeEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Oven", defaultValue: false, "Change false to true to enable this section."); infiniteFuelEntry = Bind(config, "Oven", "infiniteFuel", defaultValue: false, "If set to true, the oven will stay at max fuel level, without consuming any fuel."); autoFuelEntry = Bind(config, "Oven", "autoFuel", defaultValue: false, "The oven will fuel itself from nearby chests."); ignorePrivateAreaCheckEntry = Bind(config, "Oven", "ignorePrivateAreaCheck", defaultValue: true, "This option allows the oven to fuel itself from chests that it doesn't share a warded area with.\nFor convenience, we recommend this to be set to true."); autoRangeEntry = Bind(config, "Oven", "autoRange", 10f, 1f, 50f, "The range of the chest detection for the auto fuel feature.\nMaximum is 50"); } } public class PickableConfiguration : BaseConfig { private const string Section = "Pickable"; private ConfigEntry ediblesEntry; private ConfigEntry flowersAndIngredientsEntry; private ConfigEntry materialsEntry; private ConfigEntry valuablesEntry; private ConfigEntry surtlingCoresEntry; private ConfigEntry blackCoresEntry; private ConfigEntry questItemsEntry; public float edibles => ediblesEntry.Value; public float flowersAndIngredients => flowersAndIngredientsEntry.Value; public float materials => materialsEntry.Value; public float valuables => valuablesEntry.Value; public float surtlingCores => surtlingCoresEntry.Value; public float blackCores => blackCoresEntry.Value; public float questItems => questItemsEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Pickable", defaultValue: false, "Change false to true to enable this section.\nEach value below (in percent) will modify the yield when \"picking\" items (default key E) such as berries and flowers.\nA value of 100 will double drops, 200 will triple and so on."); ediblesEntry = Bind(config, "Pickable", "edibles", 0f, "All berries, all mushrooms, onions and carrots"); flowersAndIngredientsEntry = Bind(config, "Pickable", "flowersAndIngredients", 0f, "Barley, Flax, Dandelion, Thistle, Carrot Seeds, Turnip Seeds, Turnip, Onion Seeds"); materialsEntry = Bind(config, "Pickable", "materials", 0f, "Bone Fragments, Flint, Stone, Wood (branches on the ground)"); valuablesEntry = Bind(config, "Pickable", "valuables", 0f, "Amber, Amber Pearl, Coins, Ruby"); surtlingCoresEntry = Bind(config, "Pickable", "surtlingCores", 0f, "Surtling Core only"); blackCoresEntry = Bind(config, "Pickable", "blackCores", 0f, "Black Core only"); questItemsEntry = Bind(config, "Pickable", "questItems", 0f, "Items needed to sacrifice to bosses (excluding the first two bosses)"); } } public class PlayerConfiguration : BaseConfig { private const string Section = "Player"; private ConfigEntry baseMaximumWeightEntry; private ConfigEntry baseMegingjordBuffEntry; private ConfigEntry baseAutoPickUpRangeEntry; private ConfigEntry disableCameraShakeEntry; private ConfigEntry baseUnarmedDamageEntry; private ConfigEntry cropNotifierEntry; private ConfigEntry restSecondsPerComfortLevelEntry; private ConfigEntry deathPenaltyMultiplierEntry; private ConfigEntry autoRepairEntry; private ConfigEntry guardianBuffDurationEntry; private ConfigEntry guardianBuffCooldownEntry; private ConfigEntry disableGuardianBuffAnimationEntry; private ConfigEntry autoEquipShieldEntry; private ConfigEntry autoUnequipShieldEntry; private ConfigEntry skipIntroEntry; private ConfigEntry iHaveArrivedOnSpawnEntry; private ConfigEntry queueWeaponChangesEntry; private ConfigEntry dontUnequipItemsWhenSwimmingEntry; private ConfigEntry reequipItemsAfterSwimmingEntry; private ConfigEntry fallDamageScalePercentEntry; private ConfigEntry maxFallDamageEntry; private ConfigEntry skipTutorialsEntry; private ConfigEntry disableEncumberedEntry; private ConfigEntry autoPickUpWhenEncumberedEntry; private ConfigEntry disableEightSecondTeleportEntry; public float baseMaximumWeight => baseMaximumWeightEntry.Value; public float baseMegingjordBuff => baseMegingjordBuffEntry.Value; public float baseAutoPickUpRange => baseAutoPickUpRangeEntry.Value; public bool disableCameraShake => disableCameraShakeEntry.Value; public float baseUnarmedDamage => baseUnarmedDamageEntry.Value; public bool cropNotifier => cropNotifierEntry.Value; public float restSecondsPerComfortLevel => restSecondsPerComfortLevelEntry.Value; public float deathPenaltyMultiplier => deathPenaltyMultiplierEntry.Value; public bool autoRepair => autoRepairEntry.Value; public float guardianBuffDuration => guardianBuffDurationEntry.Value; public float guardianBuffCooldown => guardianBuffCooldownEntry.Value; public bool disableGuardianBuffAnimation => disableGuardianBuffAnimationEntry.Value; public bool autoEquipShield => autoEquipShieldEntry.Value; public bool autoUnequipShield => autoUnequipShieldEntry.Value; public bool skipIntro => skipIntroEntry.Value; public bool iHaveArrivedOnSpawn => iHaveArrivedOnSpawnEntry.Value; public bool queueWeaponChanges => queueWeaponChangesEntry.Value; public bool dontUnequipItemsWhenSwimming => dontUnequipItemsWhenSwimmingEntry.Value; public bool reequipItemsAfterSwimming => reequipItemsAfterSwimmingEntry.Value; public float fallDamageScalePercent => fallDamageScalePercentEntry.Value; public float maxFallDamage => maxFallDamageEntry.Value; public bool skipTutorials => skipTutorialsEntry.Value; public bool disableEncumbered => disableEncumberedEntry.Value; public bool autoPickUpWhenEncumbered => autoPickUpWhenEncumberedEntry.Value; public bool disableEightSecondTeleport => disableEightSecondTeleportEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Player", defaultValue: false, "Change false to true to enable this section."); baseMaximumWeightEntry = Bind(config, "Player", "baseMaximumWeight", 300f, "The base amount of carry weight of your character."); baseMegingjordBuffEntry = Bind(config, "Player", "baseMegingjordBuff", 150f, "Increase the buff you receive to your carry weight from Megingjord's girdle."); baseAutoPickUpRangeEntry = Bind(config, "Player", "baseAutoPickUpRange", 2f, "Increase auto pickup range of all items."); disableCameraShakeEntry = Bind(config, "Player", "disableCameraShake", defaultValue: false, "Disable all types of camera shake."); baseUnarmedDamageEntry = Bind(config, "Player", "baseUnarmedDamage", 70f, "The base unarmed damage multiplied by your skill level. 120 will result in a maximum of up to 12 damage when you have a skill level of 10."); cropNotifierEntry = Bind(config, "Player", "cropNotifier", defaultValue: false, "When changed to true, you will not be permitted to place a crop within the grow radius of another crop."); restSecondsPerComfortLevelEntry = Bind(config, "Player", "restSecondsPerComfortLevel", 60f, "How many seconds each comfort level contributes to the rested bonus."); deathPenaltyMultiplierEntry = Bind(config, "Player", "deathPenaltyMultiplier", 0f, "Change the death penalty in percentage, where higher will increase the death penalty and lower will reduce it.\nThis is a modifier value. 50 will increase it by 50%, -50 will reduce it by 50%."); autoRepairEntry = Bind(config, "Player", "autoRepair", defaultValue: false, "If set to true, this option will automatically repair your equipment when you interact with the appropriate workbench."); guardianBuffDurationEntry = Bind(config, "Player", "guardianBuffDuration", 300f, "Boss buff duration (seconds)"); guardianBuffCooldownEntry = Bind(config, "Player", "guardianBuffCooldown", 1200f, "Boss buff cooldown (seconds)"); disableGuardianBuffAnimationEntry = Bind(config, "Player", "disableGuardianBuffAnimation", defaultValue: false, "Disable the Guardian Buff animation"); autoEquipShieldEntry = Bind(config, "Player", "autoEquipShield", defaultValue: false, "If set to true, when equipping a one-handed weapon, the best shield from your inventory is automatically equipped.\n(Best is determined by highest block power)"); autoUnequipShieldEntry = Bind(config, "Player", "autoUnequipShield", defaultValue: false, "When unequipping a one-handed weapon also unequip shield from inventory."); skipIntroEntry = Bind(config, "Player", "skipIntro", defaultValue: false, "If set to true, you will always skip the intro of the game."); iHaveArrivedOnSpawnEntry = Bind(config, "Player", "iHaveArrivedOnSpawn", defaultValue: true, "If set to false, disables the \"I have arrived!\" message on player spawn."); queueWeaponChangesEntry = Bind(config, "Player", "queueWeaponChanges", defaultValue: false, "If set to true, weapon switches requested mid-attack will be carried out when the current attack is finished instead of being ignored."); dontUnequipItemsWhenSwimmingEntry = Bind(config, "Player", "dontUnequipItemsWhenSwimming", defaultValue: false, "If set to true, you will not put away / unequip your items when swimming."); reequipItemsAfterSwimmingEntry = Bind(config, "Player", "reequipItemsAfterSwimming", defaultValue: false, "If set to true, items will be re-equipped when you exit water after swimming (if they were hidden automatically)"); fallDamageScalePercentEntry = Bind(config, "Player", "fallDamageScalePercent", 0f, "This value represents how much the fall damage should be scaled in +/- %. This is a modifier value.\nThe value 50 would result in 50% increased fall damage. The value -50 would result in 50% reduced fall damage."); maxFallDamageEntry = Bind(config, "Player", "maxFallDamage", 100f, "Max fall damage. Game default is 100 (so with enough health, falls can't kill)."); skipTutorialsEntry = Bind(config, "Player", "skipTutorials", defaultValue: false, "If set to true, all tutorials will skip from now on. You can turn this config off and reset the tutorial (in the settings) at any time."); disableEncumberedEntry = Bind(config, "Player", "disableEncumbered", defaultValue: false, "Disable the encumbered state when you carry too many items (overweight)"); autoPickUpWhenEncumberedEntry = Bind(config, "Player", "autoPickUpWhenEncumbered", defaultValue: false, "Allow auto pickup of items when encumbered (overweight)"); disableEightSecondTeleportEntry = Bind(config, "Player", "disableEightSecondTeleport", defaultValue: false, "Shortens the teleport time as much as much as possible"); } } public class PlayerProjectileConfiguration : BaseConfig { private const string Section = "PlayerProjectile"; private ConfigEntry playerMinChargeVelocityMultiplierEntry; private ConfigEntry playerMaxChargeVelocityMultiplierEntry; private ConfigEntry playerMinChargeAccuracyMultiplierEntry; private ConfigEntry playerMaxChargeAccuracyMultiplierEntry; private ConfigEntry enableScaleWithSkillLevelEntry; public float playerMinChargeVelocityMultiplier => playerMinChargeVelocityMultiplierEntry.Value; public float playerMaxChargeVelocityMultiplier => playerMaxChargeVelocityMultiplierEntry.Value; public float playerMinChargeAccuracyMultiplier => playerMinChargeAccuracyMultiplierEntry.Value; public float playerMaxChargeAccuracyMultiplier => playerMaxChargeAccuracyMultiplierEntry.Value; public bool enableScaleWithSkillLevel => enableScaleWithSkillLevelEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "PlayerProjectile", defaultValue: false, "Change false to true to enable this section."); playerMinChargeVelocityMultiplierEntry = Bind(config, "PlayerProjectile", "playerMinChargeVelocityMultiplier", 0f, "Value of 50 would increase the minimum charge velocity from 2 to 3."); playerMaxChargeVelocityMultiplierEntry = Bind(config, "PlayerProjectile", "playerMaxChargeVelocityMultiplier", 0f, "Value of 50 would increase the maximum charge velocity (of Finwood bow) from 50 to 75."); playerMinChargeAccuracyMultiplierEntry = Bind(config, "PlayerProjectile", "playerMinChargeAccuracyMultiplier", 0f, "Value of (+)50 increase in accuracy will change the variance of arrows 20 degree to 10 degree at the point of minimum charge release."); playerMaxChargeAccuracyMultiplierEntry = Bind(config, "PlayerProjectile", "playerMaxChargeAccuracyMultiplier", 0f, "Value of (+)50 increase in accuracy will change the variance of arrows 1 degree to 0.5 degree at the point of maximum charge release."); enableScaleWithSkillLevelEntry = Bind(config, "PlayerProjectile", "enableScaleWithSkillLevel", defaultValue: false, "Enabling this option will linearly scale by skill level from the base values of the weapon to the modified values (according to multipliers above)."); } } public class ProcreationConfiguration : BaseConfig { private const string Section = "Procreation"; private ConfigEntry animalTypesEntry; private ConfigEntry loveInformationEntry; private ConfigEntry offspringInformationEntry; private ConfigEntry requiredLovePointsMultiplierEntry; private ConfigEntry pregnancyDurationMultiplierEntry; private ConfigEntry pregnancyChanceMultiplierEntry; private ConfigEntry partnerCheckRangeMultiplierEntry; private ConfigEntry ignoreHungerEntry; private ConfigEntry ignoreAlertedEntry; private ConfigEntry creatureLimitMultiplierEntry; private ConfigEntry maturityDurationMultiplierEntry; public AnimalType animalTypes => animalTypesEntry.Value; public bool loveInformation => loveInformationEntry.Value; public bool offspringInformation => offspringInformationEntry.Value; public float requiredLovePointsMultiplier => requiredLovePointsMultiplierEntry.Value; public float pregnancyDurationMultiplier => pregnancyDurationMultiplierEntry.Value; public float pregnancyChanceMultiplier => pregnancyChanceMultiplierEntry.Value; public float partnerCheckRangeMultiplier => partnerCheckRangeMultiplierEntry.Value; public bool ignoreHunger => ignoreHungerEntry.Value; public bool ignoreAlerted => ignoreAlertedEntry.Value; public float creatureLimitMultiplier => creatureLimitMultiplierEntry.Value; public float maturityDurationMultiplier => maturityDurationMultiplierEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Procreation", defaultValue: false, "Change false to true to enable this section."); animalTypesEntry = Bind(config, "Procreation", "animalTypes", AnimalType.All, "A comma-separated list of animals that can be tamed.\nValid types are: boar, hen, wolf, lox, asksvin, all, none"); loveInformationEntry = Bind(config, "Procreation", "loveInformation", defaultValue: false, "Set to true to display the amount of love points a creature has.\nWhen they become pregnant it will display the amount of time until they give birth."); offspringInformationEntry = Bind(config, "Procreation", "offspringInformation", defaultValue: false, "Set to true to display the amount of time a newborn creature will take to grow up."); requiredLovePointsMultiplierEntry = Bind(config, "Procreation", "requiredLovePointsMultiplier", 0f, "A multiplier for the amount of successful checks required for a creature to become pregnant\nA value of 100 will double the amount of successful checks required\n-100 will remove the requirement and the creature will instantly become pregnant."); pregnancyDurationMultiplierEntry = Bind(config, "Procreation", "pregnancyDurationMultiplier", 0f, "A multiplier for the time it takes for a creature to give birth after becoming pregnant.\nA value of 100 will double the pregnancy duration, -100 will cause the creature to give birth instantly."); pregnancyChanceMultiplierEntry = Bind(config, "Procreation", "pregnancyChanceMultiplier", 0f, "A multiplier for the chance of a creature gaining a love point.\nA value of 100 will double the chance of gaining a love point, -100 will prevent the creature from gaining a love point."); partnerCheckRangeMultiplierEntry = Bind(config, "Procreation", "partnerCheckRangeMultiplier", 0f, "A multiplier for the range that a creature can gain a love point from another creature in meters.\nA value of 100 will double the range, -100 will make them unable to procreate."); ignoreHungerEntry = Bind(config, "Procreation", "ignoreHunger", defaultValue: false, "Set to true to ignore hunger requirements while breeding.\nAnimals will not require food to initiate the breeding process."); ignoreAlertedEntry = Bind(config, "Procreation", "ignoreAlerted", defaultValue: false, "Set to true to allow animals to breed even when they are alerted\nFor more information see https://valheim.fandom.com/wiki/Creature_senses"); creatureLimitMultiplierEntry = Bind(config, "Procreation", "creatureLimitMultiplier", 0f, "A multiplier for the amount of offspring that can be nearby a creature before they will stop breeding.\nA value of 100 will double the amount of offspring that can be nearby, -100 will make them unable to breed."); maturityDurationMultiplierEntry = Bind(config, "Procreation", "maturityDurationMultiplier", 0f, "A multiplier for the amount of time it takes for a creature to grow up after being born. Does not apply to eggs.\nA value of 100 will double the time it takes to grow into an adult, -100 will cause the offspring to immediately mature."); } } public class SapCollectorConfiguration : BaseConfig { private const string Section = "SapCollector"; private ConfigEntry sapProductionSpeedEntry; private ConfigEntry maximumSapPerCollectorEntry; private ConfigEntry autoDepositEntry; private ConfigEntry autoDepositRangeEntry; private ConfigEntry showDurationEntry; public float sapProductionSpeed => sapProductionSpeedEntry.Value; public int maximumSapPerCollector => maximumSapPerCollectorEntry.Value; public bool autoDeposit => autoDepositEntry.Value; public float autoDepositRange => autoDepositRangeEntry.Value; public bool showDuration => showDurationEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "SapCollector", defaultValue: false, "Change false to true to enable this section."); sapProductionSpeedEntry = Bind(config, "SapCollector", "sapProductionSpeed", 60f, "Configure the speed at which the collector produces sap in seconds, 75 seconds is 1 in-game hour."); maximumSapPerCollectorEntry = Bind(config, "SapCollector", "maximumSapPerCollector", 10, "Configure the maximum amount of sap per collector"); autoDepositEntry = Bind(config, "SapCollector", "autoDeposit", defaultValue: false, "Instead of dropping the items, they will be placed inside the nearest nearby chests."); autoDepositRangeEntry = Bind(config, "SapCollector", "autoDepositRange", 10f, 1f, 50f, "The range of the chest detection for the auto deposit feature.\nMaximum is 50"); showDurationEntry = Bind(config, "SapCollector", "showDuration", defaultValue: false, "Display the time until the collector produces sap, on hover."); } } public class ServerConfiguration : BaseConfig { private const string Section = "Server"; private ConfigEntry maxPlayersEntry; private ConfigEntry disableServerPasswordEntry; private ConfigEntry enforceModEntry; private ConfigEntry serverSyncsConfigEntry; public int maxPlayers => maxPlayersEntry.Value; public bool disableServerPassword => disableServerPasswordEntry.Value; public bool enforceMod => enforceModEntry.Value; public bool serverSyncsConfig => serverSyncsConfigEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Server", defaultValue: true, "Change false to true to enable this section."); maxPlayersEntry = Bind(config, "Server", "maxPlayers", 10, 1, 32, "Modify the maximum amount of players on your Server."); disableServerPasswordEntry = Bind(config, "Server", "disableServerPassword", defaultValue: false, "Removes the requirement to have a server password."); enforceModEntry = Bind(config, "Server", "enforceMod", defaultValue: true, "This settings add a version control check to make sure that people that try to join your game or the server you try to join has V+ installed\nWE HEAVILY RECOMMEND TO NEVER DISABLE THIS!"); serverSyncsConfigEntry = Bind(config, "Server", "serverSyncsConfig", defaultValue: true, "Changes whether the server will force it's config on clients that connect. Only affects servers.\nWE HEAVILY RECOMMEND TO NEVER DISABLE THIS!"); } } public class ShieldConfiguration : BaseConfig { private const string Section = "Shields"; private ConfigEntry blockRatingEntry; public float blockRating => blockRatingEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Shields", defaultValue: false, "Change false to true to enable this section, if you set this to false the mode will not be accessible."); blockRatingEntry = Bind(config, "Shields", "blockRating", 0f, "Increase or decrease the block value on all shields in %. -50 would be 50% less block rating, 50 would be 50% more block rating."); } } public class ShieldGeneratorConfiguration : BaseConfig { private const string Section = "ShieldGenerator"; private ConfigEntry infiniteFuelEntry; private ConfigEntry autoFuelEntry; private ConfigEntry ignorePrivateAreaCheckEntry; private ConfigEntry autoRangeEntry; public bool infiniteFuel => infiniteFuelEntry.Value; public bool autoFuel => autoFuelEntry.Value; public bool ignorePrivateAreaCheck => ignorePrivateAreaCheckEntry.Value; public float autoRange => autoRangeEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "ShieldGenerator", defaultValue: false, "Change false to true to enable this section."); infiniteFuelEntry = Bind(config, "ShieldGenerator", "infiniteFuel", defaultValue: false, "If set to true, the shield generator will stay at max fuel level, without consuming any fuel."); autoFuelEntry = Bind(config, "ShieldGenerator", "autoFuel", defaultValue: false, "The shield generator will fuel itself from nearby chests."); ignorePrivateAreaCheckEntry = Bind(config, "ShieldGenerator", "ignorePrivateAreaCheck", defaultValue: true, "This option allows the shield generator to fuel itself from chests that it doesn't share a warded area with.\nFor convenience, we recommend this to be set to true."); autoRangeEntry = Bind(config, "ShieldGenerator", "autoRange", 10f, 1f, 50f, "The range of the chest detection for the auto fuel feature.\nMaximum is 50"); } } public class ShipConfiguration : BaseConfig { private const string Section = "Ship"; private ConfigEntry forwardSpeedEntry; private ConfigEntry backwardSpeedEntry; private ConfigEntry rudderSpeedEntry; private ConfigEntry steerForceEntry; private ConfigEntry waterImpactDamageEntry; public float forwardSpeed => forwardSpeedEntry.Value; public float backwardSpeed => backwardSpeedEntry.Value; public float rudderSpeed => rudderSpeedEntry.Value; public float steerForce => steerForceEntry.Value; public float waterImpactDamage => waterImpactDamageEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Ship", defaultValue: false, "Change false to true to enable this section."); forwardSpeedEntry = Bind(config, "Ship", "forwardSpeed", 0f, "This value determines the constant amount of force applied to the ship when sailing forward.\nA multiplier of 50 will result in the ship being 50% faster, -50 will result in the ship being 50% slower."); backwardSpeedEntry = Bind(config, "Ship", "backwardSpeed", 0f, "This value determines the amount of force applied to the ship when sailing backward.\nA multiplier of 50 will result in the ship moving backward 50% faster, -50 will result in the opposite."); rudderSpeedEntry = Bind(config, "Ship", "rudderSpeed", 0f, "This value determines the speed of turning the wheel of the ship.\nA multiplier of 50 will result in the wheel turning 50% faster, -50 will result in the opposite."); steerForceEntry = Bind(config, "Ship", "steerForce", 0f, "This value determines the force applied to the ship when steering.\nA multiplier of 50 will result in the ship turning 50% faster, -50 will result in the opposite."); waterImpactDamageEntry = Bind(config, "Ship", "waterImpactDamage", 0f, "This value determines the amount of damage the ship takes while sailing.\nA multiplier of 50 will result in the ship taking 50% more damage, -50 will result in the opposite."); } } public class SmelterConfiguration : BaseConfig { private const string Section = "Smelter"; private ConfigEntry maximumOreEntry; private ConfigEntry maximumCoalEntry; private ConfigEntry coalUsedPerProductEntry; private ConfigEntry productionSpeedEntry; private ConfigEntry autoDepositEntry; private ConfigEntry autoFuelEntry; private ConfigEntry ignorePrivateAreaCheckEntry; private ConfigEntry autoRangeEntry; public int maximumOre => maximumOreEntry.Value; public int maximumCoal => maximumCoalEntry.Value; public int coalUsedPerProduct => coalUsedPerProductEntry.Value; public float productionSpeed => productionSpeedEntry.Value; public bool autoDeposit => autoDepositEntry.Value; public bool autoFuel => autoFuelEntry.Value; public bool ignorePrivateAreaCheck => ignorePrivateAreaCheckEntry.Value; public float autoRange => autoRangeEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Smelter", defaultValue: false, "Change false to true to enable this section."); maximumOreEntry = Bind(config, "Smelter", "maximumOre", 10, "Maximum amount of ore in a Smelter."); maximumCoalEntry = Bind(config, "Smelter", "maximumCoal", 20, "Maximum amount of coal in a Smelter."); coalUsedPerProductEntry = Bind(config, "Smelter", "coalUsedPerProduct", 2, "The total amount of coal used to produce a single smelted ingot."); productionSpeedEntry = Bind(config, "Smelter", "productionSpeed", 30f, "The time it takes for the Smelter to produce a single ingot in seconds."); autoDepositEntry = Bind(config, "Smelter", "autoDeposit", defaultValue: false, "Instead of dropping the items, they will be placed inside the nearest nearby chests."); autoFuelEntry = Bind(config, "Smelter", "autoFuel", defaultValue: false, "The Smelter will pull coal and raw materials from nearby chests to be automatically added to it when its empty."); ignorePrivateAreaCheckEntry = Bind(config, "Smelter", "ignorePrivateAreaCheck", defaultValue: true, "This option prevents the Smelter to pull items from warded areas if it isn't placed inside of it.\nFor convenience, we recommend this to be set to true."); autoRangeEntry = Bind(config, "Smelter", "autoRange", 10f, 1f, 50f, "The range of the chest detection for the auto deposit and auto fuel features.\nMaximum is 50"); } } public class SpinningWheelConfiguration : BaseConfig { private const string Section = "SpinningWheel"; private ConfigEntry maximumFlaxEntry; private ConfigEntry productionSpeedEntry; private ConfigEntry autoDepositEntry; private ConfigEntry autoFuelEntry; private ConfigEntry ignorePrivateAreaCheckEntry; private ConfigEntry autoRangeEntry; public int maximumFlax => maximumFlaxEntry.Value; public float productionSpeed => productionSpeedEntry.Value; public bool autoDeposit => autoDepositEntry.Value; public bool autoFuel => autoFuelEntry.Value; public bool ignorePrivateAreaCheck => ignorePrivateAreaCheckEntry.Value; public float autoRange => autoRangeEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "SpinningWheel", defaultValue: false, "Change false to true to enable this section."); maximumFlaxEntry = Bind(config, "SpinningWheel", "maximumFlax", 50, "Maximum amount of flax in a spinning wheel."); productionSpeedEntry = Bind(config, "SpinningWheel", "productionSpeed", 30f, "The time it takes for the spinning wheel to produce linen thread."); autoDepositEntry = Bind(config, "SpinningWheel", "autoDeposit", defaultValue: false, "Instead of dropping the items, they will be placed inside the nearest nearby chests."); autoFuelEntry = Bind(config, "SpinningWheel", "autoFuel", defaultValue: false, "The Spinning Wheel will pull flax from nearby chests to be automatically added to it when its empty."); ignorePrivateAreaCheckEntry = Bind(config, "SpinningWheel", "ignorePrivateAreaCheck", defaultValue: true, "This option prevents the Spinning Wheel to pull items from warded areas if it isn't placed inside of it.\nFor convenience, we recommend this to be set to true."); autoRangeEntry = Bind(config, "SpinningWheel", "autoRange", 10f, 1f, 50f, "The range of the chest detection for the auto deposit and auto fuel features\nMaximum is 50"); } } public class StaminaConfiguration : BaseConfig { private const string Section = "Stamina"; private ConfigEntry dodgeStaminaUsageEntry; private ConfigEntry encumberedStaminaDrainEntry; private ConfigEntry jumpStaminaDrainEntry; private ConfigEntry runStaminaDrainEntry; private ConfigEntry sneakStaminaDrainEntry; private ConfigEntry staminaRegenEntry; private ConfigEntry staminaRegenDelayEntry; private ConfigEntry swimStaminaDrainEntry; public float dodgeStaminaUsage => dodgeStaminaUsageEntry.Value; public float encumberedStaminaDrain => encumberedStaminaDrainEntry.Value; public float jumpStaminaDrain => jumpStaminaDrainEntry.Value; public float runStaminaDrain => runStaminaDrainEntry.Value; public float sneakStaminaDrain => sneakStaminaDrainEntry.Value; public float staminaRegen => staminaRegenEntry.Value; public float staminaRegenDelay => staminaRegenDelayEntry.Value; public float swimStaminaDrain => swimStaminaDrainEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Stamina", defaultValue: false, "Change false to true to enable this section. This section contains modifiers.\nModifiers are increases and reduction in percent declared by 50, or -50."); dodgeStaminaUsageEntry = Bind(config, "Stamina", "dodgeStaminaUsage", 0f, "Changes the amount of stamina cost of using the dodge roll by %"); encumberedStaminaDrainEntry = Bind(config, "Stamina", "encumberedStaminaDrain", 0f, "Changes the stamina drain of being overweight by %"); jumpStaminaDrainEntry = Bind(config, "Stamina", "jumpStaminaDrain", 0f, "Changes the stamina cost of jumping by %"); runStaminaDrainEntry = Bind(config, "Stamina", "runStaminaDrain", 0f, "Changes the stamina cost of running by %"); sneakStaminaDrainEntry = Bind(config, "Stamina", "sneakStaminaDrain", 0f, "Changes the stamina drain by sneaking by %"); staminaRegenEntry = Bind(config, "Stamina", "staminaRegen", 0f, "Changes the total amount of stamina recovered per second by %"); staminaRegenDelayEntry = Bind(config, "Stamina", "staminaRegenDelay", 0f, "Changes the delay until stamina regeneration sets in by %"); swimStaminaDrainEntry = Bind(config, "Stamina", "swimStaminaDrain", 0f, "Changes the stamina drain of swimming by %"); } } public class StaminaUsageConfiguration : BaseConfig { private const string Section = "StaminaUsage"; private ConfigEntry axesEntry; private ConfigEntry bowsEntry; private ConfigEntry blockingEntry; private ConfigEntry clubsEntry; private ConfigEntry knivesEntry; private ConfigEntry pickaxesEntry; private ConfigEntry polearmsEntry; private ConfigEntry spearsEntry; private ConfigEntry swordsEntry; private ConfigEntry unarmedEntry; private ConfigEntry hammerEntry; private ConfigEntry hoeEntry; private ConfigEntry cultivatorEntry; private ConfigEntry fishingEntry; public float axes => axesEntry.Value; public float bows => bowsEntry.Value; public float blocking => blockingEntry.Value; public float clubs => clubsEntry.Value; public float knives => knivesEntry.Value; public float pickaxes => pickaxesEntry.Value; public float polearms => polearmsEntry.Value; public float spears => spearsEntry.Value; public float swords => swordsEntry.Value; public float unarmed => unarmedEntry.Value; public float hammer => hammerEntry.Value; public float hoe => hoeEntry.Value; public float cultivator => cultivatorEntry.Value; public float fishing => fishingEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "StaminaUsage", defaultValue: false, "Change false to true to enable this section. This section contains modifiers.\nModifiers are increases and reduction in percent declared by 50, or -50."); axesEntry = Bind(config, "StaminaUsage", "axes", 0f, "Each of these values change the respective tool in stamina usage by increases and reduction in percent declared by 50, or -50."); bowsEntry = Bind(config, "StaminaUsage", "bows", 0f, "Each of these values change the respective tool in stamina usage by increases and reduction in percent declared by 50, or -50."); blockingEntry = Bind(config, "StaminaUsage", "blocking", 0f, "Each of these values change the respective tool in stamina usage by increases and reduction in percent declared by 50, or -50."); clubsEntry = Bind(config, "StaminaUsage", "clubs", 0f, "Each of these values change the respective tool in stamina usage by increases and reduction in percent declared by 50, or -50."); knivesEntry = Bind(config, "StaminaUsage", "knives", 0f, "Each of these values change the respective tool in stamina usage by increases and reduction in percent declared by 50, or -50."); pickaxesEntry = Bind(config, "StaminaUsage", "pickaxes", 0f, "Each of these values change the respective tool in stamina usage by increases and reduction in percent declared by 50, or -50."); polearmsEntry = Bind(config, "StaminaUsage", "polearms", 0f, "Each of these values change the respective tool in stamina usage by increases and reduction in percent declared by 50, or -50."); spearsEntry = Bind(config, "StaminaUsage", "spears", 0f, "Each of these values change the respective tool in stamina usage by increases and reduction in percent declared by 50, or -50."); swordsEntry = Bind(config, "StaminaUsage", "swords", 0f, "Each of these values change the respective tool in stamina usage by increases and reduction in percent declared by 50, or -50."); unarmedEntry = Bind(config, "StaminaUsage", "unarmed", 0f, "Each of these values change the respective tool in stamina usage by increases and reduction in percent declared by 50, or -50."); hammerEntry = Bind(config, "StaminaUsage", "hammer", 0f, "Each of these values change the respective tool in stamina usage by increases and reduction in percent declared by 50, or -50."); hoeEntry = Bind(config, "StaminaUsage", "hoe", 0f, "Each of these values change the respective tool in stamina usage by increases and reduction in percent declared by 50, or -50."); cultivatorEntry = Bind(config, "StaminaUsage", "cultivator", 0f, "Each of these values change the respective tool in stamina usage by increases and reduction in percent declared by 50, or -50."); fishingEntry = Bind(config, "StaminaUsage", "fishing", 0f, "Each of these values change the respective tool in stamina usage by increases and reduction in percent declared by 50, or -50."); } } public class StructuralIntegrityConfiguration : BaseConfig { private const string Section = "StructuralIntegrity"; private ConfigEntry woodEntry; private ConfigEntry stoneEntry; private ConfigEntry ironEntry; private ConfigEntry hardWoodEntry; private ConfigEntry marbleEntry; private ConfigEntry ashstoneEntry; private ConfigEntry ancientEntry; private ConfigEntry iceEntry; private ConfigEntry timberwoodEntry; private ConfigEntry disableStructuralIntegrityEntry; private ConfigEntry disableDamageToPlayerStructuresEntry; private ConfigEntry disableDamageToPlayerBoatsEntry; private ConfigEntry disableDamageToPlayerCartsEntry; private ConfigEntry disableWaterDamageToPlayerBoatsEntry; private ConfigEntry disableWaterDamageToPlayerCartsEntry; public float wood => woodEntry.Value; public float stone => stoneEntry.Value; public float iron => ironEntry.Value; public float hardWood => hardWoodEntry.Value; public float marble => marbleEntry.Value; public float ashstone => ashstoneEntry.Value; public float ancient => ancientEntry.Value; public float ice => iceEntry.Value; public float timberwood => timberwoodEntry.Value; public bool disableStructuralIntegrity => disableStructuralIntegrityEntry.Value; public bool disableDamageToPlayerStructures => disableDamageToPlayerStructuresEntry.Value; public bool disableDamageToPlayerBoats => disableDamageToPlayerBoatsEntry.Value; public bool disableDamageToPlayerCarts => disableDamageToPlayerCartsEntry.Value; public bool disableWaterDamageToPlayerBoats => disableWaterDamageToPlayerBoatsEntry.Value; public bool disableWaterDamageToPlayerCarts => disableWaterDamageToPlayerCartsEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "StructuralIntegrity", defaultValue: false, "Change false to true to enable this section."); woodEntry = Bind(config, "StructuralIntegrity", "wood", 0f, 0f, 100f, "Each of these values reduce the loss of structural integrity by distance by % less.\nThe value 100 would result in disabled structural integrity over distance, does not allow for placement in free air without disableStructuralIntegrity."); stoneEntry = Bind(config, "StructuralIntegrity", "stone", 0f, 0f, 100f, "Each of these values reduce the loss of structural integrity by distance by % less.\nThe value 100 would result in disabled structural integrity over distance, does not allow for placement in free air without disableStructuralIntegrity."); ironEntry = Bind(config, "StructuralIntegrity", "iron", 0f, 0f, 100f, "Each of these values reduce the loss of structural integrity by distance by % less.\nThe value 100 would result in disabled structural integrity over distance, does not allow for placement in free air without disableStructuralIntegrity."); hardWoodEntry = Bind(config, "StructuralIntegrity", "hardWood", 0f, 0f, 100f, "Each of these values reduce the loss of structural integrity by distance by % less.\nThe value 100 would result in disabled structural integrity over distance, does not allow for placement in free air without disableStructuralIntegrity."); marbleEntry = Bind(config, "StructuralIntegrity", "marble", 0f, 0f, 100f, "Each of these values reduce the loss of structural integrity by distance by % less.\nThe value 100 would result in disabled structural integrity over distance, does not allow for placement in free air without disableStructuralIntegrity."); ashstoneEntry = Bind(config, "StructuralIntegrity", "ashstone", 0f, 0f, 100f, "Each of these values reduce the loss of structural integrity by distance by % less.\nThe value 100 would result in disabled structural integrity over distance, does not allow for placement in free air without disableStructuralIntegrity."); ancientEntry = Bind(config, "StructuralIntegrity", "ancient", 0f, 0f, 100f, "Each of these values reduce the loss of structural integrity by distance by % less.\nThe value 100 would result in disabled structural integrity over distance, does not allow for placement in free air without disableStructuralIntegrity."); iceEntry = Bind(config, "StructuralIntegrity", "ice", 0f, 0f, 100f, "Each of these values reduce the loss of structural integrity by distance by % less.\nThe value 100 would result in disabled structural integrity over distance, does not allow for placement in free air without disableStructuralIntegrity."); timberwoodEntry = Bind(config, "StructuralIntegrity", "timberwood", 0f, 0f, 100f, "Each of these values reduce the loss of structural integrity by distance by % less.\nThe value 100 would result in disabled structural integrity over distance, does not allow for placement in free air without disableStructuralIntegrity."); disableStructuralIntegrityEntry = Bind(config, "StructuralIntegrity", "disableStructuralIntegrity", defaultValue: false, "Disables the entire structural integrity system and allows for placement in free air, does not prevent building damage."); disableDamageToPlayerStructuresEntry = Bind(config, "StructuralIntegrity", "disableDamageToPlayerStructures", defaultValue: false, "Disables any damage from anything to all player built structures. Does not prevent damage from structural integrity."); disableDamageToPlayerBoatsEntry = Bind(config, "StructuralIntegrity", "disableDamageToPlayerBoats", defaultValue: false, "Disables any damage from anything to all player built boats."); disableDamageToPlayerCartsEntry = Bind(config, "StructuralIntegrity", "disableDamageToPlayerCarts", defaultValue: false, "Disables any damage from anything to all player built carts."); disableWaterDamageToPlayerBoatsEntry = Bind(config, "StructuralIntegrity", "disableWaterDamageToPlayerBoats", defaultValue: false, "Disables water force damage to all player built boats."); disableWaterDamageToPlayerCartsEntry = Bind(config, "StructuralIntegrity", "disableWaterDamageToPlayerCarts", defaultValue: false, "Disables water force damage to all player built carts."); } } public class TameableConfiguration : BaseConfig { private const string Section = "Tameable"; private ConfigEntry animalTypesEntry; private ConfigEntry mortalityEntry; private ConfigEntry ownerDamageOverrideEntry; private ConfigEntry stunRecoveryTimeEntry; private ConfigEntry stunInformationEntry; private ConfigEntry tameTimeMultiplierEntry; private ConfigEntry tameBoostMultiplierEntry; private ConfigEntry tameBoostRangeMultiplierEntry; private ConfigEntry ignoreHungerEntry; private ConfigEntry ignoreAlertedEntry; public AnimalType animalTypes => animalTypesEntry.Value; public int mortality => mortalityEntry.Value; public bool ownerDamageOverride => ownerDamageOverrideEntry.Value; public float stunRecoveryTime => stunRecoveryTimeEntry.Value; public bool stunInformation => stunInformationEntry.Value; public float tameTimeMultiplier => tameTimeMultiplierEntry.Value; public float tameBoostMultiplier => tameBoostMultiplierEntry.Value; public float tameBoostRangeMultiplier => tameBoostRangeMultiplierEntry.Value; public bool ignoreHunger => ignoreHungerEntry.Value; public bool ignoreAlerted => ignoreAlertedEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Tameable", defaultValue: false, "Change false to true to enable this section."); animalTypesEntry = Bind(config, "Tameable", "animalTypes", AnimalType.All, "A comma-separated list of animals that can be tamed.\nValid types are: boar, hen, wolf, lox, asksvin, all, none"); mortalityEntry = Bind(config, "Tameable", "mortality", 0, 0, 2, "Modify what happens when a tamed creature is attacked.\n0 = normal, 1 = essential(deadly attacks stun instead of kill, tamed creatures can still die rarely), 2 = immortal."); ownerDamageOverrideEntry = Bind(config, "Tameable", "ownerDamageOverride", defaultValue: true, "This will circumvent the mortality setting, so even if tamed creatures are immortal, players can still kill them with a butcher knife.\nFor this option to work you need to have mortality to set to either essential or immortal."); stunRecoveryTimeEntry = Bind(config, "Tameable", "stunRecoveryTime", 10f, "How long it takes for a tamed creature to recover if mortality is set to 1(essential) and they are stunned."); stunInformationEntry = Bind(config, "Tameable", "stunInformation", defaultValue: false, "If the tamed creature is recovering from a stun, then add Stunned to the hover text on mouse over."); tameTimeMultiplierEntry = Bind(config, "Tameable", "tameTimeMultiplier", 0f, "A multiplier for the amount of time it takes to fully tame a creature in seconds.\nA value of 100 will double the time it takes to tame a creature, -100 will instantly tame the creature."); tameBoostMultiplierEntry = Bind(config, "Tameable", "tameBoostMultiplier", 0f, "A multiplier for the taming bonus provided by the Brew of animal whispers\nA value of 100 will double the taming bonus, -100 will prevent a creature from taming while the buff is in effect."); tameBoostRangeMultiplierEntry = Bind(config, "Tameable", "tameBoostRangeMultiplier", 0f, "A multiplier for the range that a taming boost can be applied to a creature.\nA value of 100 will double the range, -100 will prevent the buff from being applied."); ignoreHungerEntry = Bind(config, "Tameable", "ignoreHunger", defaultValue: false, "Set to true to ignore hunger requirements while taming.\nStill requires you food to initiate the taming process."); ignoreAlertedEntry = Bind(config, "Tameable", "ignoreAlerted", defaultValue: false, "Set to true to allow taming even when the creature is alerted.\nFor more information see https://valheim.fandom.com/wiki/Creature_senses"); } } public class TimeConfiguration : BaseConfig { private const string Section = "Time"; private ConfigEntry forcePartOfDayEntry; private ConfigEntry forcePartOfDayTimeEntry; private ConfigEntry totalDayTimeInSecondsEntry; private ConfigEntry nightPercentEntry; public bool forcePartOfDay => forcePartOfDayEntry.Value; public float forcePartOfDayTime => forcePartOfDayTimeEntry.Value; public float totalDayTimeInSeconds => totalDayTimeInSecondsEntry.Value; public float nightPercent => nightPercentEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Time", defaultValue: false, "Change false to true to enable this section."); forcePartOfDayEntry = Bind(config, "Time", "forcePartOfDay", defaultValue: false, "Enables forcing a specific time of day. This option disables other day duration settings."); forcePartOfDayTimeEntry = Bind(config, "Time", "forcePartOfDayTime", 0.5f, 0f, 1f, "The part of day the time should be frozen to. 0 would be middle of night, 0.5 will be middle of day"); totalDayTimeInSecondsEntry = Bind(config, "Time", "totalDayTimeInSeconds", 1800f, "Sets the duration of a whole day. This will affect the day count and may change time of day once after activation (new Worlds are not affected)."); nightPercentEntry = Bind(config, "Time", "nightPercent", 30f, 0f, 200f, "What percent of time is night. 0 is all daytime, 100 is all nighttime. Default is 30."); } } public class TurretConfiguration : BaseConfig { private const string Section = "Turret"; private ConfigEntry ignorePlayersEntry; private ConfigEntry unlimitedAmmoEntry; private ConfigEntry turnRateEntry; private ConfigEntry attackCooldownEntry; private ConfigEntry viewDistanceEntry; private ConfigEntry projectileVelocityEntry; private ConfigEntry projectileAccuracyEntry; public bool ignorePlayers => ignorePlayersEntry.Value; public bool unlimitedAmmo => unlimitedAmmoEntry.Value; public float turnRate => turnRateEntry.Value; public float attackCooldown => attackCooldownEntry.Value; public float viewDistance => viewDistanceEntry.Value; public float projectileVelocity => projectileVelocityEntry.Value; public float projectileAccuracy => projectileAccuracyEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Turret", defaultValue: false, "Change false to true to enable this section."); ignorePlayersEntry = Bind(config, "Turret", "ignorePlayers", defaultValue: false, "Change false to true to make the balista ignore players."); unlimitedAmmoEntry = Bind(config, "Turret", "unlimitedAmmo", defaultValue: false, "Change false to true to prevent consumption of Balista ammo."); turnRateEntry = Bind(config, "Turret", "turnRate", 0f, "This value determines the rate at which the balista turns. A multiplier of -50 will result in the balista turning 50% faster."); attackCooldownEntry = Bind(config, "Turret", "attackCooldown", 0f, "This value determines the rate of fire of the balista. A multiplier of -50 will result in the balista shooting 100% faster."); viewDistanceEntry = Bind(config, "Turret", "viewDistance", 0f, "This value determines the distance a balista can see targets. A multiplier of 50 will result in the balista seeing 50% further."); projectileVelocityEntry = Bind(config, "Turret", "projectileVelocity", 0f, "This value determines the velocity of the projectiles a ballista fires. A multiplier of 50 will result in the projectile velocity being 50% faster."); projectileAccuracyEntry = Bind(config, "Turret", "projectileAccuracy", 0f, "This value determines the accuracy of the projectiles a ballista fires. A multiplier of 50 will result in the projectile being 50% more accurate."); } } public class WagonConfiguration : BaseConfig { private const string Section = "Wagon"; private ConfigEntry wagonExtraMassFromItemsEntry; private ConfigEntry wagonBaseMassEntry; public float wagonExtraMassFromItems => wagonExtraMassFromItemsEntry.Value; public float wagonBaseMass => wagonBaseMassEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Wagon", defaultValue: false, "Change false to true to enable this section."); wagonExtraMassFromItemsEntry = Bind(config, "Wagon", "wagonExtraMassFromItems", 0f, "This value changes the physical weight of wagons by +/- more/less from item weight inside.\nThe value 50 would increase the weight by 50% more. The value -100 would remove the entire extra weight."); wagonBaseMassEntry = Bind(config, "Wagon", "wagonBaseMass", 20f, "Change the base wagon physical mass of the wagon object.\nThis is essentially the base weight of a cart."); } } public class WardConfiguration : BaseConfig { private const string Section = "Ward"; private ConfigEntry wardRangeEntry; private ConfigEntry wardEnemySpawnRangeEntry; public float wardRange => wardRangeEntry.Value; public float wardEnemySpawnRange => wardEnemySpawnRangeEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Ward", defaultValue: false, "Change false to true to enable this section."); wardRangeEntry = Bind(config, "Ward", "wardRange", 20f, "The range of wards by meters."); wardEnemySpawnRangeEntry = Bind(config, "Ward", "wardEnemySpawnRange", 0f, "Set the enemy spawn radius around wards in meters\nThis value equals wardRange if its set to 0."); } } public class WindmillConfiguration : BaseConfig { private const string Section = "Windmill"; private ConfigEntry maximumBarleyEntry; private ConfigEntry productionSpeedEntry; private ConfigEntry ignoreWindIntensityEntry; private ConfigEntry autoDepositEntry; private ConfigEntry autoFuelEntry; private ConfigEntry ignorePrivateAreaCheckEntry; private ConfigEntry autoRangeEntry; public int maximumBarley => maximumBarleyEntry.Value; public float productionSpeed => productionSpeedEntry.Value; public bool ignoreWindIntensity => ignoreWindIntensityEntry.Value; public bool autoDeposit => autoDepositEntry.Value; public bool autoFuel => autoFuelEntry.Value; public bool ignorePrivateAreaCheck => ignorePrivateAreaCheckEntry.Value; public float autoRange => autoRangeEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Windmill", defaultValue: false, "Change false to true to enable this section."); maximumBarleyEntry = Bind(config, "Windmill", "maximumBarley", 50, "Maximum amount of barley in a windmill."); productionSpeedEntry = Bind(config, "Windmill", "productionSpeed", 10f, "The time it takes for the windmill to produce a single ingot in seconds."); ignoreWindIntensityEntry = Bind(config, "Windmill", "ignoreWindIntensity", defaultValue: false, "Ignore wind intensity so it always takes the production speed value to process one barley."); autoDepositEntry = Bind(config, "Windmill", "autoDeposit", defaultValue: false, "Instead of dropping the items, they will be placed inside the nearest nearby chests."); autoFuelEntry = Bind(config, "Windmill", "autoFuel", defaultValue: false, "The Windmill will pull barley from nearby chests to be automatically added to it when its empty."); ignorePrivateAreaCheckEntry = Bind(config, "Windmill", "ignorePrivateAreaCheck", defaultValue: true, "This option prevents the Windmill to pull items from warded areas if it isn't placed inside of it.\nFor convenience, we recommend this to be set to true."); autoRangeEntry = Bind(config, "Windmill", "autoRange", 10f, 1f, 50f, "The range of the chest detection for the auto deposit and auto fuel features.\nMaximum is 50"); } } public class WispSpawnerConfiguration : BaseConfig { private const string Section = "WispSpawner"; private ConfigEntry maximumWispsEntry; private ConfigEntry onlySpawnAtNightEntry; private ConfigEntry wispSpawnIntervalMultiplierEntry; private ConfigEntry wispSpawnChanceMultiplierEntry; public int maximumWisps => maximumWispsEntry.Value; public bool onlySpawnAtNight => onlySpawnAtNightEntry.Value; public float wispSpawnIntervalMultiplier => wispSpawnIntervalMultiplierEntry.Value; public float wispSpawnChanceMultiplier => wispSpawnChanceMultiplierEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "WispSpawner", defaultValue: false, "Change false to true to enable this section."); maximumWispsEntry = Bind(config, "WispSpawner", "maximumWisps", 3, "This value determines the maximum amount of Wisp per spawner."); onlySpawnAtNightEntry = Bind(config, "WispSpawner", "onlySpawnAtNight", defaultValue: true, "This value determines if the Wisps can spawn during the day."); wispSpawnIntervalMultiplierEntry = Bind(config, "WispSpawner", "wispSpawnIntervalMultiplier", 0f, "This value determines the rate at which the Wisps try to spawn. A multiplier of -50 will result in a wisp trying to spawn every 2.5 seconds (5 seconds by default)."); wispSpawnChanceMultiplierEntry = Bind(config, "WispSpawner", "wispSpawnChanceMultiplier", 0f, "This value determines the chance of a Wisp to spawn. A multiplier of 200 will result in a 100% wisp spawn chance."); } } public class WorkbenchConfiguration : BaseConfig { private const string Section = "Workbench"; private ConfigEntry workbenchRangeEntry; private ConfigEntry workbenchEnemySpawnRangeEntry; private ConfigEntry workbenchAttachmentRangeEntry; private ConfigEntry disableRoofCheckEntry; public float workbenchRange => workbenchRangeEntry.Value; public float workbenchEnemySpawnRange => workbenchEnemySpawnRangeEntry.Value; public float workbenchAttachmentRange => workbenchAttachmentRangeEntry.Value; public bool disableRoofCheck => disableRoofCheckEntry.Value; public override void Bind(ConfigFile config) { BindEnabled(config, "Workbench", defaultValue: false, "Change false to true to enable this section."); workbenchRangeEntry = Bind(config, "Workbench", "workbenchRange", 20f, "Set the workbench radius in meters."); workbenchEnemySpawnRangeEntry = Bind(config, "Workbench", "workbenchEnemySpawnRange", 0f, "Set the enemy spawn radius around workbenches in meters\nThis value equals workbenchRange if its set to 0."); workbenchAttachmentRangeEntry = Bind(config, "Workbench", "workbenchAttachmentRange", 5f, "Sets the workbench attachment (e.g. anvil) radius."); disableRoofCheckEntry = Bind(config, "Workbench", "disableRoofCheck", defaultValue: false, "Disables the roof and exposure requirement to use a workbench."); } } }