Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of TouchGrass v1.0.4
TouchGrass.dll
Decompiled 5 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using ServerSync; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("TouchGrass")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("sighsorry")] [assembly: AssemblyProduct("TouchGrass")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")] [assembly: AssemblyFileVersion("1.0.4")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.4.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace TouchGrass { [BepInPlugin("sighsorry.TouchGrass", "TouchGrass", "1.0.4")] public class TouchGrassPlugin : BaseUnityPlugin { public enum Toggle { On = 1, Off = 0 } public enum FatigueStatusEffectDisplay { Off, Detailed } public enum TrainingDummyDamageType { Blunt, Slash, Pierce, Fire, Frost, Lightning, Poison, Spirit } public enum TrainingMeterDisplay { Off, Detailed } internal const string ModName = "TouchGrass"; internal const string ModVersion = "1.0.4"; internal const string Author = "sighsorry"; private const string ModGUID = "sighsorry.TouchGrass"; private static string ConfigFileName = "sighsorry.TouchGrass.cfg"; private static string ConfigFileFullPath; internal static string ConnectionError; private readonly Harmony _harmony = new Harmony("sighsorry.TouchGrass"); public static readonly ManualLogSource TouchGrassLogger; private static readonly ConfigSync ConfigSync; private FileSystemWatcher? _watcher; private readonly object _reloadLock = new object(); private DateTime _lastConfigReloadTime; private const long RELOAD_DELAY = 10000000L; private static ConfigEntry<Toggle> _serverConfigLocked; internal static ConfigEntry<float> _locationFullEfficiencySeconds; internal static ConfigEntry<float> _locationFadeSeconds; internal static ConfigEntry<float> _locationMinimumMultiplier; internal static ConfigEntry<float> _stationaryRadius; internal static ConfigEntry<Toggle> _fatigueStationarySkillGains; internal static ConfigEntry<FatigueStatusEffectDisplay> _fatigueStatusEffectDisplay; internal static ConfigEntry<float> _trainingDummyHealth; internal static ConfigEntry<float> _trainingDummyCrowdingRadius; internal static ConfigEntry<int> _trainingDummyCrowdingMaxCount; internal static ConfigEntry<Toggle> _trainingDummyNightAggro; internal static ConfigEntry<float> _archeryTargetSkillMultiplier; internal static ConfigEntry<Toggle> _archeryTargetArrowBoltSkillOnly; internal static ConfigEntry<string> _trainingDummyRecipe; internal static ConfigEntry<string> _archeryTargetRecipe; internal static ConfigEntry<TrainingDummyDamageType> _localTrainingDummyDamageType; internal static ConfigEntry<float> _localTrainingDummyDamageAmount; internal static ConfigEntry<TrainingMeterDisplay> _trainingMeterDisplay; internal static ConfigEntry<float> _trainingMeterWindowSeconds; internal static readonly Dictionary<SkillType, ConfigEntry<float>> _skillGainRates; internal static readonly Dictionary<SkillType, ConfigEntry<float>> _skillReductionRates; public void Awake() { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Expected O, but got Unknown //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Expected O, but got Unknown //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Expected O, but got Unknown //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Expected O, but got Unknown //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Expected O, but got Unknown //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Expected O, but got Unknown //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Expected O, but got Unknown bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; _serverConfigLocked = config("1 - General", "Lock Configuration", Toggle.On, "If on, the configuration is locked and can be changed by server admins only."); ConfigSync.AddLockingConfigEntry<Toggle>(_serverConfigLocked); _locationFullEfficiencySeconds = config("2 - Skill Gate", "Location Full Efficiency Seconds", 120f, new ConfigDescription("Stationary farmable skill gains stay at full value for this many chained seconds before fading.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3600f), Array.Empty<object>())); _locationFadeSeconds = config("2 - Skill Gate", "Location Fade Seconds", 180f, new ConfigDescription("After full-efficiency time, stationary farmable skill gains fade to the minimum multiplier over this many seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 7200f), Array.Empty<object>())); _locationMinimumMultiplier = config("2 - Skill Gate", "Location Minimum Multiplier", 0.1f, new ConfigDescription("Lowest multiplier applied to repeated stationary farmable skill gains.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); _stationaryRadius = config("2 - Skill Gate", "Stationary XZ Radius", 4f, new ConfigDescription("Radius on the X/Z plane. If farmable skill gains keep happening without leaving this radius, location efficiency fades.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 50f), Array.Empty<object>())); _fatigueStationarySkillGains = config("2 - Skill Gate", "Fatigue Stationary Skill Gains", Toggle.On, "If on, repeated farmable skill gains within the stationary X/Z radius share one global fading multiplier instead of being blocked outright. Affected skills: " + SkillNameFormatter.FormatList(SkillEarnGate.GetLocationFatigueSkillTypes()) + "."); _fatigueStatusEffectDisplay = config("2 - Skill Gate", "Fatigue Status Effect Display", FatigueStatusEffectDisplay.Detailed, "Controls the local player's fatigue status effect display. Detailed shows the status effect icon and static compendium details; Off hides it."); _trainingDummyHealth = config("3 - Training Dummy", "Training Dummy Health", 2500f, new ConfigDescription("Max health applied to piece_TrainingDummy.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100000f), Array.Empty<object>())); _trainingDummyCrowdingRadius = config("3 - Training Dummy", "Training Dummy Crowding Radius", 4f, new ConfigDescription("XZ radius used to discourage placing too many training dummies in one spot. 0 disables the crowding check.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>())); _trainingDummyCrowdingMaxCount = config("3 - Training Dummy", "Training Dummy Crowding Max Count", 4, new ConfigDescription("Maximum existing training dummies allowed inside the crowding radius. 4 means the 5th placement is discouraged. 0 disables the crowding check.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); _trainingDummyNightAggro = config("3 - Training Dummy", "Training Dummy Night Aggro", Toggle.Off, "If on, training dummies detect players in a 16m radius at night and slide close enough for their native attack."); _trainingDummyRecipe = config("3 - Training Dummy", "Training Dummy Recipe", "FineWood:5,BronzeNails:10,Ectoplasm:5", "Recipe override for piece_TrainingDummy. Leave empty to keep vanilla, use None for no cost, or use ItemPrefab:Amount,ItemPrefab:Amount. Default: FineWood:5,BronzeNails:10,Ectoplasm:5. Materials are always recovered when dismantling."); _localTrainingDummyDamageType = config("3 - Training Dummy", "Training Dummy Damage Type", TrainingDummyDamageType.Blunt, "Damage type used by local training dummy damage tests.", synchronizedSetting: false); _localTrainingDummyDamageAmount = config("3 - Training Dummy", "Training Dummy Damage", 1f, new ConfigDescription("Damage amount used by local training dummy damage tests.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 500f), Array.Empty<object>()), synchronizedSetting: false); _trainingMeterDisplay = config("3 - Training Dummy", "Training Meter Display", TrainingMeterDisplay.Detailed, "Controls the integrated client-side training HUD for piece_TrainingDummy damage, incoming hits, and skill gains.", synchronizedSetting: false); _trainingMeterWindowSeconds = config("3 - Training Dummy", "Training Meter Window Seconds", 15f, new ConfigDescription("Rolling time window used by the training HUD.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 300f), Array.Empty<object>()), synchronizedSetting: false); _archeryTargetSkillMultiplier = config("4 - Archery Target", "Archery Target Skill Multiplier", 1f, new ConfigDescription("Multiplier applied to skill experience awarded by piece_ArcheryTarget. 0 disables archery target skill gain.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>())); _archeryTargetArrowBoltSkillOnly = config("4 - Archery Target", "Archery Target Arrow Bolt Skill Only", Toggle.On, "If on, piece_ArcheryTarget awards skill experience only for projectiles fired with arrow or bolt ammo. Other projectiles can still score hits but award no skill experience."); _archeryTargetRecipe = config("4 - Archery Target", "Archery Target Recipe", "FineWood:4,LeatherScraps:10", "Recipe override for piece_ArcheryTarget. Leave empty to keep vanilla, use None for no cost, or use ItemPrefab:Amount,ItemPrefab:Amount. Default: FineWood:4,LeatherScraps:10. Materials are always recovered when dismantling."); BindTrainingObjectConfigEvents(); BindPerSkillModifierConfigs(); Assembly executingAssembly = Assembly.GetExecutingAssembly(); _harmony.PatchAll(executingAssembly); SetupWatcher(); ((BaseUnityPlugin)this).Config.Save(); if (saveOnConfigSet) { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } } private void OnDestroy() { SaveWithRespectToConfigSet(); _watcher?.Dispose(); } private void OnGUI() { TrainingMeter.OnGUI(); TrainingDummySettingsWindow.OnGUI(); } private void SetupWatcher() { _watcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName); _watcher.Changed += ReadConfigValues; _watcher.Created += ReadConfigValues; _watcher.Renamed += ReadConfigValues; _watcher.IncludeSubdirectories = true; _watcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; _watcher.EnableRaisingEvents = true; } private void ReadConfigValues(object sender, FileSystemEventArgs e) { DateTime now = DateTime.Now; if (now.Ticks - _lastConfigReloadTime.Ticks < 10000000) { return; } lock (_reloadLock) { if (!File.Exists(ConfigFileFullPath)) { TouchGrassLogger.LogWarning((object)"Config file does not exist. Skipping reload."); return; } try { TouchGrassLogger.LogDebug((object)"Reloading configuration..."); SaveWithRespectToConfigSet(reload: true); TouchGrassLogger.LogInfo((object)"Configuration reload complete."); } catch (Exception ex) { TouchGrassLogger.LogError((object)("Error reloading configuration: " + ex.Message)); } } _lastConfigReloadTime = now; } private void SaveWithRespectToConfigSet(bool reload = false) { bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; if (reload) { ((BaseUnityPlugin)this).Config.Reload(); } ((BaseUnityPlugin)this).Config.Save(); TrainingObjectTuning.ApplyAll(); PieceRecipeTuning.ApplyAll(); if (saveOnConfigSet) { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } } private unsafe void BindPerSkillModifierConfigs() { //IL_0011: 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_002a: 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_005b: Expected O, but got Unknown //IL_0065: 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_0096: Expected O, but got Unknown foreach (SkillType configurableSkillType in GetConfigurableSkillTypes()) { string name = ((object)(*(SkillType*)(&configurableSkillType))/*cast due to .constrained prefix*/).ToString(); _skillGainRates[configurableSkillType] = config("4 - Skill Gain Rate", name, 1f, new ConfigDescription("Multiplier applied to this skill's gained experience. Vanilla equivalent is 1. 0 disables gains for this skill, 2 doubles them.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>())); _skillReductionRates[configurableSkillType] = config("5 - Skill Reduction Rate", name, 1f, new ConfigDescription("Multiplier applied to this skill's death skill loss. Vanilla equivalent is 1. 0 disables death loss for this skill, 2 doubles it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>())); } } private void BindTrainingObjectConfigEvents() { _trainingDummyHealth.SettingChanged += delegate { TrainingObjectTuning.ApplyAll(); }; _trainingDummyNightAggro.SettingChanged += delegate { TrainingObjectTuning.ApplyAll(); }; _archeryTargetSkillMultiplier.SettingChanged += delegate { TrainingObjectTuning.ApplyAll(); }; _trainingDummyRecipe.SettingChanged += delegate { PieceRecipeTuning.ApplyAll(); }; _archeryTargetRecipe.SettingChanged += delegate { PieceRecipeTuning.ApplyAll(); }; } private static IEnumerable<SkillType> GetConfigurableSkillTypes() { foreach (SkillType value in Enum.GetValues(typeof(SkillType))) { if (((int)value != 0 && (int)value != 999) || 1 == 0) { yield return value; } } } private ConfigEntry<T> config<T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags); ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val); ConfigSync.AddConfigEntry<T>(val2).SynchronizedConfig = synchronizedSetting; return val2; } private ConfigEntry<T> config<T>(string group, string name, T value, string description, bool synchronizedSetting = true) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting); } static TouchGrassPlugin() { string configPath = Paths.ConfigPath; char directorySeparatorChar = Path.DirectorySeparatorChar; ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName; ConnectionError = ""; TouchGrassLogger = Logger.CreateLogSource("TouchGrass"); ConfigSync = new ConfigSync("sighsorry.TouchGrass") { DisplayName = "TouchGrass", CurrentVersion = "1.0.4", MinimumRequiredVersion = "1.0.4" }; _serverConfigLocked = null; _locationFullEfficiencySeconds = null; _locationFadeSeconds = null; _locationMinimumMultiplier = null; _stationaryRadius = null; _fatigueStationarySkillGains = null; _fatigueStatusEffectDisplay = null; _trainingDummyHealth = null; _trainingDummyCrowdingRadius = null; _trainingDummyCrowdingMaxCount = null; _trainingDummyNightAggro = null; _archeryTargetSkillMultiplier = null; _archeryTargetArrowBoltSkillOnly = null; _trainingDummyRecipe = null; _archeryTargetRecipe = null; _localTrainingDummyDamageType = null; _localTrainingDummyDamageAmount = null; _trainingMeterDisplay = null; _trainingMeterWindowSeconds = null; _skillGainRates = new Dictionary<SkillType, ConfigEntry<float>>(); _skillReductionRates = new Dictionary<SkillType, ConfigEntry<float>>(); } } internal static class ArcheryTargetSkillGate { internal static bool ShouldAwardSkill(ItemData weapon, Projectile projectile) { ConfigEntry<TouchGrassPlugin.Toggle> archeryTargetArrowBoltSkillOnly = TouchGrassPlugin._archeryTargetArrowBoltSkillOnly; if (archeryTargetArrowBoltSkillOnly == null || archeryTargetArrowBoltSkillOnly.Value != TouchGrassPlugin.Toggle.On) { return true; } if (!IsArrowOrBoltAmmo(((Object)(object)projectile != (Object)null) ? projectile.m_ammo : null)) { return IsArrowOrBoltAmmo(weapon); } return true; } private static bool IsArrowOrBoltAmmo(ItemData? item) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Invalid comparison between Unknown and I4 if (item == null || item.m_shared == null) { return false; } ItemType itemType = item.m_shared.m_itemType; if ((int)itemType != 9 && (int)itemType != 23) { return false; } if (!ContainsArrowOrBolt(item.m_shared.m_ammoType) && !ContainsArrowOrBolt(item.m_shared.m_name)) { return ContainsArrowOrBolt(((Object)(object)item.m_dropPrefab != (Object)null) ? Utils.GetPrefabName(item.m_dropPrefab) : ""); } return true; } private static bool ContainsArrowOrBolt(string? value) { if (value == null) { return false; } string text = value.Trim(); if (text.Length == 0) { return false; } if (text.IndexOf("arrow", StringComparison.OrdinalIgnoreCase) < 0) { return text.IndexOf("bolt", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } } [HarmonyPatch(typeof(Skills), "RaiseSkill")] internal static class SkillsRaiseSkillPatch { private static bool Prefix(Skills __instance, SkillType skillType, ref float factor) { //IL_0004: 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) float sourceFactor = factor; bool flag = SkillEarnGate.AdjustSkillGain(__instance, skillType, ref factor); TrainingMeter.RecordSkillGain(__instance, skillType, sourceFactor, flag ? factor : 0f); return flag; } } [HarmonyPatch(typeof(Player), "RaiseSkill")] internal static class PlayerRaiseSkillPatch { private static void Prefix(Player __instance, SkillType skill, float value, out int __state) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) __state = TrainingMeter.BeginPlayerSkillRaise(__instance, skill, value); } private static Exception Finalizer(int __state, Exception __exception) { TrainingMeter.EndPlayerSkillRaise(__state); return __exception; } } [HarmonyPatch(typeof(Skills), "LowerAllSkills")] internal static class SkillsLowerAllSkillsPatch { private static bool Prefix(Skills __instance, float factor) { return SkillEarnGate.AdjustSkillReduction(__instance, factor); } } [HarmonyPatch(typeof(Character), "RPC_Damage")] internal static class CharacterRPCDamagePatch { private static void Prefix(Character __instance, HitData hit, out TrainingMeter.IncomingDamageState __state) { TrainingDummyDamageTest.OverrideLocalIncomingDamage(__instance, hit); __state = TrainingMeter.BeforeIncomingDamage(__instance, hit); } private static void Postfix(Character __instance, TrainingMeter.IncomingDamageState __state) { TrainingMeter.AfterIncomingDamage(__instance, __state); } } [HarmonyPatch(typeof(Character), "Awake")] internal static class CharacterAwakePatch { private static void Postfix(Character __instance) { TrainingDummyRegistry.Register(__instance); TrainingObjectTuning.ApplyTrainingDummy(__instance); } } [HarmonyPatch(typeof(Character), "OnDestroy")] internal static class CharacterOnDestroyPatch { private static void Prefix(Character __instance) { TrainingDummyRegistry.Unregister(__instance); } } [HarmonyPatch(typeof(Character), "GetHoverText")] internal static class CharacterGetHoverTextPatch { private static void Postfix(Character __instance, ref string __result) { if (TrainingDummyIdentity.IsTrainingDummy(__instance)) { __result = TrainingDummySettingsWindow.GetHoverText(__result); } } } [HarmonyPatch(typeof(Character), "Damage")] internal static class CharacterDamagePatch { private static void Prefix(Character __instance, HitData hit) { TrainingMeter.RecordOutgoingDamage(__instance, hit); } } [HarmonyPatch(typeof(Player), "TakeInput")] internal static class PlayerTakeInputPatch { private static void Postfix(ref bool __result) { if (TrainingDummySettingsWindow.IsVisible) { __result = false; } } } [HarmonyPatch(typeof(Player), "TryPlacePiece")] internal static class PlayerTryPlacePiecePatch { private static bool Prefix(Player __instance, Piece piece, ref bool __result) { if (TrainingDummyCrowding.CanPlace(__instance, piece)) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(Humanoid), "BlockAttack")] internal static class HumanoidBlockAttackPatch { private static void Postfix(Humanoid __instance, HitData hit) { TrainingMeter.RecordBlockResult(__instance, hit); } } [HarmonyPatch(typeof(ArcheryTarget), "Start")] internal static class ArcheryTargetStartPatch { private static void Postfix(ArcheryTarget __instance) { TrainingObjectTuning.ApplyArcheryTarget(__instance); } } [HarmonyPatch(typeof(ArcheryTarget), "OnProjectileHit")] internal static class ArcheryTargetOnProjectileHitPatch { private static void Prefix(ArcheryTarget __instance, ItemData weapon, Projectile projectile, out float __state) { __state = __instance.m_raiseSkillMultiplier; if (!ArcheryTargetSkillGate.ShouldAwardSkill(weapon, projectile)) { __instance.m_raiseSkillMultiplier = 0f; } } private static void Postfix(ArcheryTarget __instance, float __state) { __instance.m_raiseSkillMultiplier = __state; } private static Exception Finalizer(ArcheryTarget __instance, float __state, Exception __exception) { __instance.m_raiseSkillMultiplier = __state; return __exception; } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class ZNetSceneAwakePatch { private static void Postfix(ZNetScene __instance) { TrainingObjectTuning.ApplyPrefabTuning(__instance); PieceRecipeTuning.ApplyAll(); } } [HarmonyPatch(typeof(ObjectDB), "Awake")] internal static class ObjectDBAwakePatch { private static void Postfix() { PieceRecipeTuning.ApplyAll(); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] internal static class ObjectDBCopyOtherDBPatch { private static void Postfix() { PieceRecipeTuning.ApplyAll(); } } [HarmonyPatch(typeof(Piece), "SetCreator")] internal static class PieceSetCreatorPatch { private static void Postfix(Piece __instance) { TrainingDummyDamageTest.StampPlacedDamageProfile(__instance); } } internal static class PieceRecipeTuning { private const string ArcheryTargetPrefabName = "piece_ArcheryTarget"; private static readonly Dictionary<string, Requirement[]> VanillaRecipes = new Dictionary<string, Requirement[]>(StringComparer.OrdinalIgnoreCase); internal static void ApplyAll() { ZNetScene instance = ZNetScene.instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)ObjectDB.instance == (Object)null)) { ApplyRecipe(instance, "piece_TrainingDummy", TouchGrassPlugin._trainingDummyRecipe?.Value); ApplyRecipe(instance, "piece_ArcheryTarget", TouchGrassPlugin._archeryTargetRecipe?.Value); } } private static void ApplyRecipe(ZNetScene scene, string prefabName, string? recipeText) { GameObject prefab = scene.GetPrefab(prefabName); if ((Object)(object)prefab == (Object)null) { return; } Piece componentInChildren = prefab.GetComponentInChildren<Piece>(true); if ((Object)(object)componentInChildren == (Object)null) { return; } StoreVanillaRecipe(prefabName, componentInChildren); string text = recipeText ?? ""; if (string.IsNullOrWhiteSpace(text)) { componentInChildren.m_resources = CloneRequirements(VanillaRecipes[prefabName]); return; } text = text.Trim(); if (!TryParseRecipe(text, out Requirement[] requirements)) { componentInChildren.m_resources = CloneRequirements(VanillaRecipes[prefabName]); TouchGrassPlugin.TouchGrassLogger.LogWarning((object)("Invalid " + prefabName + " recipe override '" + text + "'. Restored vanilla recipe.")); } else { componentInChildren.m_resources = requirements; } } private static void StoreVanillaRecipe(string prefabName, Piece piece) { if (!VanillaRecipes.ContainsKey(prefabName)) { VanillaRecipes[prefabName] = CloneRequirements(piece.m_resources); } } private static bool TryParseRecipe(string recipeText, out Requirement[] requirements) { //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: 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_0112: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Expected O, but got Unknown requirements = Array.Empty<Requirement>(); string text = recipeText.Trim(); if (text.Equals("none", StringComparison.OrdinalIgnoreCase) || text.Equals("free", StringComparison.OrdinalIgnoreCase) || text == "-") { return true; } string[] array = text.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); List<Requirement> list = new List<Requirement>(); string[] array2 = array; for (int i = 0; i < array2.Length; i++) { string[] array3 = array2[i].Trim().Split(new char[2] { ':', '=' }, StringSplitOptions.RemoveEmptyEntries); if (array3.Length != 2) { return false; } string text2 = array3[0].Trim(); if (!int.TryParse(array3[1].Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || result < 1) { return false; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(text2); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val == (Object)null) { TouchGrassPlugin.TouchGrassLogger.LogWarning((object)("Unknown recipe item prefab '" + text2 + "'.")); return false; } list.Add(new Requirement { m_resItem = val, m_amount = result, m_recover = true }); } requirements = list.ToArray(); return true; } private static Requirement[] CloneRequirements(Requirement[]? requirements) { //IL_0020: 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_0031: 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_0049: 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_0062: Expected O, but got Unknown if (requirements == null || requirements.Length == 0) { return Array.Empty<Requirement>(); } Requirement[] array = (Requirement[])(object)new Requirement[requirements.Length]; for (int i = 0; i < requirements.Length; i++) { Requirement val = requirements[i]; array[i] = new Requirement { m_resItem = val.m_resItem, m_amount = val.m_amount, m_extraAmountOnlyOneIngredient = val.m_extraAmountOnlyOneIngredient, m_amountPerLevel = val.m_amountPerLevel, m_recover = val.m_recover }; } return array; } } internal static class SkillEarnGate { internal readonly struct FatigueSnapshot { internal static readonly FatigueSnapshot Empty = new FatigueSnapshot(1f); internal readonly float Multiplier; public FatigueSnapshot(float multiplier) { Multiplier = multiplier; } } private struct LocationFatigueState { internal bool HasGain; internal bool HasAnchor; internal float LastGainTime; internal float ActiveSeconds; internal float AnchorX; internal float AnchorZ; internal void SetAnchor(Vector3 position) { //IL_0008: 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) HasAnchor = true; AnchorX = position.x; AnchorZ = position.z; } internal void ClearGain() { HasGain = false; LastGainTime = 0f; ActiveSeconds = 0f; } internal void Clear() { HasAnchor = false; AnchorX = 0f; AnchorZ = 0f; ClearGain(); } } private const float TrainingChainGrace = 10f; private static readonly SkillType[] LocationFatigueSkillOrder; private static readonly HashSet<SkillType> LocationFatigueSkills; private static LocationFatigueState _locationFatigue; internal static bool AdjustSkillGain(Skills skills, SkillType skillType, ref float factor) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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) if ((Object)(object)skills == (Object)null || (Object)(object)skills.m_player != (Object)(object)Player.m_localPlayer) { return true; } if ((int)skillType == 0) { return true; } float sourceFactor = factor; factor *= GetPerSkillGainRate(skillType); if (ShouldApplyLocationFatigue(skillType, sourceFactor)) { factor *= GetLocationMultiplier(skills.m_player); } return factor > 0.0001f; } internal static bool AdjustSkillReduction(Skills skills, float factor) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)skills == (Object)null || (Object)(object)skills.m_player != (Object)(object)Player.m_localPlayer) { return true; } foreach (KeyValuePair<SkillType, Skill> skillDatum in skills.m_skillData) { float num = Mathf.Clamp01(factor * GetPerSkillReductionRate(skillDatum.Key)); Skill value = skillDatum.Value; value.m_level -= skillDatum.Value.m_level * num; skillDatum.Value.m_accumulator = 0f; } ((Character)skills.m_player).Message((MessageType)1, "$msg_skills_lowered", 0, (Sprite)null); return false; } internal static IReadOnlyList<SkillType> GetLocationFatigueSkillTypes() { return LocationFatigueSkillOrder; } private static bool ShouldApplyLocationFatigue(SkillType skillType, float sourceFactor) { //IL_0012: 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_001f: Invalid comparison between Unknown and I4 if (TouchGrassPlugin._fatigueStationarySkillGains.Value != TouchGrassPlugin.Toggle.On || !LocationFatigueSkills.Contains(skillType)) { return false; } if ((int)skillType == 108) { return IsNormalDodgeGain(sourceFactor); } return true; } private static float GetPerSkillGainRate(SkillType skillType) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return GetPerSkillConfigValue(TouchGrassPlugin._skillGainRates, skillType, 1f); } private static float GetPerSkillReductionRate(SkillType skillType) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return GetPerSkillConfigValue(TouchGrassPlugin._skillReductionRates, skillType, 1f); } private static float GetPerSkillConfigValue(IReadOnlyDictionary<SkillType, ConfigEntry<float>> configs, SkillType skillType, float fallback) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if (!configs.TryGetValue(skillType, out ConfigEntry<float> value)) { return fallback; } return value.Value; } private static float GetLocationMultiplier(Player player) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return 1f; } float time = Time.time; if (!IsInsideStationaryRadius(((Component)player).transform.position)) { ResetLocationFatigue(); FatigueStatusEffectManager.Update(player); return 1f; } float result = RecordLocationFatigueGain(ref _locationFatigue, time); FatigueStatusEffectManager.Update(player); return result; } private static float RecordLocationFatigueGain(ref LocationFatigueState state, float now) { if (state.HasGain) { float num = Mathf.Max(0f, now - state.LastGainTime); if (num <= 10f) { state.ActiveSeconds += num; } } state.HasGain = true; state.LastGainTime = now; state.ActiveSeconds = Mathf.Min(GetMaxTrackedActiveSeconds(), state.ActiveSeconds); return ComputeLocationMultiplier(state.ActiveSeconds); } private static void ResetLocationFatigue() { _locationFatigue.ClearGain(); } private static bool IsInsideStationaryRadius(Vector3 position) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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) float value = TouchGrassPlugin._stationaryRadius.Value; if (value <= 0f) { return false; } if (!_locationFatigue.HasAnchor) { _locationFatigue.SetAnchor(position); return false; } float num = position.x - _locationFatigue.AnchorX; float num2 = position.z - _locationFatigue.AnchorZ; if (num * num + num2 * num2 > value * value) { _locationFatigue.SetAnchor(position); return false; } return true; } private static float ComputeLocationMultiplier(float activeSeconds) { float value = TouchGrassPlugin._locationFullEfficiencySeconds.Value; if (activeSeconds <= value) { return 1f; } float num = Mathf.Max(1f, TouchGrassPlugin._locationFadeSeconds.Value); float num2 = Mathf.Clamp01(TouchGrassPlugin._locationMinimumMultiplier.Value); float num3 = Mathf.Clamp01((activeSeconds - value) / num); return Mathf.Lerp(1f, num2, num3); } private static bool IsNormalDodgeGain(float sourceFactor) { return sourceFactor <= 0.11f; } internal static bool TryGetFatigueSnapshot(out FatigueSnapshot snapshot) { snapshot = FatigueSnapshot.Empty; if (TouchGrassPlugin._fatigueStationarySkillGains.Value != TouchGrassPlugin.Toggle.On || TouchGrassPlugin._fatigueStatusEffectDisplay.Value == TouchGrassPlugin.FatigueStatusEffectDisplay.Off || !_locationFatigue.HasGain) { return false; } float num = ComputeLocationMultiplier(_locationFatigue.ActiveSeconds); if (num >= 0.999f) { return false; } snapshot = new FatigueSnapshot(num); return true; } private static float GetMaxTrackedActiveSeconds() { return Mathf.Max(1f, TouchGrassPlugin._locationFullEfficiencySeconds.Value + TouchGrassPlugin._locationFadeSeconds.Value); } static SkillEarnGate() { SkillType[] array = new SkillType[20]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); LocationFatigueSkillOrder = (SkillType[])(object)array; LocationFatigueSkills = new HashSet<SkillType>(LocationFatigueSkillOrder); } } internal static class FatigueStatusEffectManager { private const string EffectObjectName = "TouchGrass_Fatigue"; private static TouchGrassFatigueStatusEffect? _prototype; private static int EffectHash => ((StatusEffect)Prototype).NameHash(); private static TouchGrassFatigueStatusEffect Prototype { get { if ((Object)(object)_prototype != (Object)null) { return _prototype; } _prototype = ScriptableObject.CreateInstance<TouchGrassFatigueStatusEffect>(); ((Object)_prototype).name = "TouchGrass_Fatigue"; ((StatusEffect)_prototype).m_name = "TouchGrass Fatigue"; ((StatusEffect)_prototype).m_category = "TouchGrass"; ((StatusEffect)_prototype).m_icon = CreateIcon(); ((StatusEffect)_prototype).m_startMessage = ""; ((StatusEffect)_prototype).m_stopMessage = ""; Object.DontDestroyOnLoad((Object)(object)_prototype); return _prototype; } } internal static void Update(Player player) { if ((Object)(object)player == (Object)null || ((Character)player).GetSEMan() == null) { return; } if (!SkillEarnGate.TryGetFatigueSnapshot(out var _)) { Remove(player); return; } SEMan sEMan = ((Character)player).GetSEMan(); if ((Object)(object)sEMan.GetStatusEffect(EffectHash) == (Object)null) { sEMan.AddStatusEffect((StatusEffect)(object)Prototype, false, 0, 0f); } } internal static void Remove(Player player) { if (player != null) { SEMan sEMan = ((Character)player).GetSEMan(); if (sEMan != null) { sEMan.RemoveStatusEffect(EffectHash, true); } } } private static Sprite CreateIcon() { //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_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_0093: 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_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0123: 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) //IL_00b6: 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_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0153: 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_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(32, 32, (TextureFormat)4, false) { filterMode = (FilterMode)0, wrapMode = (TextureWrapMode)1 }; Color32[] array = (Color32[])(object)new Color32[1024]; Color32 val2 = default(Color32); ((Color32)(ref val2))..ctor((byte)0, (byte)0, (byte)0, (byte)0); Color32 val3 = default(Color32); ((Color32)(ref val3))..ctor((byte)89, (byte)162, (byte)105, byte.MaxValue); Color32 val4 = default(Color32); ((Color32)(ref val4))..ctor((byte)26, (byte)54, (byte)41, byte.MaxValue); Color32 val5 = default(Color32); ((Color32)(ref val5))..ctor((byte)202, (byte)231, (byte)179, byte.MaxValue); Vector2 val6 = default(Vector2); ((Vector2)(ref val6))..ctor(15.5f, 15.5f); for (int i = 0; i < 32; i++) { for (int j = 0; j < 32; j++) { float num = Vector2.Distance(new Vector2((float)j, (float)i), val6); array[i * 32 + j] = ((num <= 14.5f) ? val4 : val2); if (num <= 12.5f) { array[i * 32 + j] = val3; } } } for (int k = 8; k <= 23; k++) { int num2 = 15 + Mathf.RoundToInt((float)(k - 16) * 0.15f); array[k * 32 + num2] = val5; array[k * 32 + num2 + 1] = val5; } for (int l = 8; l <= 16; l++) { int num3 = 16 - l; for (int m = 16; m <= 16 + num3; m++) { array[l * 32 + m] = val5; } } for (int n = 14; n <= 22; n++) { int num4 = n - 14; for (int num5 = 14 - num4; num5 <= 14; num5++) { array[n * 32 + num5] = val5; } } val.SetPixels32(array); val.Apply(false, true); Object.DontDestroyOnLoad((Object)(object)val); Sprite obj = Sprite.Create(val, new Rect(0f, 0f, 32f, 32f), new Vector2(0.5f, 0.5f), 32f); Object.DontDestroyOnLoad((Object)(object)obj); return obj; } } internal class TouchGrassFatigueStatusEffect : StatusEffect { public override bool CanAdd(Character character) { return (Object)(object)character == (Object)(object)Player.m_localPlayer; } public override bool IsDone() { SkillEarnGate.FatigueSnapshot snapshot; if (!((StatusEffect)this).IsDone()) { return !SkillEarnGate.TryGetFatigueSnapshot(out snapshot); } return true; } public override string GetIconText() { if (!SkillEarnGate.TryGetFatigueSnapshot(out var snapshot)) { return ""; } return $"{Mathf.RoundToInt(snapshot.Multiplier * 100f)}%"; } public override string GetTooltipString() { return "Touch the grass Bro!"; } } internal static class SkillNameFormatter { internal static string FormatList(IReadOnlyList<SkillType> skillTypes) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < skillTypes.Count; i++) { if (i > 0) { stringBuilder.Append(", "); } stringBuilder.Append(Format(skillTypes[i])); } return stringBuilder.ToString(); } internal unsafe static string Format(SkillType skillType) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Invalid comparison between Unknown and I4 string text = "$skill_" + ((object)(*(SkillType*)(&skillType))/*cast due to .constrained prefix*/).ToString().ToLowerInvariant(); if (Localization.instance != null) { string text2 = Localization.instance.Localize(text); if (!string.IsNullOrWhiteSpace(text2) && text2 != text) { return text2; } } if ((int)skillType != 11) { return ((object)(*(SkillType*)(&skillType))/*cast due to .constrained prefix*/).ToString(); } return "Fists"; } } internal static class TrainingDummyCrowding { private const string CrowdedMessage = "Too crowded Bro!"; internal static bool CanPlace(Player player, Piece piece) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)piece == (Object)null || !TrainingDummyIdentity.IsTrainingDummy(piece) || (Object)(object)player.m_placementGhost == (Object)null) { return true; } if (!IsCrowded(player.m_placementGhost.transform.position)) { return true; } ((Character)player).Message((MessageType)2, "Too crowded Bro!", 0, (Sprite)null); return false; } private static bool IsCrowded(Vector3 position) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: 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_0094: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp(TouchGrassPlugin._trainingDummyCrowdingRadius?.Value ?? 4f, 0f, 50f); int num2 = Mathf.Clamp(TouchGrassPlugin._trainingDummyCrowdingMaxCount?.Value ?? 4, 0, 100); if (num <= 0f || num2 <= 0) { return false; } float num3 = num * num; int num4 = 0; foreach (Character loadedDummy in TrainingDummyRegistry.GetLoadedDummies()) { if ((Object)(object)loadedDummy == (Object)null) { continue; } Vector3 position2 = ((Component)loadedDummy).transform.position; float num5 = position2.x - position.x; float num6 = position2.z - position.z; if (!(num5 * num5 + num6 * num6 > num3)) { num4++; if (num4 >= num2) { return true; } } } return false; } } internal static class TrainingDummyDamageTest { private readonly struct DamageProfile { internal readonly TouchGrassPlugin.TrainingDummyDamageType DamageType; internal readonly float Amount; public DamageProfile(TouchGrassPlugin.TrainingDummyDamageType damageType, float amount) { DamageType = damageType; Amount = amount; } } internal const string DummyDamageProfileVersionKey = "TouchGrass_DummyDamageProfileVersion"; internal const string DummyDamageTypeKey = "TouchGrass_DummyDamageType"; internal const string DummyDamageAmountKey = "TouchGrass_DummyDamageAmount"; internal const int DummyDamageProfileVersion = 1; internal static void OverrideLocalIncomingDamage(Character victim, HitData hit) { //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) if (hit != null && !((Object)(object)victim == (Object)null) && !((Object)(object)victim != (Object)(object)Player.m_localPlayer)) { Character attacker = hit.GetAttacker(); if (TrainingDummyIdentity.IsTrainingDummy(attacker) && (TryReadStampedDamageProfile(attacker, out var profile) || TryGetLocalDamageProfile(out profile))) { hit.m_damage = BuildDamageTypes(profile.DamageType, profile.Amount); } } } internal static void StampPlacedDamageProfile(Piece piece) { if ((Object)(object)piece == (Object)null || !TrainingDummyIdentity.IsTrainingDummy(piece) || !TryGetLocalDamageProfile(out var profile)) { return; } ZNetView val = (ZNetView)(((Object)(object)piece.m_nview != (Object)null) ? ((object)piece.m_nview) : ((object)TrainingDummyIdentity.GetNetView((Component?)(object)piece))); if (!((Object)(object)val == (Object)null) && val.IsValid() && val.IsOwner()) { ZDO zDO = val.GetZDO(); if (zDO != null && piece.GetCreator() != 0L && zDO.GetInt("TouchGrass_DummyDamageType", -1) < 0) { zDO.Set("TouchGrass_DummyDamageProfileVersion", 1); zDO.Set("TouchGrass_DummyDamageType", (int)profile.DamageType); zDO.Set("TouchGrass_DummyDamageAmount", profile.Amount); } } } internal static bool TryGetEffectiveDamageProfile(Character attacker, out TouchGrassPlugin.TrainingDummyDamageType damageType, out float amount) { if (TryReadStampedDamageProfile(attacker, out var profile)) { damageType = profile.DamageType; amount = profile.Amount; return true; } if (TryGetLocalDamageProfile(out var profile2)) { damageType = profile2.DamageType; amount = profile2.Amount; return true; } damageType = TouchGrassPlugin.TrainingDummyDamageType.Blunt; amount = 1f; return false; } internal static void SetDamageProfile(Character character, TouchGrassPlugin.TrainingDummyDamageType damageType, float amount) { ZNetView val = (ZNetView)((!((Object)(object)character != (Object)null)) ? null : (((Object)(object)character.m_nview != (Object)null) ? ((object)character.m_nview) : ((object)TrainingDummyIdentity.GetNetView((Component?)(object)character)))); if (!((Object)(object)val == (Object)null) && val.IsValid()) { val.ClaimOwnership(); ZDO zDO = val.GetZDO(); if (zDO != null) { zDO.Set("TouchGrass_DummyDamageProfileVersion", 1); zDO.Set("TouchGrass_DummyDamageType", (int)damageType); zDO.Set("TouchGrass_DummyDamageAmount", Mathf.Clamp(amount, 1f, 500f)); } } } private static bool TryReadStampedDamageProfile(Character attacker, out DamageProfile profile) { profile = default(DamageProfile); ZNetView netView = TrainingDummyIdentity.GetNetView((Component?)(object)attacker); if ((Object)(object)netView == (Object)null || !netView.IsValid()) { return false; } ZDO zDO = netView.GetZDO(); if (zDO == null) { return false; } int num = zDO.GetInt("TouchGrass_DummyDamageType", -1); if (!Enum.IsDefined(typeof(TouchGrassPlugin.TrainingDummyDamageType), num)) { return false; } float num2 = zDO.GetFloat("TouchGrass_DummyDamageAmount", 0f); if (num2 <= 0f) { return false; } profile = new DamageProfile((TouchGrassPlugin.TrainingDummyDamageType)num, num2); return true; } private static bool TryGetLocalDamageProfile(out DamageProfile profile) { profile = new DamageProfile(TouchGrassPlugin._localTrainingDummyDamageType.Value, TouchGrassPlugin._localTrainingDummyDamageAmount.Value); return true; } private static DamageTypes BuildDamageTypes(TouchGrassPlugin.TrainingDummyDamageType damageType, float amount) { //IL_0014: 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) amount = Mathf.Clamp(amount, 1f, 500f); DamageTypes result = default(DamageTypes); switch (damageType) { case TouchGrassPlugin.TrainingDummyDamageType.Blunt: result.m_blunt = amount; break; case TouchGrassPlugin.TrainingDummyDamageType.Slash: result.m_slash = amount; break; case TouchGrassPlugin.TrainingDummyDamageType.Pierce: result.m_pierce = amount; break; case TouchGrassPlugin.TrainingDummyDamageType.Fire: result.m_fire = amount; break; case TouchGrassPlugin.TrainingDummyDamageType.Frost: result.m_frost = amount; break; case TouchGrassPlugin.TrainingDummyDamageType.Lightning: result.m_lightning = amount; break; case TouchGrassPlugin.TrainingDummyDamageType.Poison: result.m_poison = amount; break; case TouchGrassPlugin.TrainingDummyDamageType.Spirit: result.m_spirit = amount; break; default: result.m_blunt = amount; break; } return result; } } internal static class TrainingDummyIdentity { internal const string PiecePrefabName = "piece_TrainingDummy"; private static readonly int PiecePrefabHash = StringExtensionMethods.GetStableHashCode("piece_TrainingDummy"); internal static bool IsTrainingDummy(Character character) { if ((Object)(object)character == (Object)null) { return false; } if (HasTrainingDummyPrefab(GetNetView((Component?)(object)character))) { return true; } Piece componentInParent = ((Component)character).GetComponentInParent<Piece>(); if ((Object)(object)componentInParent != (Object)null && IsTrainingDummy(componentInParent)) { return true; } return IsTrainingDummyPrefabName(Utils.GetPrefabName(((Component)character).gameObject)); } internal static bool IsTrainingDummy(Piece piece) { if ((Object)(object)piece == (Object)null) { return false; } if (HasTrainingDummyPrefab(GetNetView((Component?)(object)piece))) { return true; } return IsTrainingDummyPrefabName(Utils.GetPrefabName(((Component)piece).gameObject)); } internal static ZNetView? GetNetView(Component? component) { if (!((Object)(object)component != (Object)null)) { return null; } return component.GetComponent<ZNetView>() ?? component.GetComponentInParent<ZNetView>(); } private static bool HasTrainingDummyPrefab(ZNetView? netView) { if ((Object)(object)netView == (Object)null) { return false; } if (netView.IsValid() && netView.GetZDO() != null && IsTrainingDummyPrefabHash(netView.GetZDO().GetPrefab())) { return true; } return IsTrainingDummyPrefabName(netView.GetPrefabName()); } private static bool IsTrainingDummyPrefabName(string prefabName) { if (!string.IsNullOrEmpty(prefabName)) { return string.Equals(prefabName, "piece_TrainingDummy", StringComparison.OrdinalIgnoreCase); } return false; } private static bool IsTrainingDummyPrefabHash(int prefabHash) { return prefabHash == PiecePrefabHash; } } internal sealed class TrainingDummyNightAggro : MonoBehaviour { private const float DetectionRange = 16f; private const float DetectionInterval = 0.5f; private const float StopDistance = 1.8f; private const float SlideSpeed = 3f; private const float TurnSpeed = 720f; private Character? _character; private ZNetView? _netView; private Rigidbody? _body; private ZSyncTransform? _syncTransform; private Player? _target; private float _detectionTimer; private void Awake() { _character = ((Component)this).GetComponent<Character>(); _netView = (ZNetView?)(((Object)(object)_character != (Object)null && (Object)(object)_character.m_nview != (Object)null) ? ((object)_character.m_nview) : ((object)TrainingDummyIdentity.GetNetView((Component?)(object)this))); _body = ((Component)this).GetComponent<Rigidbody>(); _syncTransform = ((Component)this).GetComponent<ZSyncTransform>(); } private void FixedUpdate() { //IL_004a: 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_005f: 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) //IL_0085: 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_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) if (!HasOwnership()) { return; } if (!CanActAtNight()) { _target = null; StopOwnedMotion(); return; } UpdateTarget(Time.fixedDeltaTime); if ((Object)(object)_target == (Object)null) { StopOwnedMotion(); return; } Vector3 val = ((Component)_target).transform.position - ((Component)this).transform.position; val.y = 0f; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude <= 0.001f) { StopOwnedMotion(); return; } Vector3 direction = val / magnitude; LookTowards(direction); SlideTowardsTarget(direction, magnitude); } private bool HasOwnership() { if ((Object)(object)_netView != (Object)null && _netView.IsValid()) { return _netView.IsOwner(); } return false; } private bool CanActAtNight() { if (TouchGrassPlugin._trainingDummyNightAggro.Value == TouchGrassPlugin.Toggle.On && (Object)(object)EnvMan.instance != (Object)null && EnvMan.IsNight() && (Object)(object)_character != (Object)null) { return !_character.IsDead(); } return false; } private Player? FindClosestTarget() { //IL_0044: 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_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) Player result = null; float num = 256f; foreach (Player allPlayer in Player.GetAllPlayers()) { if (!((Object)(object)allPlayer == (Object)null) && !((Character)allPlayer).IsDead() && !allPlayer.InDebugFlyMode() && !((Character)allPlayer).InGhostMode()) { Vector3 val = ((Component)allPlayer).transform.position - ((Component)this).transform.position; val.y = 0f; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude <= num) { result = allPlayer; num = sqrMagnitude; } } } return result; } private void UpdateTarget(float dt) { _detectionTimer -= dt; if (!(_detectionTimer > 0f) || !IsValidTarget(_target)) { _target = FindClosestTarget(); _detectionTimer = 0.5f; } } private bool IsValidTarget(Player? player) { //IL_0029: 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_003e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || ((Character)player).IsDead() || player.InDebugFlyMode() || ((Character)player).InGhostMode()) { return false; } Vector3 val = ((Component)player).transform.position - ((Component)this).transform.position; val.y = 0f; return ((Vector3)(ref val)).sqrMagnitude <= 256f; } private void LookTowards(Vector3 direction) { //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) //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_0014: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_character != (Object)null) { _character.SetLookDir(direction, 0f); } Quaternion val = Quaternion.LookRotation(direction, Vector3.up); if ((Object)(object)_body != (Object)null) { Quaternion val2 = Quaternion.RotateTowards(_body.rotation, val, 720f * Time.fixedDeltaTime); _body.MoveRotation(val2); } else { ((Component)this).transform.rotation = Quaternion.RotateTowards(((Component)this).transform.rotation, val, 720f * Time.fixedDeltaTime); } } private void SlideTowardsTarget(Vector3 direction, float distance) { //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_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_003e: 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_0053: 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_006f: Unknown result type (might be due to invalid IL or missing references) float num = distance - 1.8f; if (num <= 0f) { StopOwnedMotion(); return; } Vector3 val = ((Component)this).transform.position + direction * Mathf.Min(num, 3f * Time.fixedDeltaTime); if ((Object)(object)_body != (Object)null) { _body.MovePosition(val); _body.linearVelocity = Vector3.zero; _body.angularVelocity = Vector3.zero; } else { ((Component)this).transform.position = val; } ZSyncTransform? syncTransform = _syncTransform; if (syncTransform != null) { syncTransform.SyncNow(); } } private void OnDisable() { _target = null; if (HasOwnership()) { StopOwnedMotion(); } } private void StopOwnedMotion() { //IL_000c: 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_003b: Unknown result type (might be due to invalid IL or missing references) Character? character = _character; if (character != null) { character.SetMoveDir(Vector3.zero); } if (!((Object)(object)_body == (Object)null)) { _body.linearVelocity = Vector3.zero; _body.angularVelocity = Vector3.zero; } } } internal static class TrainingDummyRegistry { private static readonly HashSet<Character> LoadedDummies = new HashSet<Character>(); internal static void Register(Character character) { if (!((Object)(object)character == (Object)null) && TrainingDummyIdentity.IsTrainingDummy(character)) { LoadedDummies.Add(character); } } internal static void Unregister(Character character) { if (!((Object)(object)character == (Object)null)) { LoadedDummies.Remove(character); } } internal static IReadOnlyCollection<Character> GetLoadedDummies() { LoadedDummies.RemoveWhere((Character character) => (Object)(object)character == (Object)null); return LoadedDummies; } } internal sealed class TrainingDummySettingsInteractable : MonoBehaviour, Interactable { public bool Interact(Humanoid user, bool hold, bool alt) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) if (hold || (Object)(object)user == (Object)null || (Object)(object)user != (Object)(object)Player.m_localPlayer) { return false; } Character component = ((Component)this).GetComponent<Character>(); if ((Object)(object)component == (Object)null || !TrainingDummyIdentity.IsTrainingDummy(component)) { return false; } if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return true; } TrainingDummySettingsWindow.Open(component); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } } internal static class TrainingDummySettingsWindow { [CompilerGenerated] private static class <>O { public static WindowFunction <0>__DrawWindow; } private const float WindowWidth = 430f; private const float WindowHeight = 260f; private static readonly TouchGrassPlugin.TrainingDummyDamageType[] DamageTypes = new TouchGrassPlugin.TrainingDummyDamageType[8] { TouchGrassPlugin.TrainingDummyDamageType.Blunt, TouchGrassPlugin.TrainingDummyDamageType.Slash, TouchGrassPlugin.TrainingDummyDamageType.Pierce, TouchGrassPlugin.TrainingDummyDamageType.Fire, TouchGrassPlugin.TrainingDummyDamageType.Frost, TouchGrassPlugin.TrainingDummyDamageType.Lightning, TouchGrassPlugin.TrainingDummyDamageType.Poison, TouchGrassPlugin.TrainingDummyDamageType.Spirit }; private static readonly string[] DamageTypeNames = Array.ConvertAll(DamageTypes, (TouchGrassPlugin.TrainingDummyDamageType type) => type.ToString()); private static Character? _target; private static Rect _windowRect = new Rect(260f, 160f, 430f, 260f); private static string _damageText = ""; private static int _damageTypeIndex; private static string _message = ""; private static GUIStyle? _messageStyle; internal static bool IsVisible => (Object)(object)_target != (Object)null; internal static void Open(Character target) { if (!((Object)(object)target == (Object)null) && TrainingDummyIdentity.IsTrainingDummy(target)) { _target = target; if (!TrainingDummyDamageTest.TryGetEffectiveDamageProfile(target, out var damageType, out var amount)) { damageType = TouchGrassPlugin._localTrainingDummyDamageType.Value; amount = TouchGrassPlugin._localTrainingDummyDamageAmount.Value; } _damageText = FormatInput(amount); _damageTypeIndex = Mathf.Max(0, Array.IndexOf(DamageTypes, damageType)); _message = ""; CenterWindowIfNeeded(); } } internal static void OnGUI() { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Invalid comparison between Unknown and I4 //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_007f: 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_008a: Expected O, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Invalid comparison between Unknown and I4 if ((Object)(object)_target == (Object)null) { return; } if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)_target == (Object)null) { Close(); return; } if (Event.current != null && (int)Event.current.type == 4 && (int)Event.current.keyCode == 27) { Close(); Event.current.Use(); return; } EnsureStyles(); Rect windowRect = _windowRect; object obj = <>O.<0>__DrawWindow; if (obj == null) { WindowFunction val = DrawWindow; <>O.<0>__DrawWindow = val; obj = (object)val; } _windowRect = GUI.Window(99150524, windowRect, (WindowFunction)obj, "TouchGrass Dummy Settings"); } internal static string GetHoverText(string existingText) { string text = "[<color=yellow><b>" + GetUseKeyLabel() + "</b></color>] Configure"; if (!string.IsNullOrWhiteSpace(existingText)) { return existingText + "\n" + text; } return text; } private static string GetUseKeyLabel() { string boundKeyLabel = GetBoundKeyLabel(ZInput.IsGamepadActive() ? "JoyUse" : "Use"); if (string.IsNullOrWhiteSpace(boundKeyLabel)) { boundKeyLabel = GetBoundKeyLabel("Use"); } if (!string.IsNullOrWhiteSpace(boundKeyLabel)) { return boundKeyLabel; } return "E"; } private static string GetBoundKeyLabel(string buttonName) { ZInput instance = ZInput.instance; string text = ((instance != null) ? instance.GetBoundKeyString(buttonName, true) : null) ?? ""; if (string.IsNullOrWhiteSpace(text)) { return ""; } string text2 = ((Localization.instance != null) ? Localization.instance.Localize(text) : text); if (!text2.Contains("$KEY_")) { return text2.Trim(); } return ""; } private static void DrawWindow(int id) { //IL_0125: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); GUILayout.Label("Damage", Array.Empty<GUILayoutOption>()); _damageText = GUILayout.TextField(_damageText, 16, Array.Empty<GUILayoutOption>()); GUILayout.Space(6f); GUILayout.Label("Damage Type", Array.Empty<GUILayoutOption>()); _damageTypeIndex = GUILayout.SelectionGrid(_damageTypeIndex, DamageTypeNames, 4, Array.Empty<GUILayoutOption>()); GUILayout.Space(8f); if (!string.IsNullOrWhiteSpace(_message)) { GUILayout.Label(_message, _messageStyle, Array.Empty<GUILayoutOption>()); } GUILayout.FlexibleSpace(); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Load Config Defaults", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) })) { LoadConfigDefaults(); } if (GUILayout.Button("Apply", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) })) { Apply(); } if (GUILayout.Button("Close", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) })) { Close(); } GUILayout.EndHorizontal(); GUILayout.EndVertical(); GUI.DragWindow(new Rect(0f, 0f, 430f, 24f)); } private static void LoadConfigDefaults() { _damageText = FormatInput(TouchGrassPlugin._localTrainingDummyDamageAmount.Value); _damageTypeIndex = Mathf.Max(0, Array.IndexOf(DamageTypes, TouchGrassPlugin._localTrainingDummyDamageType.Value)); _message = "Loaded damage defaults. Press Apply to save them to this dummy."; } private static void Apply() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_target == (Object)null) { Close(); return; } if (!TryParseFloat(_damageText, 1f, 500f, out var value)) { _message = "Damage must be between 1 and 500."; return; } if (!PrivateArea.CheckAccess(((Component)_target).transform.position, 0f, true, false)) { _message = "No access."; return; } TouchGrassPlugin.TrainingDummyDamageType damageType = DamageTypes[Mathf.Clamp(_damageTypeIndex, 0, DamageTypes.Length - 1)]; TrainingDummyDamageTest.SetDamageProfile(_target, damageType, value); _message = "Saved damage settings to this dummy."; } private static bool TryParseFloat(string text, float min, float max, out float value) { text = text.Trim().Replace(',', '.'); if (!float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out value)) { value = 0f; return false; } if (value >= min) { return value <= max; } return false; } private static string FormatInput(float value) { return value.ToString((value >= 100f) ? "0" : "0.##", CultureInfo.InvariantCulture); } private static void EnsureStyles() { //IL_0011: 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_0022: Expected O, but got Unknown if (_messageStyle == null) { _messageStyle = new GUIStyle(GUI.skin.label) { wordWrap = true }; } } private static void CenterWindowIfNeeded() { ((Rect)(ref _windowRect)).width = 430f; ((Rect)(ref _windowRect)).height = 260f; ((Rect)(ref _windowRect)).x = Mathf.Clamp(((Rect)(ref _windowRect)).x, 0f, Mathf.Max(0f, (float)Screen.width - ((Rect)(ref _windowRect)).width)); ((Rect)(ref _windowRect)).y = Mathf.Clamp(((Rect)(ref _windowRect)).y, 0f, Mathf.Max(0f, (float)Screen.height - ((Rect)(ref _windowRect)).height)); } private static void Close() { _target = null; _message = ""; GUI.FocusControl((string)null); } } internal static class TrainingMeter { internal sealed class IncomingDamageState { internal bool IsTrainingDummyHit; internal bool WasBlocking; internal float Time; internal float Health; internal float RawDamage; internal float BlockedDamage; internal string RawDamageType = ""; internal DamageTypes DamageAfterBlock; } private readonly struct OutgoingDamageEvent { internal readonly float Time; internal readonly float ImpactDamage; internal readonly float StatusDamage; public OutgoingDamageEvent(float time, float impactDamage, float statusDamage) { Time = time; ImpactDamage = impactDamage; StatusDamage = statusDamage; } } private readonly struct IncomingDamageEvent { internal readonly float Time; internal readonly float RawDamage; internal readonly string RawDamageType; internal readonly float BlockedDamage; internal readonly float ResistReduction; internal readonly float ArmorReduction; internal readonly float FinalDamage; internal readonly float StatusDamage; internal readonly string StatusDamageType; public IncomingDamageEvent(float time, float rawDamage, string rawDamageType, float blockedDamage, float resistReduction, float armorReduction, float finalDamage, float statusDamage, string statusDamageType) { Time = time; RawDamage = rawDamage; RawDamageType = rawDamageType; BlockedDamage = blockedDamage; ResistReduction = resistReduction; ArmorReduction = armorReduction; FinalDamage = finalDamage; StatusDamage = statusDamage; StatusDamageType = statusDamageType; } } private readonly struct PlayerSkillRaiseContext { internal readonly int Id; internal readonly SkillType SkillType; internal readonly float RawFactor; public PlayerSkillRaiseContext(int id, SkillType skillType, float rawFactor) { //IL_0008: 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) Id = id; SkillType = skillType; RawFactor = rawFactor; } } private readonly struct SkillGainEvent { internal readonly float Time; internal readonly SkillType SkillType; internal readonly float BaseExp; internal readonly float FinalExp; internal readonly float Efficiency; public SkillGainEvent(float time, SkillType skillType, float baseExp, float finalExp, float efficiency) { //IL_0008: 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) Time = time; SkillType = skillType; BaseExp = baseExp; FinalExp = finalExp; Efficiency = efficiency; } } private readonly struct DamageReductionBreakdown { internal readonly float ResistReduction; internal readonly float ArmorReduction; internal readonly float FinalDamage; internal readonly float StatusDamage; internal readonly string StatusDamageType; public DamageReductionBreakdown(float resistReduction, float armorReduction, float finalDamage, float statusDamage, string statusDamageType) { ResistReduction = resistReduction; ArmorReduction = armorReduction; FinalDamage = finalDamage; StatusDamage = statusDamage; StatusDamageType = statusDamageType; } } private const float HugeDamageThreshold = 1E+09f; private const string HudTitle = "TouchGrass Training Meter"; private const float HudPaddingX = 10f; private const float HudPaddingY = 8f; private const float HudLineSpacing = 2f; private const float HudHeaderSpacing = 4f; private const float HudHeightSafetyPadding = 8f; private const float HudHeightHoldSeconds = 0.35f; private const float HudScale = 1.6f; private const float HudBaseWidth = 420f; private const float DefaultHudAnchorX = 0.02f; private const float DefaultHudAnchorY = 0.86f; private static readonly List<OutgoingDamageEvent> OutgoingDamageEvents = new List<OutgoingDamageEvent>(); private static readonly List<IncomingDamageEvent> IncomingDamageEvents = new List<IncomingDamageEvent>(); private static readonly List<SkillGainEvent> SkillGainEvents = new List<SkillGainEvent>(); private static readonly List<PlayerSkillRaiseContext> PlayerSkillRaiseContexts = new List<PlayerSkillRaiseContext>(); private static readonly HashSet<SkillType> DisplayedSkillTypes = new HashSet<SkillType> { (SkillType)1, (SkillType)2, (SkillType)3, (SkillType)4, (SkillType)5, (SkillType)6, (SkillType)7, (SkillType)8, (SkillType)14, (SkillType)11, (SkillType)12, (SkillType)13, (SkillType)9, (SkillType)10 }; private static float _lastTrainingDummyInteractionTime = -9999f; private static float _lastHudHeight; private static float _lastHudHeightHoldUntil = -9999f; private static Vector2 _hudPosition; private static Vector2 _hudDragOffset; private static bool _hudPositionInitialized; private static bool _isDraggingHud; private static IncomingDamageState? _activeIncomingDamageState; private static GUIStyle? _boxStyle; private static GUIStyle? _headerStyle; private static GUIStyle? _labelStyle; private static Texture2D? _backgroundTexture; private static float _styleScale = -1f; private static int _nextSkillRaiseContextId; internal static void RecordOutgoingDamage(Character target, HitData hit) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (IsEnabled() && !((Object)(object)target == (Object)null) && hit != null && TrainingDummyIdentity.IsTrainingDummy(target) && !((Object)(object)hit.GetAttacker() != (Object)(object)Player.m_localPlayer)) { float statusDamage = GetStatusDamage(hit.m_damage); float num = Mathf.Max(0f, ((DamageTypes)(ref hit.m_damage)).GetTotalDamage() - statusDamage); if ((!(num <= 0f) || !(statusDamage <= 0f)) && !(num + statusDamage > 1E+09f)) { float time = Time.time; MarkTrainingDummyInteraction(time); OutgoingDamageEvents.Add(new OutgoingDamageEvent(time, num, statusDamage)); Prune(time); } } } internal static IncomingDamageState BeforeIncomingDamage(Character victim, HitData hit) { //IL_0095: 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) IncomingDamageState incomingDamageState = new IncomingDamageState(); if (!IsEnabled() || (Object)(object)victim == (Object)null || hit == null) { return incomingDamageState; } if ((Object)(object)victim != (Object)(object)Player.m_localPlayer) { return incomingDamageState; } _activeIncomingDamageState = null; if (!TrainingDummyIdentity.IsTrainingDummy(hit.GetAttacker())) { return incomingDamageState; } _ = Player.m_localPlayer; float time = Time.time; MarkTrainingDummyInteraction(time); incomingDamageState.IsTrainingDummyHit = true; incomingDamageState.Time = time; incomingDamageState.Health = victim.GetHealth(); incomingDamageState.WasBlocking = hit.m_blockable && victim.IsBlocking(); incomingDamageState.RawDamage = ((DamageTypes)(ref hit.m_damage)).GetTotalDamage(); incomingDamageState.RawDamageType = GetDamageTypeText(hit.m_damage); incomingDamageState.DamageAfterBlock = ((DamageTypes)(ref hit.m_damage)).Clone(); _activeIncomingDamageState = incomingDamageState; return incomingDamageState; } internal static void AfterIncomingDamage(Character victim, IncomingDamageState state) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (state != null && state.IsTrainingDummyHit && !((Object)(object)victim == (Object)null) && !((Object)(object)victim != (Object)(object)Player.m_localPlayer)) { _activeIncomingDamageState = null; DamageReductionBreakdown damageReductionBreakdown = ComputeIncomingBreakdown(Player.m_localPlayer, state.DamageAfterBlock); IncomingDamageEvents.Add(new IncomingDamageEvent(state.Time, state.RawDamage, state.RawDamageType, state.BlockedDamage, damageReductionBreakdown.ResistReduction, damageReductionBreakdown.ArmorReduction, damageReductionBreakdown.FinalDamage, damageReductionBreakdown.StatusDamage, damageReductionBreakdown.StatusDamageType)); Prune(Time.time); } } internal static void RecordBlockResult(Humanoid blocker, HitData hit) { //IL_0038: 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) if (_activeIncomingDamageState != null && _activeIncomingDamageState.IsTrainingDummyHit && !((Object)(object)blocker == (Object)null) && !((Object)(object)blocker != (Object)(object)Player.m_localPlayer) && hit != null) { _activeIncomingDamageState.DamageAfterBlock = ((DamageTypes)(ref hit.m_damage)).Clone(); _activeIncomingDamageState.BlockedDamage = Mathf.Max(0f, _activeIncomingDamageState.RawDamage - ((DamageTypes)(ref hit.m_damage)).GetTotalDamage()); } } internal static int BeginPlayerSkillRaise(Player player, SkillType skillType, float rawFactor) { //IL_0016: 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) if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || (int)skillType == 0) { return 0; } int num = ++_nextSkillRaiseContextId; PlayerSkillRaiseContexts.Add(new PlayerSkillRaiseContext(num, skillType, Mathf.Max(0f, rawFactor))); return num; } internal static void EndPlayerSkillRaise(int contextId) { if (contextId == 0) { return; } for (int num = PlayerSkillRaiseContexts.Count - 1; num >= 0; num--) { if (PlayerSkillRaiseContexts[num].Id == contextId) { PlayerSkillRaiseContexts.RemoveAt(num); break; } } } internal static void RecordSkillGain(Skills skills, SkillType skillType, float sourceFactor, float finalFactor) { //IL_0022: 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_0043: 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_0058: 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) if (!IsEnabled() || (Object)(object)skills == (Object)null || (Object)(object)skills.m_player != (Object)(object)Player.m_localPlayer || (int)skillType == 0 || !DisplayedSkillTypes.Contains(skillType)) { return; } float time = Time.time; if (IsTrainingSessionActive(time)) { float num = ComputeBaseSkillExperience(skills, skillType, GetBaseSkillFactor(skills.m_player, skillType, sourceFactor)); float num2 = ComputeSkillExperience(skills, skillType, Mathf.Max(0f, finalFactor)); if (!(num <= 0f) || !(num2 <= 0f)) { float efficiency = ((num > 0f) ? Mathf.Max(0f, num2 / num) : 1f); SkillGainEvents.Add(new SkillGainEvent(time, skillType, num, num2, efficiency)); Prune(time); } } } internal static void OnGUI() { //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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: 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_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Expected O, but got Unknown //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Expected O, but got Unknown //IL_0159: Unknown result type (might be due to invalid IL or missing references) if (!IsEnabled() || (Object)(object)Player.m_localPlayer == (Object)null) { StopHudDrag(); return; } float time = Time.time; Prune(time); if (!IsTrainingSessionActive(time)) { StopHudDrag(); return; } List<string> list = BuildHudLines(time); if (list.Count == 0) { StopHudDrag(); return; } float num = 1.6f; EnsureStyles(num); GUIStyle headerStyle = _headerStyle; GUIStyle labelStyle = _labelStyle; float num2 = 10f * num; float num3 = 8f * num; float num4 = 2f * num; float num5 = 4f * num; float hudWidth = GetHudWidth(); float num6 = hudWidth - num2 * 2f; float stableHudHeight = GetStableHudHeight(GetHudHeight(list, num6, headerStyle, labelStyle, num3, num4, num5, num), time); Rect val = GetHudRect(hudWidth, stableHudHeight); val = HandleHudDrag(val); GUI.Box(val, GUIContent.none, _boxStyle); float num7 = ((Rect)(ref val)).x + num2; float num8 = ((Rect)(ref val)).y + num3; float num9 = Mathf.Ceil(headerStyle.CalcHeight(new GUIContent("TouchGrass Training Meter"), num6)); GUI.Label(new Rect(num7, num8, num6, num9), "TouchGrass Training Meter", headerStyle); num8 += num9 + num5; foreach (string item in list) { float num10 = Mathf.Ceil(labelStyle.CalcHeight(new GUIContent(item), num6)); GUI.Label(new Rect(num7, num8, num6, num10), item, labelStyle); num8 += num10 + num4; } } private static List<string> BuildHudLines(float now) { //IL_0461: Unknown result type (might be due to invalid IL or missing references) float num = now - GetWindowSeconds(); float num2 = now; float num3 = 0f; float num4 = 0f; float num5 = 0f; int num6 = 0; int num7 = 0; OutgoingDamageEvent? outgoingDamageEvent = null; IncomingDamageEvent? incomingDamageEvent = null; SkillGainEvent? skillGainEvent = null; foreach (OutgoingDamageEvent outgoingDamageEvent2 in OutgoingDamageEvents) { if (!(outgoingDamageEvent2.Time < num)) { num2 = Mathf.Min(num2, outgoingDamageEvent2.Time); num3 = Mathf.Max(num3, outgoingDamageEvent2.Time); num4 += outgoingDamageEvent2.ImpactDamage; num5 += outgoingDamageEvent2.StatusDamage; num6++; if (!outgoingDamageEvent.HasValue || outgoingDamageEvent2.Time > outgoingDamageEvent.Value.Time) { outgoingDamageEvent = outgoingDamageEvent2; } } } foreach (IncomingDamageEvent incomingDamageEvent2 in IncomingDamageEvents) { if (!(incomingDamageEvent2.Time < num)) { num2 = Mathf.Min(num2, incomingDamageEvent2.Time); num3 = Mathf.Max(num3, incomingDamageEvent2.Time); num7++; if (!incomingDamageEvent.HasValue || incomingDamageEvent2.Time > incomingDamageEvent.Value.Time) { incomingDamageEvent = incomingDamageEvent2; } } } foreach (SkillGainEvent skillGainEvent2 in SkillGainEvents) { if (!(skillGainEvent2.Time < num)) { num2 = Mathf.Min(num2, skillGainEvent2.Time); num3 = Mathf.Max(num3, skillGainEvent2.Time); if (!skillGainEvent.HasValue || skillGainEvent2.Time > skillGainEvent.Value.Time) { skillGainEvent = skillGainEvent2; } } } if (num6 == 0 && num7 == 0 && !skillGainEvent.HasValue) { return new List<string>(); } if (num3 <= 0f) { num3 = now; } float num8 = Mathf.Max(1f, Mathf.Min(GetWindowSeconds(), now - num2)); float value = num4 / num8; float value2 = ((num6 > 0) ? (num4 / (float)num6) : 0f); List<string> list = new List<string>(); if (num6 > 0) { if (num5 > 0f) { list.Add("ToDummy: Status | Attempt | DPH | Hits | DPS | Time"); list.Add($"ToDummy: {FormatFloat(num5)} | {FormatFloat(num4)} | {FormatFloat(value2)} | {num6} | {FormatFloat(value)} | {FormatFloat(num8)}s"); } else { list.Add("ToDummy: Attempt | DPH | Hits | DPS | Time"); list.Add($"ToDummy: {FormatFloat(num4)} | {FormatFloat(value2)} | {num6} | {FormatFloat(value)} | {FormatFloat(num8)}s"); } } if (incomingDamageEvent.HasValue) { IncomingDamageEvent value3 = incomingDamageEvent.Value; string text = "Raw - Blocked - Resist - Armor = Final"; string text2 = string.Concat(FormatFloat(value3.RawDamage) + "(" + value3.RawDamageType + ") - " + FormatFloat(value3.BlockedDamage) + " - " + FormatSubtractedSigned(value3.ResistReduction) + " - " + FormatFloat(value3.ArmorReduction), " = ", FormatFloat(value3.FinalDamage)); if (value3.StatusDamage > 0f) { list.Add("FromDummy: " + text + " | Status"); list.Add("FromDummy: " + text2 + " | " + FormatFloat(value3.StatusDamage) + "(" + value3.StatusDamageType + ")"); } else { list.Add("FromDummy: " + text); list.Add("FromDummy: " + text2); } } if (skillGainEvent.HasValue) { SkillGainEvent value4 = skillGainEvent.Value; list.Add("Skill: " + FormatSkill(value4.SkillType) + " +" + FormatFloat(value4.FinalExp) + " / +" + FormatFloat(value4.BaseExp) + " base exp (" + FormatPercent(value4.Efficiency) + ")"); } return list; } private static void MarkTrainingDummyInteraction(float now) { _lastTrainingDummyInteractionTime = now; } private static bool IsTrainingSessionActive(float now) { return now - _lastTrainingDummyInteractionTime <= GetWindowSeconds(); } private static bool IsEnabled() { if (TouchGrassPlugin._trainingMeterDisplay != null) { return TouchGrassPlugin._trainingMeterDisplay.Value != TouchGrassPlugin.TrainingMeterDisplay.Off; } return false; } private static float GetWindowSeconds() { return Mathf.Clamp(TouchGrassPlugin._trainingMeterWindowSeconds?.Value ?? 15f, 5f, 300f); } private static float GetHudWidth() { return Mathf.Clamp(672f, 240f, (float)Screen.width); } private static Rect GetHudRect(float width, float height) { //IL_002f: 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_0056: 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_0024: Unknown result type (might be due to invalid IL or missing references) if (!_hudPositionInitialized) { _hudPosition = new Vector2(0.02f * (float)Screen.width, 0.13999999f * (float)Screen.height); _hudPositionInitialized = true; } _hudPosition = ClampHudPosition(_hudPosition, width, height); return new Rect(_hudPosition.x, _hudPosition.y, width, height); } private static Rect HandleHudDrag(Rect rect) { //IL_0009: 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_0025: 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_003c: Expected I4, but got Unknown //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: 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_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_0082: 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_00a4: 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_00bc: 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_00c8: Unknown result type (might be due to invalid IL or missing references) Event current = Event.current; if (current == null) { return rect; } if (_isDraggingHud && !Input.GetMouseButton(0)) { StopHudDrag(); } EventType type = current.type; switch ((int)type) { case 0: if (current.button == 0 && ((Rect)(ref rect)).Contains(current.mousePosition)) { _isDraggingHud = true; _hudDragOffset = current.mousePosition - new Vector2(((Rect)(ref rect)).x, ((Rect)(ref rect)).y); current.Use(); } break; case 3: if (current.button == 0 && _isDraggingHud) { _hudPosition = ClampHudPosition(current.mousePosition - _hudDragOffset, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height); ((Rect)(ref rect)).position = _hudPosition; current.Use(); } break; case 1: if (current.button == 0 && _isDraggingHud) { _isDraggingHud = false; current.Use(); } break; } if (_isDraggingHud) { ((Rect)(ref rect)).position = _hudPosition; } return rect; } private static void StopHudDrag() { _isDraggingHud = false; } private static Vector2 ClampHudPosition(Vector2 position, float width, float height) { //IL_0002: 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_0052: Unknown result type (might be due to invalid IL or missing references) position.x = Mathf.Clamp(position.x, 0f, Mathf.Max(0f, (float)Screen.width - width)); position.y = Mathf.Clamp(position.y, 0f, Mathf.Max(0f, (float)Screen.height - height)); return position; } private static float GetHudHeight(List<string> lines, float contentWidth, GUIStyle headerStyle, GUIStyle labelStyle, float paddingY, float lineSpacing, float headerSpacing, float scale) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown float num = paddingY * 2f; num += Mathf.Ceil(headerStyle.CalcHeight(new GUIContent("TouchGrass Training Meter"), contentWidth)) + headerSpacing; foreach (string line in lines) { num += Mathf.Ceil(labelStyle.CalcHeight(new GUIContent(line), contentWidth)) + lineSpacing; } return num + 8f * scale; } private static float GetStableHudHeight(float desiredHeight, float now) { if (desiredHeight >= _lastHudHeight) { _lastHudHeight = desiredHeight; _lastHudHeightHoldUntil = now + 0.35f; return desiredHeight; } if (now <= _lastHudHeightHoldUntil) { return _lastHudHeight; } _lastHudHeight = desiredHeight; _lastHudHeightHoldUntil = now + 0.35f; return desiredHeight; } private static void Prune(float now) { float oldest = now - GetWindowSeconds(); OutgoingDamageEvents.RemoveAll((OutgoingDamageEvent e) => e.Time < oldest); IncomingDamageEvents.RemoveAll((IncomingDamageEvent e) => e.Time < oldest); SkillGainEvents.RemoveAll((SkillGainEvent e) => e.Time < oldest); } private static float ComputeSkillExperience(Skills skills, SkillType skillType, float factor) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (factor <= 0f) { return 0f; } Skill skill = skills.GetSkill(skillType); if (skill == null || skill.m_level >= 100f) { return 0f; } return skill.m_info.m_increseStep * factor * Game.m_skillGainRate; } private static float ComputeBaseSkillExperience(Skills skills, SkillType skillType, float factor) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (factor <= 0f) { return 0f; } Skill skill = skills.GetSkill(skillType); if (skill == null || skill.m_level >= 100f) { return 0f; } return skill.m_info.m_increseStep * factor; } private static float GetBaseSkillFactor(Player player, SkillType skillType, float fallbackFactor) { //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) for (int num = PlayerSkillRaiseContexts.Count - 1; num >= 0; num--) { PlayerSkillRaiseContext playerSkillRaiseContext = PlayerSkillRaiseContexts[num]; if (playerSkillRaiseContext.SkillType == skillType) { return playerSkillRaiseContext.RawFactor; } } return Mathf.Max(0f, fallbackFactor); } private static DamageReductionBreakdown ComputeIncomingBreakdown(Player player, DamageTypes damageAfterBlock) { //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_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown //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) //IL_008f: Unknown result type (might be due to invalid IL or missing references) HitData val = new HitData { m_damage = ((DamageTypes)(ref damageAfterBlock)).Clone() }; float totalDamage = ((DamageTypes)(ref val.m_damage)).GetTotalDamage(); DamageModifier val2 = default(DamageModifier); val.ApplyResistance(((Character)player).GetDamageModifiers((WeakSpot)null), ref val2); float totalDamage2 = ((DamageTypes)(ref val.m_damage)).GetTotalDamage(); val.ApplyArmor(((Character)player).GetBodyArmor()); float totalDamage3 = ((DamageTypes)(ref val.m_damage)).GetTotalDamage(); float statusDamage = GetStatusDamage(val.m_damage); float num = Mathf.Max(0f, totalDamage3 - statusDamage); if (num <= 0.1f) { num = 0f; } return new DamageReductionBreakdown(totalDamage - totalDamage2, Mathf.Max(0f, totalDamage2 - totalDamage3), num, statusDamage, GetStatusDamageTypeText(val.m_damage)); } private static float GetStatusDamage(DamageTypes damage) { //IL_0005: 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) //IL_0026: Unknown result type (might be due to invalid IL or missing references) return Mathf.Max(0f, damage.m_fire) + Mathf.Max(0f, damage.m_poison) + Mathf.Max(0f, damage.m_spirit); } private static string GetStatusDamageTypeText(DamageTypes damage) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due