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.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.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]
[Microsoft.CodeAnalysis.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]
[Microsoft.CodeAnalysis.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.0")]
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
}
[CompilerGenerated]
private sealed class <GetConfigurableSkillTypes>d__43 : IEnumerable<SkillType>, IEnumerable, IEnumerator<SkillType>, IDisposable, IEnumerator
{
private int <>1__state;
private SkillType <>2__current;
private int <>l__initialThreadId;
private IEnumerator <>7__wrap1;
SkillType IEnumerator<SkillType>.Current
{
[DebuggerHidden]
get
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
return <>2__current;
}
}
[DebuggerHidden]
public <GetConfigurableSkillTypes>d__43(int <>1__state)
{
this.<>1__state = <>1__state;
<>l__initialThreadId = Environment.CurrentManagedThreadId;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
int num = <>1__state;
if (num == -3 || num == 1)
{
try
{
}
finally
{
<>m__Finally1();
}
}
<>7__wrap1 = null;
<>1__state = -2;
}
private bool MoveNext()
{
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: 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_005a: Invalid comparison between Unknown and I4
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
try
{
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<>7__wrap1 = Enum.GetValues(typeof(SkillType)).GetEnumerator();
<>1__state = -3;
break;
case 1:
<>1__state = -3;
break;
}
while (<>7__wrap1.MoveNext())
{
SkillType val = (SkillType)<>7__wrap1.Current;
if (((int)val != 0 && (int)val != 999) || 1 == 0)
{
<>2__current = val;
<>1__state = 1;
return true;
}
}
<>m__Finally1();
<>7__wrap1 = null;
return false;
}
catch
{
//try-fault
((IDisposable)this).Dispose();
throw;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
private void <>m__Finally1()
{
<>1__state = -1;
if (<>7__wrap1 is IDisposable disposable)
{
disposable.Dispose();
}
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
[DebuggerHidden]
IEnumerator<SkillType> IEnumerable<SkillType>.GetEnumerator()
{
if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
{
<>1__state = 0;
return this;
}
return new <GetConfigurableSkillTypes>d__43(0);
}
[DebuggerHidden]
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<SkillType>)this).GetEnumerator();
}
}
internal const string ModName = "TouchGrass";
internal const string ModVersion = "1.0.0";
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<float> _archeryTargetSkillMultiplier;
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_020f: Unknown result type (might be due to invalid IL or missing references)
//IL_021a: Expected O, but got Unknown
//IL_023d: Unknown result type (might be due to invalid IL or missing references)
//IL_0248: Expected O, but got Unknown
//IL_0292: Unknown result type (might be due to invalid IL or missing references)
//IL_029d: Expected O, but got Unknown
//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
//IL_02f2: 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.");
_archeryTargetSkillMultiplier = config("1 - General", "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>()));
_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>()));
_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);
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();
}
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();
if (saveOnConfigSet)
{
((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet;
}
}
private 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())
{
SkillType current = configurableSkillType;
string name = ((object)(SkillType)(ref current)).ToString();
_skillGainRates[current] = 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[current] = 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();
};
_archeryTargetSkillMultiplier.SettingChanged += delegate
{
TrainingObjectTuning.ApplyAll();
};
}
[IteratorStateMachine(typeof(<GetConfigurableSkillTypes>d__43))]
private static IEnumerable<SkillType> GetConfigurableSkillTypes()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <GetConfigurableSkillTypes>d__43(-2);
}
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.0",
MinimumRequiredVersion = "1.0.0"
};
_serverConfigLocked = null;
_locationFullEfficiencySeconds = null;
_locationFadeSeconds = null;
_locationMinimumMultiplier = null;
_stationaryRadius = null;
_fatigueStationarySkillGains = null;
_fatigueStatusEffectDisplay = null;
_trainingDummyHealth = null;
_trainingDummyCrowdingRadius = null;
_trainingDummyCrowdingMaxCount = null;
_archeryTargetSkillMultiplier = null;
_localTrainingDummyDamageType = null;
_localTrainingDummyDamageAmount = null;
_trainingMeterDisplay = null;
_trainingMeterWindowSeconds = null;
_skillGainRates = new Dictionary<SkillType, ConfigEntry<float>>();
_skillReductionRates = new Dictionary<SkillType, ConfigEntry<float>>();
}
}
[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(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), "Damage")]
internal static class CharacterDamagePatch
{
private static void Prefix(Character __instance, HitData hit)
{
TrainingMeter.RecordOutgoingDamage(__instance, hit);
}
}
[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(ZNetScene), "Awake")]
internal static class ZNetSceneAwakePatch
{
private static void Postfix(ZNetScene __instance)
{
TrainingObjectTuning.ApplyPrefabTuning(__instance);
}
}
[HarmonyPatch(typeof(Piece), "SetCreator")]
internal static class PieceSetCreatorPatch
{
private static void Postfix(Piece __instance)
{
TrainingDummyDamageTest.StampPlacedDamageProfile(__instance);
}
}
internal static class SkillEarnGate
{
internal readonly struct FatigueSnapshot
{
internal static readonly FatigueSnapshot Empty = new FatigueSnapshot(1f);
internal readonly float FinalMultiplier;
internal readonly float GlobalMultiplier;
public FatigueSnapshot(float globalMultiplier)
{
FinalMultiplier = globalMultiplier;
GlobalMultiplier = globalMultiplier;
}
}
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.FinalMultiplier * 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 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)(ref skillType)).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)(ref skillType)).ToString();
}
return "Fists";
}
}
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;
}
}
private const string TrainingDummyLocalizationKey = "$piece_trainingdummy";
private static readonly int PieceTrainingDummyPrefabHash = StringExtensionMethods.GetStableHashCode("piece_TrainingDummy");
private static readonly int TrainingDummyPrefabHash = StringExtensionMethods.GetStableHashCode("TrainingDummy");
private const string DummyDamageProfileVersionKey = "TouchGrass_DummyDamageProfileVersion";
private const string DummyDamageTypeKey = "TouchGrass_DummyDamageType";
private const string DummyDamageAmountKey = "TouchGrass_DummyDamageAmount";
private 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 (IsTrainingDummy(attacker) && (TryGetStampedDamageProfile(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 || !IsTrainingDummy(piece) || !TryGetLocalDamageProfile(out var profile))
{
return;
}
ZNetView val = (((Object)(object)piece.m_nview != (Object)null) ? piece.m_nview : ((Component)piece).GetComponent<ZNetView>());
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 IsTrainingDummy(Character attacker)
{
if ((Object)(object)attacker == (Object)null)
{
return false;
}
if (attacker.m_name == "$piece_trainingdummy")
{
return true;
}
if (HasTrainingDummyPrefab(attacker))
{
return true;
}
return IsTrainingDummyPrefabName(Utils.GetPrefabName(((Component)attacker).gameObject));
}
internal static bool IsTrainingDummy(Piece piece)
{
if ((Object)(object)piece == (Object)null)
{
return false;
}
if (piece.m_name == "$piece_trainingdummy")
{
return true;
}
ZNetView val = (((Object)(object)piece.m_nview != (Object)null) ? piece.m_nview : ((Component)piece).GetComponent<ZNetView>());
if ((Object)(object)val != (Object)null && val.IsValid() && val.GetZDO() != null && IsTrainingDummyPrefabHash(val.GetZDO().GetPrefab()))
{
return true;
}
return IsTrainingDummyPrefabName(Utils.GetPrefabName(((Component)piece).gameObject));
}
internal static bool HasTrainingDummyPrefab(Character character)
{
if ((Object)(object)character == (Object)null)
{
return false;
}
ZNetView val = (((Object)(object)character.m_nview != (Object)null) ? character.m_nview : ((Component)character).GetComponent<ZNetView>());
if ((Object)(object)val == (Object)null)
{
return false;
}
if (val.IsValid() && val.GetZDO() != null && IsTrainingDummyPrefabHash(val.GetZDO().GetPrefab()))
{
return true;
}
return IsTrainingDummyPrefabName(val.GetPrefabName());
}
internal static bool HasTrainingDummyZdoPrefab(Character character)
{
if ((Object)(object)character == (Object)null)
{
return false;
}
ZNetView val = (((Object)(object)character.m_nview != (Object)null) ? character.m_nview : ((Component)character).GetComponent<ZNetView>());
if ((Object)(object)val != (Object)null && val.IsValid() && val.GetZDO() != null)
{
return IsTrainingDummyPrefabHash(val.GetZDO().GetPrefab());
}
return false;
}
private static bool TryGetStampedDamageProfile(Character attacker, out DamageProfile profile)
{
profile = default(DamageProfile);
ZNetView component = ((Component)attacker).GetComponent<ZNetView>();
if ((Object)(object)component == (Object)null || !component.IsValid())
{
return false;
}
ZDO zDO = component.GetZDO();
if (zDO == null)
{
return false;
}
int @int = zDO.GetInt("TouchGrass_DummyDamageType", -1);
if (!Enum.IsDefined(typeof(TouchGrassPlugin.TrainingDummyDamageType), @int))
{
return false;
}
float @float = zDO.GetFloat("TouchGrass_DummyDamageAmount", 0f);
if (@float <= 0f)
{
return false;
}
profile = new DamageProfile((TouchGrassPlugin.TrainingDummyDamageType)@int, @float);
return true;
}
private static bool TryGetLocalDamageProfile(out DamageProfile profile)
{
profile = new DamageProfile(TouchGrassPlugin._localTrainingDummyDamageType.Value, TouchGrassPlugin._localTrainingDummyDamageAmount.Value);
return true;
}
private static bool IsTrainingDummyPrefabName(string prefabName)
{
if (string.IsNullOrEmpty(prefabName))
{
return false;
}
if (!string.Equals(prefabName, "TrainingDummy", StringComparison.OrdinalIgnoreCase))
{
return string.Equals(prefabName, "piece_TrainingDummy", StringComparison.OrdinalIgnoreCase);
}
return true;
}
private static bool IsTrainingDummyPrefabHash(int prefabHash)
{
if (prefabHash != PieceTrainingDummyPrefabHash)
{
return prefabHash == TrainingDummyPrefabHash;
}
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 TrainingObjectTuning
{
private static readonly string[] TrainingDummyPrefabNames = new string[2] { "piece_TrainingDummy", "TrainingDummy" };
internal static void ApplyAll()
{
ApplyPrefabTuning();
ApplyLoadedTrainingDummies();
ApplyLoadedArcheryTargets();
}
internal static void ApplyPrefabTuning(ZNetScene? scene = null)
{
if (scene == null)
{
scene = ZNetScene.instance;
}
if ((Object)(object)scene == (Object)null)
{
return;
}
string[] trainingDummyPrefabNames = TrainingDummyPrefabNames;
foreach (string text in trainingDummyPrefabNames)
{
GameObject prefab = scene.GetPrefab(text);
if (!((Object)(object)prefab == (Object)null))
{
Character componentInChildren = prefab.GetComponentInChildren<Character>(true);
if ((Object)(object)componentInChildren != (Object)null)
{
ApplyTrainingDummy(componentInChildren);
}
}
}
GameObject prefab2 = scene.GetPrefab("piece_ArcheryTarget");
if ((Object)(object)prefab2 != (Object)null)
{
ArcheryTarget componentInChildren2 = prefab2.GetComponentInChildren<ArcheryTarget>(true);
if ((Object)(object)componentInChildren2 != (Object)null)
{
ApplyArcheryTarget(componentInChildren2);
}
}
}
internal static void ApplyTrainingDummy(Character character)
{
if (!((Object)(object)character == (Object)null) && TrainingDummyDamageTest.IsTrainingDummy(character))
{
float trainingDummyHealth = GetTrainingDummyHealth();
ZNetView nview = character.m_nview;
bool flag = (Object)(object)nview != (Object)null && nview.IsValid();
float num = Mathf.Max(0.001f, flag ? character.GetMaxHealth() : character.m_health);
float num2 = Mathf.Max(0f, flag ? character.GetHealth() : num);
float num3 = Mathf.Clamp01(num2 / num);
bool flag2 = num2 >= num - 0.01f;
character.m_health = trainingDummyHealth;
if (!((Object)(object)nview == (Object)null) && nview.IsValid() && nview.IsOwner())
{
character.SetMaxHealth(trainingDummyHealth);
character.SetHealth(flag2 ? trainingDummyHealth : Mathf.Clamp(trainingDummyHealth * num3, 0f, trainingDummyHealth));
}
}
}
internal static void ApplyArcheryTarget(ArcheryTarget archeryTarget)
{
if (!((Object)(object)archeryTarget == (Object)null))
{
archeryTarget.m_raiseSkillMultiplier = GetArcheryTargetSkillMultiplier();
}
}
private static void ApplyLoadedTrainingDummies()
{
foreach (Character loadedDummy in TrainingDummyRegistry.GetLoadedDummies())
{
ApplyTrainingDummy(loadedDummy);
}
}
private static void ApplyLoadedArcheryTargets()
{
ArcheryTarget[] array = Object.FindObjectsByType<ArcheryTarget>((FindObjectsSortMode)0);
for (int i = 0; i < array.Length; i++)
{
ApplyArcheryTarget(array[i]);
}
}
private static float GetTrainingDummyHealth()
{
return Mathf.Clamp(TouchGrassPlugin._trainingDummyHealth?.Value ?? 2500f, 1f, 100000f);
}
private static float GetArcheryTargetSkillMultiplier()
{
return Mathf.Clamp(TouchGrassPlugin._archeryTargetSkillMultiplier?.Value ?? 1f, 0f, 10f);
}
}
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) && TrainingDummyDamageTest.HasTrainingDummyZdoPrefab(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 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 || !TrainingDummyDamageTest.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 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 SkillGainEvent
{
internal readonly float Time;
internal readonly SkillType SkillType;
internal readonly float SourceExp;
internal readonly float FinalExp;
internal readonly float Efficiency;
public SkillGainEvent(float time, SkillType skillType, float sourceExp, 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;
SourceExp = sourceExp;
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 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;
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 && TrainingDummyDamageTest.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 (!TrainingDummyDamageTest.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 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_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
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 = ComputeSkillExperience(skills, skillType, sourceFactor);
float num2 = ComputeSkillExperience(skills, skillType, Mathf.Max(0f, finalFactor));
if (!(num <= 0f) || !(num2 <= 0f))
{
float efficiency = ((num > 0f) ? Mathf.Clamp01(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.SourceExp) + " 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 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 to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
string name = "Status";
float value = 0f;
UseIfHigher("Fire", damage.m_fire);
UseIfHigher("Poison", damage.m_poison);
UseIfHigher("Spirit", damage.m_spirit);
if (!(value > 0f))
{
return "";
}
return name;
void UseIfHigher(string candidateName, float candidateValue)
{
if (candidateValue > value)
{
name = candidateName;
value = candidateValue;
}
}
}
private static string GetDamageTypeText(DamageTypes damage)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: 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_009c: Unknown result type (might be due to invalid IL or missing references)
string name = "Generic";
float value = damage.m_damage;
UseIfHigher("Blunt", damage.m_blunt);
UseIfHigher("Slash", damage.m_slash);
UseIfHigher("Pierce", damage.m_pierce);
UseIfHigher("Fire", damage.m_fire);
UseIfHigher("Frost", damage.m_frost);
UseIfHigher("Lightning", damage.m_lightning);
UseIfHigher("Poison", damage.m_poison);
UseIfHigher("Spirit", damage.m_spirit);
if (!(value > 0f))
{
return "None";
}
return name;
void UseIfHigher(string candidateName, float candidateValue)
{
if (candidateValue > value)
{
name = candidateName;
value = candidateValue;
}
}
}
private static string FormatSkill(SkillType skillType)
{
//IL_0000: 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)
if ((int)skillType == 0)
{
return "-";
}
return SkillNameFormatter.Format(skillType);
}
private static string FormatFloat(float value)
{
if (value >= 100f)
{
return value.ToString("0");
}
if (!(value >= 10f))
{
return value.ToString("0.00");
}
return value.ToString("0.0");
}
private static string FormatPercent(float value)
{
return $"{Mathf.RoundToInt(Mathf.Clamp01(value) * 100f)}%";
}
private static string FormatSigned(float value)
{
if (!(value >= 0f))
{
return "- " + FormatFloat(Mathf.Abs(value));
}
return "+ " + FormatFloat(value);
}
private static string FormatSubtractedSigned(float value)
{
if (!(value >= 0f))
{
return "(" + FormatSigned(value) + ")";
}
return FormatFloat(value);
}
private static void EnsureStyles(float scale)
{
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: 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_00d9: Expected O, but got Unknown
//IL_00de: Expected O, but got Unknown
//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
//IL_0105: Unknown result type (might be due to invalid IL or missing references)
//IL_0111: Expected O, but got Unknown
//IL_012f: Unknown result type (might be due to invalid IL or missing references)
//IL_0143: Unknown result type (might be due to invalid IL or missing references)
//IL_0148: Unknown result type (might be due to invalid IL or missing references)
//IL_0160: Unknown result type (might be due to invalid IL or missing references)
//IL_0167: Unknown result type (might be due to invalid IL or missing references)
//IL_0173: Expected O, but got Unknown
//IL_017d: 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_0044: Expected O, but got Unknown
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
if (_boxStyle == null || _headerStyle == null || _labelStyle == null || !Mathf.Approximately(_styleScale, scale))
{
_styleScale = scale;
if ((Object)(object)_backgroundTexture == (Object)null)
{
_backgroundTexture = new Texture2D(1, 1, (TextureFormat)4, false);
_backgroundTexture.SetPixel(0, 0, new Color(0.04f, 0.06f, 0.05f, 0.82f));
_backgroundTexture.Apply(false, true);
Object.DontDestroyOnLoad((Object)(object)_backgroundTexture);
}
GUIStyle val = new GUIStyle(GUI.skin.box);
val.normal.background = _backgroundTexture;
val.border = new RectOffset(Mathf.RoundToInt(8f * scale), Mathf.RoundToInt(8f * scale), Mathf.RoundToInt(8f * scale), Mathf.RoundToInt(8f * scale));
_boxStyle = val;
_headerStyle = new GUIStyle(GUI.skin.label)
{
fontSize = Mathf.Max(8, Mathf.RoundToInt(14f * scale)),
richText = false
};
_headerStyle.normal.textColor = new Color(0.82f, 1f, 0.78f, 1f);
_labelStyle = new GUIStyle(GUI.skin.label)
{
fontSize = Mathf.Max(8, Mathf.RoundToInt(13f * scale)),
richText = false,
wordWrap = true
};
_labelStyle.normal.textColor = Color.white;
}
}
}
[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
public static class RegisterAndCheckVersion
{
private static void Prefix(ZNetPeer peer, ref ZNet __instance)
{
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Expected O, but got Unknown
TouchGrassPlugin.TouchGrassLogger.LogDebug((object)"Registering version RPC handler");
peer.m_rpc.Register<ZPackage>("TouchGrass_VersionCheck", (Action<ZRpc, ZPackage>)RpcHandlers.RPC_TouchGrass_Version);
TouchGrassPlugin.TouchGrassLogger.LogInfo((object)"Invoking version check");
ZPackage val = new ZPackage();
val.Write("1.0.0");
peer.m_rpc.Invoke("TouchGrass_VersionCheck", new object[1] { val });
}
}
[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
public static class VerifyClient
{
private static bool Prefix(ZRpc rpc, ZPackage pkg, ref ZNet __instance)
{
if (!__instance.IsServer() || RpcHandlers.ValidatedPeers.Contains(rpc))
{
return true;
}
TouchGrassPlugin.TouchGrassLogger.LogWarning((object)("Peer (" + rpc.m_socket.GetHostName() + ") never sent version or couldn't due to previous disconnect, disconnecting"));
rpc.Invoke("Error", new object[1] { 3 });
return false;
}
private static void Postfix(ZNet __instance)
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Expected O, but got Unknown
ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "TouchGrassRequestAdminSync", new object[1] { (object)new ZPackage() });
}
}
[HarmonyPatch(typeof(FejdStartup), "ShowConnectError")]
public class ShowConnectionError
{
private static void Postfix(FejdStartup __instance)
{
if (__instance.m_connectionFailedPanel.activeSelf)
{
__instance.m_connectionFailedError.fontSizeMax = 25f;
__instance.m_connectionFailedError.fontSizeMin = 15f;
TMP_Text connectionFailedError = __instance.m_connectionFailedError;
connectionFailedError.text = connectionFailedError.text + "\n" + TouchGrassPlugin.ConnectionError;
}
}
}
[HarmonyPatch(typeof(ZNet), "Disconnect")]
public static class RemoveDisconnectedPeerFromVerified
{
private static void Prefix(ZNetPeer peer, ref ZNet __instance)
{
if (__instance.IsServer())
{
TouchGrassPlugin.TouchGrassLogger.LogInfo((object)("Peer (" + peer.m_rpc.m_socket.GetHostName() + ") disconnected, removing from validated list"));
RpcHandlers.ValidatedPeers.Remove(peer.m_rpc);
}
}
}
public static class RpcHandlers
{
public static readonly List<ZRpc> ValidatedPeers = new List<ZRpc>();
public static void RPC_TouchGrass_Version(ZRpc rpc, ZPackage pkg)
{
string text = pkg.ReadString();
TouchGrassPlugin.TouchGrassLogger.LogInfo((object)("Version check, local: 1.0.0, remote: " + text));
if (text != "1.0.0")
{
TouchGrassPlugin.ConnectionError = "TouchGrass Installed: 1.0.0\n Needed: " + text;
if (ZNet.instance.IsServer())
{
TouchGrassPlugin.TouchGrassLogger.LogWarning((object)("Peer (" + rpc.m_socket.GetHostName() + ") has incompatible version, disconnecting..."));
rpc.Invoke("Error", new object[1] { 3 });
}
}
else if (!ZNet.instance.IsServer())
{
TouchGrassPlugin.TouchGrassLogger.LogInfo((object)"Received same version from server!");
}
else
{
TouchGrassPlugin.TouchGrassLogger.LogInfo((object)("Adding peer (" + rpc.m_socket.GetHostName() + ") to validated list"));
ValidatedPeers.Add(rpc);
}
}
}
}
namespace ServerSync
{
[PublicAPI]
internal abstract class OwnConfigEntryBase
{
public object? LocalBaseValue;
public bool SynchronizedConfig = true;
public abstract ConfigEntryBase BaseConfig { get; }
}
[PublicAPI]
internal class SyncedConfigEntry<T> : OwnConfigEntryBase
{
public readonly ConfigEntry<T> SourceConfig;
public override ConfigEntryBase BaseConfig => (ConfigEntryBase)(object)SourceConfig;
public T Value
{
get
{
return SourceConfig.Value;
}
set
{
SourceConfig.Value = value;
}
}
public SyncedConfigEntry(ConfigEntry<T> sourceConfig)
{
SourceConfig = sourceConfig;
base..ctor();
}
public void AssignLocalValue(T value)
{
if (LocalBaseValue == null)
{
Value = value;
}
else
{
LocalBaseValue = value;
}
}
}
internal abstract class CustomSyncedValueBase
{
public object? LocalBaseValue;
public readonly string Identifier;
public readonly Type Type;
private object? boxedValue;
protected bool localIsOwner;
public readonly int Priority;
public object? BoxedValue
{
get
{
return boxedValue;
}
set
{
boxedValue = value;
this.ValueChanged?.Invoke();
}
}
public event Action? ValueChanged;
protected CustomSyncedValueBase(ConfigSync configSync, string identifier, Type type, int priority)
{
Priority = priority;
Identifier = identifier;
Type = type;
configSync.AddCustomValue(this);
localIsOwner = configSync.IsSourceOfTruth;
configSync.SourceOfTruthChanged += delegate(bool truth)
{
localIsOwner = truth;
};
}
}
[PublicAPI]
internal sealed class CustomSyncedValue<T> : CustomSyncedValueBase
{
public T Value
{
get
{
return (T)base.BoxedValue;
}
set
{
base.BoxedValue = value;
}
}
public CustomSyncedValue(ConfigSync configSync, string identifier, T value = default(T), int priority = 0)
: base(configSync, identifier, typeof(T), priority)
{
Value = value;
}
public void AssignLocalValue(T value)
{
if (localIsOwner)
{
Value = value;
}
else
{
LocalBaseValue = value;
}
}
}
internal class ConfigurationManagerAttributes
{
[UsedImplicitly]
public bool? ReadOnly = false;
}
[PublicAPI]
internal class ConfigSync
{
[HarmonyPatch(typeof(ZRpc), "HandlePackage")]
private static class SnatchCurrentlyHandlingRPC
{
public static ZRpc? currentRpc;
[HarmonyPrefix]
private static void Prefix(ZRpc __instance)
{
currentRpc = __instance;
}
}
[HarmonyPatch(typeof(ZNet), "Awake")]
internal static class RegisterRPCPatch
{
[HarmonyPostfix]
private static void Postfix(ZNet __instance)
{
isServer = __instance.IsServer();
foreach (ConfigSync configSync2 in configSyncs)
{
ZRoutedRpc.instance.Register<ZPackage>(configSync2.Name + " ConfigSync", (Action<long, ZPackage>)configSync2.RPC_FromOtherClientConfigSync);
if (isServer)
{
configSync2.InitialSyncDone = true;
Debug.Log((object)("Registered '" + configSync2.Name + " ConfigSync' RPC - waiting for incoming connections"));
}
}
if (isServer)
{
((MonoBehaviour)__instance).StartCoroutine(WatchAdminListChanges());
}
static void SendAdmin(List<ZNetPeer> peers, bool isAdmin)
{
ZPackage package = ConfigsToPackage(null, null, new PackageEntry[1]
{
new PackageEntry
{
section = "Internal",
key = "lockexempt",
type = typeof(bool),
value = isAdmin
}
});
ConfigSync configSync = configSyncs.First();
if (configSync != null)
{
((MonoBehaviour)ZNet.instance).StartCoroutine(configSync.sendZPackage(peers, package));
}
}
static IEnumerator WatchAdminListChanges()
{
MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null);
SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance);
List<string> CurrentList = new List<string>(adminList.GetList());
while (true)
{
yield return (object)new WaitForSeconds(30f);
if (!adminList.GetList().SequenceEqual(CurrentList))
{
CurrentList = new List<string>(adminList.GetList());
List<ZNetPeer> adminPeer = ZNet.instance.GetPeers().Where(delegate(ZNetPeer p)
{
string hostName = p.m_rpc.GetSocket().GetHostName();
return ((object)listContainsId == null) ? adminList.Contains(hostName) : ((bool)listContainsId.Invoke(ZNet.instance, new object[2] { adminList, hostName }));
}).ToList();
List<ZNetPeer> nonAdminPeer = ZNet.instance.GetPeers().Except(adminPeer).ToList();
SendAdmin(nonAdminPeer, isAdmin: false);
SendAdmin(adminPeer, isAdmin: true);
}
}
}
}
}
[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
private static class RegisterClientRPCPatch
{
[HarmonyPostfix]
private static void Postfix(ZNet __instance, ZNetPeer peer)
{
if (__instance.IsServer())
{
return;
}
foreach (ConfigSync configSync in configSyncs)
{
peer.m_rpc.Register<ZPackage>(configSync.Name + " ConfigSync", (Action<ZRpc, ZPackage>)configSync.RPC_FromServerConfigSync);
}
}
}
private class ParsedConfigs
{
public readonly Dictionary<OwnConfigEntryBase, object?> configValues = new Dictionary<OwnConfigEntryBase, object>();
public readonly Dictionary<CustomSyncedValueBase, object?> customValues = new Dictionary<CustomSyncedValueBase, object>();
}
[HarmonyPatch(typeof(ZNet), "Shutdown")]
private class ResetConfigsOnShutdown
{
[HarmonyPostfix]
private static void Postfix()
{
ProcessingServerUpdate = true;
foreach (ConfigSync configSync in configSyncs)
{
configSync.resetConfigsFromServer();
configSync.IsSourceOfTruth = true;
configSync.InitialSyncDone = false;
}
ProcessingServerUpdate = false;
}
}
[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
private class SendConfigsAfterLogin
{
private class BufferingSocket : ZPlayFabSocket, ISocket
{
public volatile bool finished = false;
public volatile int versionMatchQueued = -1;
public readonly List<ZPackage> Package = new List<ZPackage>();
public readonly ISocket Original;
public BufferingSocket(ISocket original)
{
Original = original;
((ZPlayFabSocket)this)..ctor();
}
public bool IsConnected()
{
return Original.IsConnected();
}
public ZPackage Recv()
{
return Original.Recv();
}
public int GetSendQueueSize()
{
return Original.GetSendQueueSize();
}
public int GetCurrentSendRate()
{
return Original.GetCurrentSendRate();
}
public bool IsHost()
{
return Original.IsHost();
}
public void Dispose()
{
Original.Dispose();
}
public bool GotNewData()
{
return Original.GotNewData();
}
public void Close()
{
Original.Close();
}
public string GetEndPointString()
{
return Original.GetEndPointString();
}
public void GetAndResetStats(out int totalSent, out int totalRecv)
{
Original.GetAndResetStats(ref totalSent, ref totalRecv);
}
public void GetConnectionQuality(out float localQuality, out float remoteQuality, out int ping, out float outByteSec, out float inByteSec)
{
Original.GetConnectionQuality(ref localQuality, ref remoteQuality, ref ping, ref outByteSec, ref inByteSec);
}
public ISocket Accept()
{
return Original.Accept();
}
public int GetHostPort()
{
return Original.GetHostPort();
}
public bool Flush()
{
return Original.Flush();
}
public string GetHostName()
{
return Original.GetHostName();
}
public void VersionMatch()
{
if (finished)
{
Original.VersionMatch();
}
else
{
versionMatchQueued = Package.Count;
}
}
public void Send(ZPackage pkg)
{
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Expected O, but got Unknown
int pos = pkg.GetPos();
pkg.SetPos(0);
int num = pkg.ReadInt();
if ((num == StringExtensionMethods.GetStableHashCode("PeerInfo") || num == StringExtensionMethods.GetStableHashCode("RoutedRPC") || num == StringExtensionMethods.GetStableHashCode("ZDOData")) && !finished)
{
ZPackage val = new ZPackage(pkg.GetArray());
val.SetPos(pos);
Package.Add(val);
}
else
{
pkg.SetPos(pos);
Original.Send(pkg);
}
}
}
[HarmonyPriority(800)]
[HarmonyPrefix]
private static void Prefix(ref Dictionary<Assembly, BufferingSocket>? __state, ZNet __instance, ZRpc rpc)
{
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Invalid comparison between Unknown and I4
if (!__instance.IsServer())
{
return;
}
BufferingSocket bufferingSocket = new BufferingSocket(rpc.GetSocket());
AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, bufferingSocket);
object? obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc });
ZNetPeer val = (ZNetPeer)((obj is ZNetPeer) ? obj : null);
if (val != null && (int)ZNet.m_onlineBackend > 0)
{
FieldInfo fieldInfo = AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket");
object? value = fieldInfo.GetValue(val);
ZPlayFabSocket val2 = (ZPlayFabSocket)((value is ZPlayFabSocket) ? value : null);
if (val2 != null)
{
typeof(ZPlayFabSocket).GetField("m_remotePlayerId").SetValue(bufferingSocket, val2.m_remotePlayerId);
}
fieldInfo.SetValue(val, bufferingSocket);
}
if (__state == null)
{
__state = new Dictionary<Assembly, BufferingSocket>();
}
__state[Assembly.GetExecutingAssembly()] = bufferingSocket;
}
[HarmonyPostfix]
private static void Postfix(Dictionary<Assembly, BufferingSocket> __state, ZNet __instance, ZRpc rpc)
{
ZRpc rpc2 = rpc;
ZNet __instance2 = __instance;
Dictionary<Assembly, BufferingSocket> __state2 = __state;
ZNetPeer peer;
if (__instance2.IsServer())
{
object obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance2, new object[1] { rpc2 });
peer = (ZNetPeer)((obj is ZNetPeer) ? obj : null);
if (peer == null)
{
SendBufferedData();
}
else
{
((MonoBehaviour)__instance2).StartCoroutine(sendAsync());
}
}
void SendBufferedData()
{
if (rpc2.GetSocket() is BufferingSocket bufferingSocket)
{
AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc2, bufferingSocket.Original);
object? obj2 = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance2, new object[1] { rpc2 });
ZNetPeer val = (ZNetPeer)((obj2 is ZNetPeer) ? obj2 : null);
if (val != null)
{
AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket").SetValue(val, bufferingSocket.Original);
}
}
BufferingSocket bufferingSocket2 = __state2[Assembly.GetExecutingAssembly()];
bufferingSocket2.finished = true;
for (int i = 0; i < bufferingSocket2.Package.Count; i++)
{
if (i == bufferingSocket2.versionMatchQueued)
{
bufferingSocket2.Original.VersionMatch();
}
bufferingSocket2.Original.Send(bufferingSocket2.Package[i]);
}
if (bufferingSocket2.Package.Count == bufferingSocket2.versionMatchQueued)
{
bufferingSocket2.Original.VersionMatch();
}
}
IEnumerator sendAsync()
{
foreach (ConfigSync configSync in configSyncs)
{
List<PackageEntry> entries = new List<PackageEntry>();
if (configSync.CurrentVersion != null)
{
entries.Add(new PackageEntry
{
section = "Internal",
key = "serverversion",
type = typeof(string),
value = configSync.CurrentVersion
});
}
MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null);
SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance);
entries.Add(new PackageEntry
{
section = "Internal",
key = "lockexempt",
type = typeof(bool),
value = (((object)listContainsId == null) ? ((object)adminList.Contains(rpc2.GetSocket().GetHostName())) : listContainsId.Invoke(ZNet.instance, new object[2]
{
adminList,
rpc2.GetSocket().GetHostName()
}))
});
ZPackage package = ConfigsToPackage(configSync.allConfigs.Select((OwnConfigEntryBase c) => c.BaseConfig), configSync.allCustomValues, entries, partial: false);
yield return ((MonoBehaviour)__instance2).StartCoroutine(configSync.sendZPackage(new List<ZNetPeer> { peer }, package));
}
SendBufferedData();
}
}
}
private class PackageEntry
{
public string section = null;
public string key = null;
public Type type = null;
public object? value;
}
[HarmonyPatch(typeof(ConfigEntryBase), "GetSerializedValue")]
private static class PreventSavingServerInfo
{
[HarmonyPrefix]
private static bool Prefix(ConfigEntryBase __instance, ref string __result)
{
OwnConfigEntryBase ownConfigEntryBase = configData(__instance);
if (ownConfigEntryBase == null || isWritableConfig(ownConfigEntryBase))
{
return true;
}
__result = TomlTypeConverter.ConvertToString(ownConfigEntryBase.LocalBaseValue, __instance.SettingType);
return false;
}
}
[HarmonyPatch(typeof(ConfigEntryBase), "SetSerializedValue")]
private static class PreventConfigRereadChangingValues
{
[HarmonyPrefix]
private static bool Prefix(ConfigEntryBase __instance, string value)
{
OwnConfigEntryBase ownConfigEntryBase = configData(__instance);
if (ownConfigEntryBase == null || ownConfigEntryBase.LocalBaseValue == null)
{
return true;
}
try
{
ownConfigEntryBase.LocalBaseValue = TomlTypeConverter.ConvertToValue(value, __instance.SettingType);
}
catch (Exception ex)
{
Debug.LogWarning((object)$"Config value of setting \"{__instance.Definition}\" could not be parsed and will be ignored. Reason: {ex.Message}; Value: {value}");
}
return false;
}
}
private class InvalidDeserializationTypeException : Exception
{
public string expected = null;
public string received = null;
public string field = "";
}
public static bool ProcessingServerUpdate;
public readonly string Name;
public string? DisplayName;
public string? CurrentVersion;
public string? MinimumRequiredVersion;
public bool ModRequired = false;
private bool? forceConfigLocking;
private bool isSourceOfTruth = true;
private static readonly HashSet<ConfigSync> configSyncs;
private readonly HashSet<OwnConfigEntryBase> allConfigs = new HashSet<OwnConfigEntryBase>();
private HashSet<CustomSyncedValueBase> allCustomValues = new HashSet<CustomSyncedValueBase>();
private static bool isServer;
private static bool lockExempt;
private OwnConfigEntryBase? lockedConfig = null;
private const byte PARTIAL_CONFIGS = 1;
private const byte FRAGMENTED_CONFIG = 2;
private const byte COMPRESSED_CONFIG = 4;
private readonly Dictionary<string, SortedDictionary<int, byte[]>> configValueCache = new Dictionary<string, SortedDictionary<int, byte[]>>();
private readonly List<KeyValuePair<long, string>> cacheExpirations = new List<KeyValuePair<long, string>>();
private static long packageCounter;
public bool IsL