Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Trails v0.2.9
plugins/Trails.dll
Decompiled 2 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Trails { public static class Api { public static float CartFactor(Vagon cart) { if ((Object)(object)cart == (Object)null || !Rules.Enabled || !Walkers.CartFactor.TryGetValue(((Object)cart).GetInstanceID(), out var value)) { return 1f; } if (!(value < 0.7f)) { if (!(value > 1f)) { return value; } return 1f; } return 0.7f; } } [HarmonyPatch] internal static class Effects { private const float MudSlowdown = 0.1f; private static bool Local(Character c) { if ((Object)(object)c != (Object)null && (Object)(object)c == (Object)(object)Player.m_localPlayer) { return Rules.Enabled; } return false; } internal static float Speed() { byte localRoad = Walkers.LocalRoad; if (localRoad != 0) { return 1f + (float)(Rules.RunBonus + Roads.ExtraSpeed(localRoad, Rules.RoadStep)) / 100f; } if (Walkers.LocalMuddy && Walkers.Wet > 0.05f) { return 1f - 0.1f * Walkers.Wet; } return 1f + (float)Rules.RunBonus / 100f * Walkers.LocalTrail; } [HarmonyPostfix] [HarmonyPatch(typeof(Player), "GetRunSpeedFactor")] private static void Run(Player __instance, ref float __result) { if (Local((Character)(object)__instance)) { __result *= Speed(); } } [HarmonyPostfix] [HarmonyPatch(typeof(Player), "GetJogSpeedFactor")] private static void Jog(Player __instance, ref float __result) { if (Local((Character)(object)__instance)) { __result *= Speed(); } } [HarmonyPostfix] [HarmonyPatch(typeof(SEMan), "ModifyRunStaminaDrain")] private static void Stamina(SEMan __instance, ref float drain, bool minZero) { if (minZero && Local(__instance.m_character)) { float num = ((Walkers.LocalRoad != 0) ? 1f : ((Walkers.LocalMuddy && Walkers.Wet > 0.05f) ? 0f : Walkers.LocalTrail)); drain *= 1f - (float)Rules.StaminaSaving / 100f * num; } } [HarmonyPostfix] [HarmonyPatch(typeof(SEMan), "ModifyStaminaRegen")] private static void Regen(SEMan __instance, ref float staminaMultiplier) { if (Local(__instance.m_character) && Walkers.LocalRoad != 0) { staminaMultiplier *= 1f + Roads.Regen(Walkers.LocalRoad); } } [HarmonyPostfix] [HarmonyPatch(typeof(Character), "GetRunSpeedFactor")] private static void MountRun(Character __instance, ref float __result) { if (Walkers.MountFactor.TryGetValue(((Object)__instance).GetInstanceID(), out var value)) { __result *= value; } } [HarmonyPostfix] [HarmonyPatch(typeof(Character), "GetJogSpeedFactor")] private static void MountJog(Character __instance, ref float __result) { if (Walkers.MountFactor.TryGetValue(((Object)__instance).GetInstanceID(), out var value)) { __result *= value; } } [HarmonyPrefix] [HarmonyPatch(typeof(Vagon), "SetMass")] private static void CartMass(Vagon __instance, ref float mass) { if (Walkers.CartFactor.TryGetValue(((Object)__instance).GetInstanceID(), out var value)) { mass *= Mathf.Clamp(value, 0.7f, 1f); } } [HarmonyTranspiler] [HarmonyPatch(typeof(ClutterSystem), "GenerateVegPatch")] private static IEnumerable<CodeInstruction> Lay(IEnumerable<CodeInstruction> code) { MethodInfo cleared = AccessTools.Method(typeof(Heightmap), "IsCleared", new Type[1] { typeof(Vector3) }, (Type[])null); MethodInfo ours = AccessTools.Method(typeof(Effects), "GrassCleared", (Type[])null, (Type[])null); int n = 0; foreach (CodeInstruction item in code) { if ((item.opcode == OpCodes.Callvirt || item.opcode == OpCodes.Call) && object.Equals(item.operand, cleared)) { n++; yield return CodeInstructionExtensions.MoveBlocksFrom(CodeInstructionExtensions.MoveLabelsFrom(new CodeInstruction(OpCodes.Call, (object)ours), item), item); } else { yield return item; } } if (n == 0) { Plugin.Warn("ClutterSystem.GenerateVegPatch has no IsCleared call (the game changed?): no grass thinning"); } } private static bool GrassCleared(Heightmap hmap, Vector3 point) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) bool flag = hmap.IsCleared(point); if (flag || TrailRegion.Loaded.Count == 0 || !Plugin.Thinning.Value || !Rules.Enabled) { return flag; } try { float num = Stages.Thin(TrailRegion.WearAt(point)); return num > 0f && Pattern(point) < num; } catch (Exception ex) { Plugin.Debug("thinning: " + ex.Message); return false; } } private static float Pattern(Vector3 p) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) int num = (Mathf.RoundToInt(p.x * 8f) * 73856093) ^ (Mathf.RoundToInt(p.z * 8f) * 19349663); int num2 = (num ^ (num >> 13)) * 1540483477; return (float)((num2 ^ (num2 >> 15)) & 0xFFFF) / 65536f; } } internal static class Gravel { private sealed class Patch { internal Mesh Mesh; internal int Version; internal float RemakeAt; internal Vector3 Centre; } private const float Reach = 40f; private const float RemakeEvery = 30f; private const int PerCell = 10; private static readonly Dictionary<long, Patch> patches = new Dictionary<long, Patch>(); private static readonly List<long> gone = new List<long>(); private static Material material; private static bool looked; private static int layer = -1; private static readonly List<Vector3> vertices = new List<Vector3>(); private static readonly List<Vector3> normals = new List<Vector3>(); private static readonly List<Vector2> uvs = new List<Vector2>(); private static readonly List<int> triangles = new List<int>(); internal static void Clear() { foreach (Patch value in patches.Values) { if ((Object)(object)value.Mesh != (Object)null) { Object.Destroy((Object)(object)value.Mesh); } } patches.Clear(); } internal static void Update() { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) Camera mainCamera = Utils.GetMainCamera(); if (!Plugin.GravelPebbles.Value || (Object)(object)mainCamera == (Object)null || TrailRegion.Loaded.Count == 0) { if (patches.Count > 0) { Clear(); } return; } if (!looked) { Look(); } if ((Object)(object)material == (Object)null) { return; } Vector3 position = ((Component)mainCamera).transform.position; float time = Time.time; int num = 0; gone.Clear(); foreach (long key2 in patches.Keys) { if (!TrailRegion.Loaded.ContainsKey(key2)) { gone.Add(key2); } } foreach (long item in gone) { if ((Object)(object)patches[item].Mesh != (Object)null) { Object.Destroy((Object)(object)patches[item].Mesh); } patches.Remove(item); } foreach (KeyValuePair<long, TrailRegion> item2 in TrailRegion.Loaded) { TrailRegion value = item2.Value; if ((Object)(object)value == (Object)null) { continue; } Vector3 val = ((Component)value).transform.position - position; if (((Vector3)(ref val)).sqrMagnitude > 5184f) { continue; } if (!patches.TryGetValue(item2.Key, out var value2)) { Dictionary<long, Patch> dictionary = patches; long key = item2.Key; Patch obj = new Patch { Version = -1 }; value2 = obj; dictionary[key] = obj; } if ((value2.Version != value.Version || time >= value2.RemakeAt) && num < 2) { Make(item2.Key, value, value2, time); num++; } if (!((Object)(object)value2.Mesh == (Object)null)) { val = value2.Centre - position; if (!(((Vector3)(ref val)).sqrMagnitude > 4096f)) { Graphics.DrawMesh(value2.Mesh, Matrix4x4.identity, material, layer, (Camera)null, 0, (MaterialPropertyBlock)null, false, true); } } } } private static void Look() { looked = true; layer = LayerMask.NameToLayer("terrain"); if (layer < 0) { layer = 0; } GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab("Stone") : null); MeshRenderer val2 = (((Object)(object)val != (Object)null) ? val.GetComponentInChildren<MeshRenderer>(true) : null); if ((Object)(object)val2 != (Object)null && (Object)(object)((Renderer)val2).sharedMaterial != (Object)null) { material = ((Renderer)val2).sharedMaterial; } if ((Object)(object)material == (Object)null) { looked = false; Plugin.Debug("gravel: no stone material yet"); } } private static void Make(long key, TrailRegion region, Patch patch, float now) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Expected O, but got Unknown //IL_00fc: 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_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0118: 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_038e: Unknown result type (might be due to invalid IL or missing references) //IL_0391: Unknown result type (might be due to invalid IL or missing references) //IL_0396: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) patch.Version = region.Version; patch.RemakeAt = now + 30f; vertices.Clear(); normals.Clear(); uvs.Clear(); triangles.Clear(); bool sphere = Surface.Sphere; bool flag = false; Vector3 val = Vector3.zero; int num = 0; RaycastHit val3 = default(RaycastHit); foreach (KeyValuePair<ushort, RegionData.Cell> cell in region.Data.Cells) { if (cell.Value.Road != 1) { continue; } long num2 = Grid.FromLocal(key, cell.Key); if (!Surface.Ground(num2, out var point)) { flag = true; continue; } Vector3 val2 = (sphere ? ((Vector3)(ref point)).normalized : Vector3.up); if (Physics.Raycast(point + val2 * 1.5f, -val2, ref val3, 3f, 1 << layer, (QueryTriggerInteraction)1)) { point = ((RaycastHit)(ref val3)).point; val2 = ((RaycastHit)(ref val3)).normal; } Vector3 val4 = Vector3.Cross(val2, (Mathf.Abs(val2.z) < 0.9f) ? Vector3.forward : Vector3.right); Vector3 normalized = ((Vector3)(ref val4)).normalized; Vector3 val5 = Vector3.Cross(normalized, val2); uint seed = (uint)(num2.GetHashCode() * -1640531535 + (int)(num2 >> 32)); for (int i = 0; i < 10; i++) { float num3 = Next(ref seed) - 0.5f; float num4 = Next(ref seed) - 0.5f; float num5 = Mathf.Lerp(0.035f, 0.085f, Next(ref seed) * Next(ref seed)); float num6 = Mathf.Lerp(0.45f, 0.75f, Next(ref seed)); Quaternion val6 = Quaternion.AngleAxis(Next(ref seed) * 360f, val2) * Quaternion.AngleAxis((Next(ref seed) - 0.5f) * 30f, normalized); Pebble(point + normalized * num3 + val5 * num4 - val2 * num5 * num6 * 0.35f, val6 * normalized * num5 * Mathf.Lerp(0.8f, 1.3f, Next(ref seed)), val6 * val2 * num5 * num6, val6 * val5 * num5, Next(ref seed)); } val += point; num++; } if (flag) { patch.RemakeAt = now + 3f; } if (vertices.Count == 0) { if ((Object)(object)patch.Mesh != (Object)null) { Object.Destroy((Object)(object)patch.Mesh); patch.Mesh = null; } return; } if ((Object)(object)patch.Mesh == (Object)null) { patch.Mesh = new Mesh { name = "Trails gravel" }; } patch.Mesh.Clear(); patch.Mesh.indexFormat = (IndexFormat)(vertices.Count > 65000); patch.Mesh.SetVertices(vertices); patch.Mesh.SetNormals(normals); patch.Mesh.SetUVs(0, uvs); patch.Mesh.SetTriangles(triangles, 0); patch.Mesh.RecalculateBounds(); patch.Centre = val / (float)num; } private static void Pebble(Vector3 at, Vector3 x, Vector3 y, Vector3 z, float u) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: 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_00aa: Unknown result type (might be due to invalid IL or missing references) int count = vertices.Count; Vector3[] array = (Vector3[])(object)new Vector3[6] { x, -x, y, -y, z, -z }; for (int i = 0; i < 6; i++) { vertices.Add(at + array[i]); normals.Add(((Vector3)(ref array[i])).normalized); uvs.Add(new Vector2(u * 0.8f + (float)(i & 1) * 0.15f, 0.2f + (float)(i >> 1) * 0.25f)); } int[] array2 = new int[24] { 0, 2, 4, 4, 2, 1, 1, 2, 5, 5, 2, 0, 4, 3, 0, 1, 3, 4, 5, 3, 1, 0, 3, 5 }; foreach (int num in array2) { triangles.Add(count + num); } } private static float Next(ref uint seed) { seed ^= seed << 13; seed ^= seed >> 17; seed ^= seed << 5; return (float)(seed & 0xFFFFFF) / 16777216f; } } internal static class Host { private sealed class Region { internal ZDO Zdo; internal RegionData Data; internal bool Dirty; internal bool Unpainted = true; internal bool SoilKnown; internal Soil Soil; internal Biome Biome; internal float JobUntil; } internal const string StepsRpc = "chistix_trails_steps"; internal const string PaintedRpc = "chistix_trails_painted"; internal const string RoadRpc = "chistix_trails_road"; private const float FlushEvery = 5f; private const float DecayEvery = 60f; private const float JobTimeout = 20f; private const float PainterReach = 80f; private const int JobCells = 96; private const int GraceDays = 1; private const int RoadsideAge = 3; private const int RoadsideMax = 4; private const float RoadsideChance = 1f / 30f; private static readonly Dictionary<long, Region> regions = new Dictionary<long, Region>(); private static readonly Random random = new Random(); private static bool indexed; private static float nextFlush; private static float nextDecay; private static float nextJobs; private static double lastDecayTime = -1.0; private static readonly Dictionary<Biome, string[]> roadside = new Dictionary<Biome, string[]> { { (Biome)1, new string[3] { "Pickable_Dandelion", "Pickable_Dandelion", "Bush01" } }, { (Biome)8, new string[3] { "Pickable_Thistle", "Bush02_en", "Bush01" } }, { (Biome)16, new string[1] { "Bush01_heath" } } }; private static readonly List<long> empty = new List<long>(); private static readonly List<KeyValuePair<ushort, byte>> job = new List<KeyValuePair<ushort, byte>>(); internal static int RegionCount { get { Index(); return regions.Count; } } private static double DayLength => ((Object)(object)EnvMan.instance != (Object)null && EnvMan.instance.m_dayLengthSec > 0) ? EnvMan.instance.m_dayLengthSec : 1800; private static double Now { get { if (!((Object)(object)ZNet.instance != (Object)null)) { return 0.0; } return ZNet.instance.GetTimeSeconds(); } } private static ushort Today => (ushort)(long)(Now / DayLength); internal static void Register(ZRoutedRpc rpc) { rpc.Register<ZPackage>("chistix_trails_steps", (Action<long, ZPackage>)delegate(long sender, ZPackage pkg) { if (Rules.Server) { Steps(pkg); } }); rpc.Register<ZPackage>("chistix_trails_painted", (Action<long, ZPackage>)delegate(long sender, ZPackage pkg) { if (Rules.Server) { Painted(pkg); } }); rpc.Register<ZPackage>("chistix_trails_road", (Action<long, ZPackage>)delegate(long sender, ZPackage pkg) { if (Rules.Server) { Road(pkg); } }); } internal static void Clear() { regions.Clear(); indexed = false; lastDecayTime = -1.0; } private static void Index() { if (indexed || ZDOMan.instance == null) { return; } indexed = true; int num = 0; foreach (ZDO value in ZDOMan.instance.m_objectsByID.Values) { if (value.GetPrefab() == Prefabs.RegionHash) { long key = value.GetLong(Prefabs.KeyHash, 0L); if (regions.ContainsKey(key)) { num++; continue; } regions[key] = new Region { Zdo = value, Data = RegionData.Read(value.GetByteArray(Prefabs.CellsHash, (byte[])null)) }; } } Plugin.Log($"trails: {regions.Count} regions in the world" + ((num > 0) ? $", {num} duplicates ignored" : "")); } private static Region Get(long key, Vector3 near, bool create) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) Index(); if (regions.TryGetValue(key, out var value) && value.Zdo != null && value.Zdo.IsValid()) { return value; } if (!create) { return null; } ZDO val = ZDOMan.instance.CreateNewZDO(Surface.RegionPoint(key, near), Prefabs.RegionHash); val.Persistent = true; val.SetType((ObjectType)0); val.SetPrefab(Prefabs.RegionHash); val.Set(Prefabs.KeyHash, key); val.Set(Prefabs.BornHash, (int)Today, false); value = new Region { Zdo = val, Data = new RegionData() }; regions[key] = value; return value; } private static void Know(Region r) { //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) //IL_0029: 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 (!r.SoilKnown && r.Zdo != null) { r.SoilKnown = true; r.Biome = Surface.Biome(r.Zdo.GetPosition()); r.Soil = Surface.SoilOf(r.Biome); } } private static void Steps(ZPackage pkg) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) try { Vector3 anchor = pkg.ReadVector3(); int num = pkg.ReadInt(); List<KeyValuePair<long, float>> list = new List<KeyValuePair<long, float>>(Mathf.Min(num, 4096)); for (int i = 0; i < num; i++) { list.Add(new KeyValuePair<long, float>(pkg.ReadLong(), pkg.ReadSingle())); } Add(anchor, list); } catch (Exception ex) { Plugin.Warn("steps: " + ex.Message); } } internal static void Add(Vector3 anchor, IEnumerable<KeyValuePair<long, float>> cells) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) if (!Rules.Enabled || ZDOMan.instance == null) { return; } float num = Plugin.WearScales[Mathf.Clamp((int)Plugin.WearSpeed.Value, 0, Plugin.WearScales.Length - 1)]; ushort today = Today; Region region = null; long num2 = long.MinValue; foreach (KeyValuePair<long, float> cell in cells) { if (cell.Value > 0f && !(cell.Value > 20f)) { long num3 = Grid.RegionOf(cell.Key); if (num3 != num2) { num2 = num3; region = Get(num3, anchor, create: true); } region.Data.Add(Grid.Local(cell.Key), cell.Value * num, today); region.Dirty = (region.Unpainted = true); } } } private static void Road(ZPackage pkg) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) try { SetRoad(pkg.ReadVector3(), pkg.ReadSingle(), pkg.ReadByte()); } catch (Exception ex) { Plugin.Warn("road: " + ex.Message); } } internal static int SetRoad(Vector3 world, float radius, byte level) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) if (ZDOMan.instance == null || !Surface.ToGrid(world, out var x, out var y, out var z)) { return 0; } List<KeyValuePair<long, float>> list = new List<KeyValuePair<long, float>>(); Grid.Brush(x, y, z, Mathf.Max(0f, radius - 0.9f), Surface.Flat, list); int num = 0; Region region = null; long num2 = long.MinValue; foreach (KeyValuePair<long, float> item in list) { long num3 = Grid.RegionOf(item.Key); if (num3 != num2) { num2 = num3; region = Get(num3, world, level != 0); } if (region != null) { ushort num4 = Grid.Local(item.Key); region.Data.Cells.TryGetValue(num4, out var value); byte b = (byte)((level != 0) ? ((byte)Mathf.Max((int)value.Road, (int)level)) : 0); if (b != value.Road || !region.Data.Cells.ContainsKey(num4)) { region.Data.SetRoad(num4, b); region.Dirty = true; num++; } } } return num; } internal static int Stamp(Vector3 world, float radius, float amount) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) if (!Surface.ToGrid(world, out var x, out var y, out var z)) { return 0; } List<KeyValuePair<long, float>> list = new List<KeyValuePair<long, float>>(); Grid.Brush(x, y, z, radius, Surface.Flat, list); List<KeyValuePair<long, float>> list2 = new List<KeyValuePair<long, float>>(); foreach (KeyValuePair<long, float> item in list) { list2.Add(new KeyValuePair<long, float>(item.Key, Mathf.Min(20f, amount * Mathf.Clamp01(item.Value * 1.5f)))); } for (float num = amount; num > 0f; num -= 20f) { float num2 = Mathf.Min(20f, num) / Mathf.Min(20f, amount); List<KeyValuePair<long, float>> list3 = new List<KeyValuePair<long, float>>(); foreach (KeyValuePair<long, float> item2 in list2) { list3.Add(new KeyValuePair<long, float>(item2.Key, item2.Value * num2)); } Add(world, list3); } return list2.Count; } internal static int Scale(Vector3 world, float radius, float factor, bool roads = false) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (!Surface.ToGrid(world, out var x, out var y, out var z)) { return 0; } Index(); int num = 0; foreach (KeyValuePair<long, Region> region in regions) { foreach (ushort item in new List<ushort>(region.Value.Data.Cells.Keys)) { if (!(Grid.Distance(Grid.FromLocal(region.Key, item), x, Surface.Flat ? 0.0 : y, z) > (double)radius)) { RegionData.Cell value = region.Value.Data.Cells[item]; value.Wear *= factor; if (roads) { value.Road = 0; } region.Value.Data.Cells[item] = value; region.Value.Dirty = (region.Value.Unpainted = true); num++; } } } return num; } private static void Painted(ZPackage pkg) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) try { long key = pkg.ReadLong(); int num = pkg.ReadInt(); Region region = Get(key, Vector3.zero, create: false); for (int i = 0; i < num; i++) { ushort key2 = pkg.ReadUShort(); byte painted = pkg.ReadByte(); if (region != null && region.Data.Cells.TryGetValue(key2, out var value)) { value.Painted = painted; region.Data.Cells[key2] = value; region.Dirty = true; } } if (region != null) { region.JobUntil = 0f; region.Unpainted = true; } } catch (Exception ex) { Plugin.Warn("painted: " + ex.Message); } } internal static void PaintedHere(long key, List<KeyValuePair<ushort, byte>> done) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(key); val.Write(done.Count); foreach (KeyValuePair<ushort, byte> item in done) { val.Write(item.Key); val.Write(item.Value); } val.SetPos(0); Painted(val); } internal static void Update() { if (Rules.Server && ZDOMan.instance != null && !((Object)(object)ZNet.instance == (Object)null)) { float time = Time.time; if (time >= nextDecay) { nextDecay = time + 60f; Decay(); Roadside(); } if (time >= nextFlush) { nextFlush = time + 5f; Flush(); } if (time >= nextJobs) { nextJobs = time + 1f; Jobs(); } } } private static bool Snowing(Vector3 point) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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_002d: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)EnvMan.instance == (Object)null)) { Vector3 val = ((Component)localPlayer).transform.position - point; if (!(((Vector3)(ref val)).sqrMagnitude > 90000f)) { EnvSetup currentEnvironment = EnvMan.instance.GetCurrentEnvironment(); if (currentEnvironment != null && currentEnvironment.m_name != null) { return currentEnvironment.m_name.IndexOf("snow", StringComparison.OrdinalIgnoreCase) >= 0; } return false; } } return false; } private static void Decay() { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) double now = Now; if (lastDecayTime < 0.0) { lastDecayTime = now; return; } double num = (now - lastDecayTime) / DayLength; lastDecayTime = now; double num2 = Plugin.HalfLives[Mathf.Clamp((int)Plugin.Regrowth.Value, 0, Plugin.HalfLives.Length - 1)]; if (num2 <= 0.0 || num <= 0.0) { return; } Index(); ushort today = Today; foreach (Region value in regions.Values) { Know(value); double num3 = Soils.HalfLifeFactor(value.Soil, value.Soil == Soil.Snow && value.Zdo != null && Snowing(value.Zdo.GetPosition())); if (value.Data.Decay(today, num, num2 * num3, 1)) { value.Dirty = (value.Unpainted = true); } } } private static void Roadside() { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Expected O, but got Unknown if (!Plugin.Roadside.Value || !Rules.Enabled) { return; } ushort today = Today; int num = 0; foreach (KeyValuePair<long, Region> region in regions) { Region value = region.Value; if (value.Zdo == null || !value.Zdo.IsValid() || random.NextDouble() > 0.03333333507180214) { continue; } Know(value); if (!roadside.TryGetValue(value.Biome, out var value2) || value.Zdo.GetInt(Prefabs.FlowersHash, 0) >= 4) { continue; } if (value.Zdo.GetOwner() != ZDOMan.GetSessionID()) { value.Zdo.SetOwner(ZDOMan.GetSessionID()); } if (value.Zdo.GetInt(Prefabs.BornHash, -1) < 0) { value.Zdo.Set(Prefabs.BornHash, (int)today, false); } if ((ushort)(today - (ushort)value.Zdo.GetInt(Prefabs.BornHash, (int)today)) < 3) { continue; } long num2 = Edge(region.Key, value.Data); if (num2 == 0L) { continue; } long num3 = Painter(value.Zdo.GetPosition()); if (num3 != 0L) { int stableHashCode = StringExtensionMethods.GetStableHashCode(value2[random.Next(value2.Length)]); value.Zdo.Set(Prefabs.FlowersHash, value.Zdo.GetInt(Prefabs.FlowersHash, 0) + 1, false); ZPackage val = new ZPackage(); val.Write(num2); val.Write(stableHashCode); if (num3 == ZDOMan.GetSessionID()) { val.SetPos(0); Trails.Painter.Grow(num3, val); } else { ZRoutedRpc.instance.InvokeRoutedRPC(num3, "chistix_trails_grow", new object[1] { val }); } if (++num >= 4) { break; } } } } private static long Edge(long region, RegionData data) { List<ushort> list = new List<ushort>(); foreach (KeyValuePair<ushort, RegionData.Cell> cell in data.Cells) { if (cell.Value.Wear >= Stages.PaintSteps[3] && cell.Value.Road == 0) { list.Add(cell.Key); } } if (list.Count == 0) { return 0L; } for (int i = 0; i < 12; i++) { Grid.Unpack(Grid.FromLocal(region, list[random.Next(list.Count)]), out var x, out var y, out var z); int num = random.Next(-3, 4); int num2 = random.Next(-3, 4); if (Math.Abs(num) >= 2 || Math.Abs(num2) >= 2) { long num3 = Grid.Key(x + num, y, z + num2); long num4 = Grid.RegionOf(num3); Region value; RegionData regionData = ((num4 == region) ? data : (regions.TryGetValue(num4, out value) ? value.Data : null)); if (regionData == null || !regionData.Cells.TryGetValue(Grid.Local(num3), out var value2) || (!(value2.Wear >= 4f) && value2.Road == 0)) { return num3; } } } return 0L; } private static void Flush() { empty.Clear(); long sessionID = ZDOMan.GetSessionID(); foreach (KeyValuePair<long, Region> region in regions) { Region value = region.Value; if (value.Dirty && value.Zdo != null && value.Zdo.IsValid()) { value.Dirty = false; if (value.Zdo.GetOwner() != sessionID) { value.Zdo.SetOwner(sessionID); } value.Data.Prune(); if (value.Data.Cells.Count == 0) { empty.Add(region.Key); } else { value.Zdo.Set(Prefabs.CellsHash, value.Data.Write()); } } } foreach (long item in empty) { ZDOMan.instance.DestroyZDO(regions[item].Zdo); regions.Remove(item); } } private static void Jobs() { //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Expected O, but got Unknown float time = Time.time; int num = 0; foreach (KeyValuePair<long, Region> region in regions) { Region value = region.Value; if (!value.Unpainted || time < value.JobUntil || value.Zdo == null || !value.Zdo.IsValid()) { continue; } Know(value); int max = Soils.MaxPaint(value.Soil); job.Clear(); foreach (KeyValuePair<ushort, RegionData.Cell> cell in value.Data.Cells) { int num2 = Stages.Paint(cell.Value.Wear, cell.Value.Painted, max, cell.Value.Road != 0); if (num2 != cell.Value.Painted) { job.Add(new KeyValuePair<ushort, byte>(cell.Key, (byte)num2)); } if (job.Count >= 96) { break; } } if (job.Count == 0) { value.Unpainted = false; continue; } long num3 = Painter(value.Zdo.GetPosition()); if (num3 == 0L) { continue; } value.JobUntil = time + 20f; ZPackage val = new ZPackage(); val.Write(region.Key); val.Write(job.Count); foreach (KeyValuePair<ushort, byte> item in job) { val.Write(item.Key); val.Write(value.Data.Cells[item.Key].Painted); val.Write(item.Value); } if (num3 == ZDOMan.GetSessionID()) { val.SetPos(0); Trails.Painter.Accept(num3, val); } else { ZRoutedRpc.instance.InvokeRoutedRPC(num3, "chistix_trails_paint", new object[1] { val }); } if (++num < 8) { continue; } break; } } private static long Painter(Vector3 point) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) float num = 6400f; long result = 0L; Player localPlayer = Player.m_localPlayer; Vector3 val; if ((Object)(object)localPlayer != (Object)null) { val = ((Component)localPlayer).transform.position - point; if (((Vector3)(ref val)).sqrMagnitude < num) { return ZDOMan.GetSessionID(); } } foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer != null && peer.IsReady()) { val = peer.m_refPos - point; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; result = peer.m_uid; } } } return result; } internal static string Report(Vector3 world) { Index(); int num = 0; int num2 = 0; int num3 = 0; foreach (Region value in regions.Values) { foreach (RegionData.Cell value2 in value.Data.Cells.Values) { num++; if (value2.Painted > 0) { num2++; } if (value2.Road > 0) { num3++; } } } return $"regions {regions.Count}, cells {num}, painted {num2}, road cells {num3}"; } } internal static class Painter { private struct Job { internal long Host; internal long Region; internal ushort Local; internal byte From; internal byte To; } internal const string PaintRpc = "chistix_trails_paint"; private const int PerFrame = 6; private static readonly Queue<Job> queue = new Queue<Job>(); private static readonly Dictionary<long, List<KeyValuePair<ushort, byte>>> done = new Dictionary<long, List<KeyValuePair<ushort, byte>>>(); private static float nextReport; internal static int Painted; internal const string GrowRpc = "chistix_trails_grow"; private static readonly Queue<KeyValuePair<long, int>> sowing = new Queue<KeyValuePair<long, int>>(); private static int blockMask; internal static int Sown; internal static void Register(ZRoutedRpc rpc) { rpc.Register<ZPackage>("chistix_trails_paint", (Action<long, ZPackage>)Accept); rpc.Register<ZPackage>("chistix_trails_grow", (Action<long, ZPackage>)Grow); } internal static void Clear() { queue.Clear(); done.Clear(); sowing.Clear(); } internal static void Grow(long sender, ZPackage pkg) { try { sowing.Enqueue(new KeyValuePair<long, int>(pkg.ReadLong(), pkg.ReadInt())); } catch (Exception ex) { Plugin.Warn("grow job: " + ex.Message); } } private static void Sow(long cell, int hash) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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) //IL_00a1: 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_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: 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_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(hash) : null); if (!((Object)(object)val == (Object)null) && Surface.Ground(cell, out var point)) { Vector3 val2 = (Surface.Sphere ? ((Vector3)(ref point)).normalized : Vector3.up); if (blockMask == 0) { blockMask = LayerMask.GetMask(new string[7] { "piece", "piece_nonsolid", "static_solid", "Default", "Default_small", "item", "vehicle" }); } if (!Physics.CheckSphere(point + val2 * 0.6f, 0.7f, blockMask, (QueryTriggerInteraction)1)) { Object.Instantiate<GameObject>(val, point, Quaternion.AngleAxis(Random.Range(0f, 360f), val2) * Quaternion.FromToRotation(Vector3.up, val2)); Sown++; } } } internal static void Accept(long sender, ZPackage pkg) { try { long region = pkg.ReadLong(); int num = pkg.ReadInt(); for (int i = 0; i < num; i++) { queue.Enqueue(new Job { Host = sender, Region = region, Local = pkg.ReadUShort(), From = pkg.ReadByte(), To = pkg.ReadByte() }); } } catch (Exception ex) { Plugin.Warn("paint job: " + ex.Message); } } internal static void Update() { if (sowing.Count > 0) { KeyValuePair<long, int> keyValuePair = sowing.Dequeue(); try { Sow(keyValuePair.Key, keyValuePair.Value); } catch (Exception ex) { Plugin.Warn("sow: " + ex.Message); } } for (int i = 0; i < 6; i++) { if (queue.Count <= 0) { break; } Job job = queue.Dequeue(); try { if (Paint(job, out var now)) { Done(job.Region, job.Local, now); } } catch (Exception ex2) { Plugin.Warn("paint: " + ex2.Message); } } if (done.Count > 0 && (queue.Count == 0 || Time.time >= nextReport)) { nextReport = Time.time + 2f; Report(); } } private static void Done(long region, ushort local, byte stage) { if (!done.TryGetValue(region, out var value)) { value = (done[region] = new List<KeyValuePair<ushort, byte>>()); } value.Add(new KeyValuePair<ushort, byte>(local, stage)); } private static void Report() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown foreach (KeyValuePair<long, List<KeyValuePair<ushort, byte>>> item in done) { if (Rules.Server) { Host.PaintedHere(item.Key, item.Value); } else { if (ZRoutedRpc.instance == null) { continue; } ZPackage val = new ZPackage(); val.Write(item.Key); val.Write(item.Value.Count); foreach (KeyValuePair<ushort, byte> item2 in item.Value) { val.Write(item2.Key); val.Write(item2.Value); } ZRoutedRpc.instance.InvokeRoutedRPC("chistix_trails_painted", new object[1] { val }); } } done.Clear(); } private static bool Paint(Job job, out byte now) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) now = job.From; if (!Surface.Ground(Grid.FromLocal(job.Region, job.Local), out var point)) { return false; } if (job.To == job.From) { return true; } Heightmap val = Heightmap.FindHeightmap(point); if ((Object)(object)val != (Object)null) { Color paintMask = val.GetPaintMask(point); bool flag = job.To > job.From; if (flag && (paintMask.g > 0.3f || paintMask.b > 0.3f)) { now = job.To; return true; } if (!flag && (paintMask.g > 0.15f || paintMask.b > 0.15f || paintMask.r > (float)(int)job.From / 4f + 0.3f)) { now = 0; return true; } } TerrainOp val2 = Prefabs.Paint(job.From, job.To); if ((Object)(object)val2 == (Object)null) { return true; } if ((Object)(object)ObjectDB.instance != (Object)null) { Prefabs.RegisterObjects(ObjectDB.instance); } Object.Instantiate<GameObject>(((Component)val2).gameObject, point, Quaternion.identity); Painted++; now = job.To; return true; } } internal static class Pens { private static Func<Vector3, bool> inPen; private static bool looked; internal static bool Inside(Vector3 point) { //IL_00bb: Unknown result type (might be due to invalid IL or missing references) if (!looked) { looked = true; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { MethodInfo methodInfo = assemblies[i].GetType("Leash.Api", throwOnError: false)?.GetMethod("IsInPen", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(Vector3) }, null); if (!(methodInfo == null) && !(methodInfo.ReturnType != typeof(bool))) { inPen = (Func<Vector3, bool>)Delegate.CreateDelegate(typeof(Func<Vector3, bool>), methodInfo); Plugin.Log("Leash found: no trails inside its pens"); break; } } } if (inPen == null) { return false; } try { return inPen(point); } catch (Exception ex) { Plugin.Warn("Leash pens: " + ex.Message + ", pens are ignored from now on"); inPen = null; return false; } } } internal enum WearRate { Slow, Normal, Fast, VeryFast } internal enum Growth { Off, Slow, Normal, Fast } [BepInPlugin("chistix.trails", "Trails", "0.2.9")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "chistix.trails"; public const string Version = "0.2.9"; private static ManualLogSource log; internal static readonly float[] WearScales = new float[4] { 0.5f, 1f, 2f, 4f }; internal static readonly double[] HalfLives = new double[4] { 0.0, 20.0, 8.0, 3.0 }; internal static readonly int[] RunBonuses = new int[6] { 0, 5, 10, 15, 20, 25 }; internal static readonly int[] StaminaSavings = new int[6] { 0, 10, 15, 20, 30, 40 }; internal static readonly int[] RoadBonuses = new int[4] { 0, 5, 10, 15 }; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> Tamed; internal static ConfigEntry<bool> Wild; internal static ConfigEntry<bool> Carts; internal static ConfigEntry<bool> CropTrampling; internal static ConfigEntry<bool> Mud; internal static ConfigEntry<bool> Roadside; internal static ConfigEntry<bool> Thinning; internal static ConfigEntry<bool> GravelPebbles; internal static ConfigEntry<bool> DebugLog; internal static ConfigEntry<WearRate> WearSpeed; internal static ConfigEntry<Growth> Regrowth; internal static ConfigEntry<int> RunBonus; internal static ConfigEntry<int> StaminaSaving; internal static ConfigEntry<int> RoadBonus; internal static bool Russian { get { if (Localization.instance != null) { return Localization.instance.GetSelectedLanguage() == "Russian"; } return false; } } private void Awake() { //IL_0314: Unknown result type (might be due to invalid IL or missing references) log = ((BaseUnityPlugin)this).Logger; int num = 100; Enabled = Bind("General", "Enabled", value: true, "Worn trails on.", "Протоптанные тропы включены.", num--); WearSpeed = Bind("General", "WearSpeed", WearRate.Normal, "How fast a trail wears in: Normal - the grass goes after some 16 crossings, the trail is finished after 45; Slow half as fast, Fast twice, VeryFast four times.", "Как быстро вытаптывается тропа: Normal - трава пропадает примерно после 16 проходов, тропа готова после 45; Slow вдвое медленнее, Fast вдвое быстрее, VeryFast вчетверо.", num--); Regrowth = Bind("General", "Regrowth", Growth.Normal, "How fast an unwalked trail grows back (it keeps for a game day first): its wear halves every 20 (Slow), 8 (Normal) or 3 (Fast) game days; Off - never.", "Как быстро зарастает нехоженая тропа (первые игровые сутки не меняется): износ вдвое за 20 (Slow), 8 (Normal) или 3 (Fast) игровых дня; Off - никогда.", num--); RunBonus = Bind("General", "RunBonus", 10, "% faster running and jogging on a finished trail (less on one wearing in).", "На сколько процентов быстрее бег и обычный ход по готовой тропе (по недотоптанной - меньше).", num--, (AcceptableValueBase)(object)new AcceptableValueList<int>(RunBonuses)); StaminaSaving = Bind("General", "StaminaSaving", 15, "% less stamina for running on a finished trail.", "На сколько процентов меньше выносливости уходит на бег по готовой тропе.", num--, (AcceptableValueBase)(object)new AcceptableValueList<int>(StaminaSavings)); RoadBonus = Bind("General", "RoadBonus", 5, "Roads: % faster than a trail per step (gravel one, stone two). On a road stamina also comes back faster (+25 % gravel, +50 % stone), carts are lighter, mounts faster; roads never grow back. Gravel: the hoe's \"Gravel road\" (1 stone); stone: the game's \"Paved road\" on top.", "Дороги: на сколько процентов быстрее тропы каждая ступень (гравий - одна, камень - две). На дороге ещё и выносливость восстанавливается быстрее (+25 % гравий, +50 % камень), телега легче, ездовой зверь быстрее; дорога не зарастает. Гравий - «Гравийная дорога» у мотыги (1 камень), камень - игровая «Мощёная дорога» поверх.", num--, (AcceptableValueBase)(object)new AcceptableValueList<int>(RoadBonuses)); Carts = Bind("General", "Carts", value: true, "Cart wheels wear two ruts that grow into a wide road; a cart is lighter on ruts and roads.", "Колёса телег протаптывают две колеи, из которых выходит широкая дорога; на колее и дороге телега легче.", num--); Mud = Bind("General", "Mud", value: true, "Rain turns earth trails to mud: while the ground is wet they are slower (down to -10 %), not faster. Mountains, plains, ash and roads stay firm.", "Дождь размывает земляные тропы в грязь: пока сыро, по ним медленнее (до −10 %), а не быстрее. Горы, равнины, пепел и дороги не размокают.", num--); CropTrampling = Bind("General", "CropTrampling", value: true, "Crops get trampled: a step on a crop sets its growth back a tenth, the fifth step in a game day kills it. Sneaking does no harm.", "Грядки мнутся: шаг по посадке задерживает её рост на десятую часть, пятый шаг за игровые сутки губит её. Крадущимся шагом растения не мнутся.", num--); Roadside = Bind("General", "Roadside", value: true, "Flowers and bushes grow along old trails over time (meadows, Black Forest, plains).", "Вдоль старых троп со временем вырастают цветы и кусты (луга, Чёрный лес, равнины).", num--); Tamed = Bind("Creatures", "TamedWear", value: false, "Tamed animals wear trails too (big ones wider). Off: only players and carts do.", "Приручённые животные тоже протаптывают тропы (крупные - шире). Выключено: топчут только игроки и телеги.", num--); Wild = Bind("Creatures", "WildWear", value: false, "Wild animals wear trails too.", "Дикие животные тоже протаптывают тропы.", num--); GravelPebbles = Bind("Visual", "GravelPebbles", value: true, "Small pebbles drawn over gravel roads near you (one light mesh per 32 m area, no shadows). Yours only.", "Мелкие камешки на гравийных дорогах рядом с вами (один лёгкий меш на участок 32 м, без теней). Только у вас.", num--, null, local: true); Thinning = Bind("Visual", "GrassThinning", value: true, "The grass of a trail thins little by little before it goes (flat worlds). Yours only.", "Трава на тропе редеет понемногу, прежде чем пропасть (плоский мир). Только у вас.", num--, null, local: true); DebugLog = Bind("Advanced", "DebugLog", value: false, "Details in the log.", "Подробности в журнал.", num--, null, local: true); ConfigEntryBase[] array = (ConfigEntryBase[])(object)new ConfigEntryBase[11] { (ConfigEntryBase)Enabled, (ConfigEntryBase)WearSpeed, (ConfigEntryBase)Regrowth, (ConfigEntryBase)RunBonus, (ConfigEntryBase)StaminaSaving, (ConfigEntryBase)Tamed, (ConfigEntryBase)Wild, (ConfigEntryBase)Carts, (ConfigEntryBase)RoadBonus, (ConfigEntryBase)CropTrampling, (ConfigEntryBase)Mud }; foreach (ConfigEntryBase entry in array) { ((BaseUnityPlugin)this).Config.SettingChanged += delegate(object s, SettingChangedEventArgs e) { if (e.ChangedSetting == entry) { Rules.Changed(); } }; } Prefabs.Make(); new Harmony("chistix.trails").PatchAll(typeof(Plugin).Assembly); Log("Trails 0.2.9"); } private void Update() { try { Rules.Update(); Walkers.Update(); Painter.Update(); Host.Update(); Gravel.Update(); } catch (Exception ex) { Warn("update: " + ex); } } private ConfigEntry<T> Bind<T>(string section, string key, T value, string en, string ru, int order, AcceptableValueBase values = null, bool local = false) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown return ((BaseUnityPlugin)this).Config.Bind<T>(section, key, value, new ConfigDescription(en + (local ? "" : " In multiplayer the host's value applies.") + " / " + ru + (local ? "" : " В мультиплеере действует значение хоста."), values, new object[1] { new ConfigurationManagerAttributes { Order = order } })); } internal static string T(string ru, string en) { if (!Russian) { return en; } return ru; } internal static void Log(string text) { ManualLogSource obj = log; if (obj != null) { obj.LogInfo((object)text); } } internal static void Warn(string text) { ManualLogSource obj = log; if (obj != null) { obj.LogWarning((object)text); } } internal static void Debug(string text) { if (DebugLog != null && DebugLog.Value) { ManualLogSource obj = log; if (obj != null) { obj.LogInfo((object)text); } } } } [HarmonyPatch] internal static class Network { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__2_0; internal void <Command>b__2_0(ConsoleEventArgs args) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { args.Context.AddString("trails: no player"); return; } Vector3 position = ((Component)localPlayer).transform.position; if (args.Length >= 2 && (args[1] == "stamp" || args[1] == "clear")) { if (!Rules.Server || !args.Context.IsCheatsEnabled()) { args.Context.AddString("trails: host with devcommands only"); return; } float result; float result2; float radius = ((args.Length >= 4 && float.TryParse(args[3], NumberStyles.Float, CultureInfo.InvariantCulture, out result)) ? result : ((args[1] == "clear" && args.Length >= 3 && float.TryParse(args[2], NumberStyles.Float, CultureInfo.InvariantCulture, out result2)) ? result2 : 1.5f)); if (args[1] == "clear") { args.Context.AddString($"trails: {Host.Scale(position, radius, 0f, roads: true)} cells cleared (roads too)"); return; } float result3; float num = ((args.Length >= 3 && float.TryParse(args[2], NumberStyles.Float, CultureInfo.InvariantCulture, out result3)) ? result3 : 20f); args.Context.AddString($"trails: {Host.Stamp(position, radius, num)} cells +{num}"); } else { args.Context.AddString(Status(position)); } } } [HarmonyPostfix] [HarmonyPatch(typeof(ZNet), "Awake")] private static void Start() { Host.Clear(); Walkers.Clear(); Painter.Clear(); Rules.Reset(); Gravel.Clear(); ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { Rules.Register(instance); Host.Register(instance); Painter.Register(instance); } } [HarmonyPrefix] [HarmonyPatch(typeof(ZNet), "OnDestroy")] private static void Stop() { Host.Clear(); Walkers.Clear(); Painter.Clear(); Rules.Reset(); Gravel.Clear(); } [HarmonyPostfix] [HarmonyPatch(typeof(Terminal), "InitTerminal")] private static void Command() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown object obj = <>c.<>9__2_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { args.Context.AddString("trails: no player"); } else { Vector3 position = ((Component)localPlayer).transform.position; if (args.Length >= 2 && (args[1] == "stamp" || args[1] == "clear")) { if (!Rules.Server || !args.Context.IsCheatsEnabled()) { args.Context.AddString("trails: host with devcommands only"); } else { float result; float result2; float radius = ((args.Length >= 4 && float.TryParse(args[3], NumberStyles.Float, CultureInfo.InvariantCulture, out result)) ? result : ((args[1] == "clear" && args.Length >= 3 && float.TryParse(args[2], NumberStyles.Float, CultureInfo.InvariantCulture, out result2)) ? result2 : 1.5f)); if (args[1] == "clear") { args.Context.AddString($"trails: {Host.Scale(position, radius, 0f, roads: true)} cells cleared (roads too)"); } else { float result3; float num = ((args.Length >= 3 && float.TryParse(args[2], NumberStyles.Float, CultureInfo.InvariantCulture, out result3)) ? result3 : 20f); args.Context.AddString($"trails: {Host.Stamp(position, radius, num)} cells +{num}"); } } } else { args.Context.AddString(Status(position)); } } }; <>c.<>9__2_0 = val; obj = (object)val; } new ConsoleCommand("trails", "[stamp N [radius] | clear [radius]] — Trails: wear here, or (host, cheats) wear the ground", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } internal static string Status(Vector3 pos) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) float num = TrailRegion.WearAt(pos); return "trails 0.2.9: " + (Rules.Enabled ? "on" : (Rules.Received ? "off" : "waiting for the host")) + ", " + (Surface.Sphere ? "planet" : "flat") + ", " + string.Format("wear here {0:0.0} (thin {1:0.00}, step {2}, run {3:0.00}), on trail {4:0.00}, road {5}, wet {6:0.00}{7}, speed x{8:0.00}, ", num, Stages.Thin(num), Stages.Paint(num, 0), Stages.Speed(num), Walkers.LocalTrail, Walkers.LocalRoad, Walkers.Wet, Walkers.LocalMuddy ? " (mud)" : "", Effects.Speed()) + $"trampled {Walkers.Trampled}, sown {Painter.Sown}, " + $"loaded regions {TrailRegion.Loaded.Count}, sent {Walkers.Sent}, painted {Painter.Painted}" + (Rules.Server ? (", host: " + Host.Report(pos)) : ""); } } internal sealed class ConfigurationManagerAttributes { public int? Order; } internal static class Prefabs { internal const string RegionName = "chistix_trails_region"; internal static readonly int RegionHash = StringExtensionMethods.GetStableHashCode("chistix_trails_region"); internal static readonly int KeyHash = StringExtensionMethods.GetStableHashCode("chistix_trails_key"); internal static readonly int CellsHash = StringExtensionMethods.GetStableHashCode("chistix_trails_cells"); internal static readonly int BornHash = StringExtensionMethods.GetStableHashCode("chistix_trails_born"); internal static readonly int FlowersHash = StringExtensionMethods.GetStableHashCode("chistix_trails_flowers"); private static GameObject holder; private static GameObject region; private static readonly Dictionary<int, TerrainOp> paints = new Dictionary<int, TerrainOp>(); internal static Transform Holder { get { Make(); return holder.transform; } } internal static void Make() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown if ((Object)(object)holder != (Object)null) { return; } holder = new GameObject("Trails prefabs"); holder.SetActive(false); Object.DontDestroyOnLoad((Object)(object)holder); region = new GameObject("chistix_trails_region"); region.transform.SetParent(holder.transform, false); ZNetView obj = region.AddComponent<ZNetView>(); obj.m_persistent = true; obj.m_type = (ObjectType)0; region.AddComponent<TrailRegion>(); for (int i = 0; i <= 4; i++) { for (int j = 0; j <= 4; j++) { if (i != j) { GameObject val = new GameObject(PaintName(i, j)); val.transform.SetParent(holder.transform, false); TerrainOp val2 = val.AddComponent<TerrainOp>(); val2.m_settings = new Settings { m_level = false, m_raise = false, m_smooth = false, m_halfOffset = false, m_paintCleared = true, m_paintHeightCheck = false, m_paintType = (PaintType)((j <= i) ? 3 : 0), m_paintRadius = 1.5f, m_paintExp = 1f, m_paintStrength = Stages.PaintStrength(i, j) }; paints[Key(i, j)] = val2; } } } } private static int Key(int from, int to) { return from * 16 + to; } private static string PaintName(int from, int to) { return $"chistix_trails_paint_{((to > from) ? 'u' : 'd')}{from}{to}"; } internal static TerrainOp Paint(int from, int to) { if (!paints.TryGetValue(Key(from, to), out var value)) { return null; } return value; } internal static void RegisterScene(ZNetScene scene) { if (!((Object)(object)scene == (Object)null) && !((Object)(object)region == (Object)null) && !scene.m_namedPrefabs.ContainsKey(RegionHash)) { scene.m_namedPrefabs[RegionHash] = region; scene.m_prefabs.Add(region); } } internal static void RegisterObjects(ObjectDB db) { if ((Object)(object)db == (Object)null) { return; } foreach (TerrainOp value in paints.Values) { int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)((Component)value).gameObject).name); if (!db.m_terrainOpsByHash.ContainsKey(stableHashCode)) { db.m_terrainOpsByHash[stableHashCode] = value; } } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class RegisterRegionPrefab { private static void Postfix(ZNetScene __instance) { try { Prefabs.RegisterScene(__instance); } catch (Exception ex) { Plugin.Warn("region prefab: " + ex.Message); } } } [HarmonyPatch(typeof(ObjectDB), "Awake")] internal static class RegisterPaintOps { private static void Postfix(ObjectDB __instance) { try { Prefabs.RegisterObjects(__instance); } catch (Exception ex) { Plugin.Warn("paint ops: " + ex.Message); } } } internal sealed class TrailRegion : MonoBehaviour { internal static readonly Dictionary<long, TrailRegion> Loaded = new Dictionary<long, TrailRegion>(); private ZNetView view; private long key; private bool registered; private uint revision = uint.MaxValue; internal RegionData Data = new RegionData(); internal int Version; private float nextCheck; private float grassAt = -1f; private int thinning; private float lastGrass = -100f; private static readonly List<KeyValuePair<long, float>> brush = new List<KeyValuePair<long, float>>(); private void Awake() { view = ((Component)this).GetComponent<ZNetView>(); if (!((Object)(object)view == (Object)null) && view.IsValid()) { key = view.GetZDO().GetLong(Prefabs.KeyHash, 0L); Loaded[key] = this; registered = true; Refresh(); } } private void OnDestroy() { if (registered && Loaded.TryGetValue(key, out var value) && (Object)(object)value == (Object)(object)this) { Loaded.Remove(key); } } private void Update() { //IL_004b: Unknown result type (might be due to invalid IL or missing references) float time = Time.time; if (grassAt >= 0f && time >= grassAt) { grassAt = -1f; if ((Object)(object)ClutterSystem.instance != (Object)null && Plugin.Thinning.Value) { ClutterSystem.instance.ResetGrass(((Component)this).transform.position, 24f); } } if (time < nextCheck) { return; } nextCheck = time + 1f; try { Refresh(); } catch (Exception ex) { Plugin.Debug("region: " + ex.Message); } } private void Refresh() { ZDO val = (((Object)(object)view != (Object)null && view.IsValid()) ? view.GetZDO() : null); if (val == null || val.DataRevision == revision) { return; } revision = val.DataRevision; Data = RegionData.Read(val.GetByteArray(Prefabs.CellsHash, (byte[])null)); Version++; int num = 0; foreach (KeyValuePair<ushort, RegionData.Cell> cell in Data.Cells) { num = num * 31 + cell.Key * 7 + (int)(Stages.Thin(cell.Value.Wear) * 8f); } if (num != thinning) { thinning = num; if (grassAt < 0f) { grassAt = Mathf.Max(Time.time, lastGrass + 10f); } lastGrass = grassAt; } } internal static float WearAt(Vector3 world) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) byte road; return Sample(world, out road); } internal static float Sample(Vector3 world, out byte road) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) road = 0; if (Loaded.Count == 0 || !Surface.ToGrid(world, out var x, out var y, out var z)) { return 0f; } bool flat = Surface.Flat; Grid.Brush(x, y, z, 0.3, flat, brush); float num = 0f; float num2 = 0f; long num3 = long.MinValue; TrailRegion value = null; foreach (KeyValuePair<long, float> item in brush) { long num4 = Grid.RegionOf(item.Key); if (num4 != num3) { num3 = num4; Loaded.TryGetValue(num4, out value); } num2 += item.Value; if ((Object)(object)value != (Object)null && value.Data.Cells.TryGetValue(Grid.Local(item.Key), out var value2)) { num += value2.Wear * item.Value; if (item.Value > 0.5f && value2.Road > road) { road = value2.Road; } } } if (!(num2 > 0f)) { return 0f; } return num / num2; } } [HarmonyPatch] internal static class RoadPieces { internal const string GravelName = "chistix_trails_gravel"; private static GameObject gravel; private static readonly Action<Localization, string, string> AddWord = AccessTools.MethodDelegate<Action<Localization, string, string>>(AccessTools.Method(typeof(Localization), "AddWord", (Type[])null, (Type[])null), (object)null, true); [HarmonyPostfix] [HarmonyPatch(typeof(ObjectDB), "Awake")] private static void Items(ObjectDB __instance) { try { Make(__instance); } catch (Exception ex) { Plugin.Warn("gravel road: " + ex.Message); } } [HarmonyPostfix] [HarmonyPatch(typeof(ZNetScene), "Awake")] private static void Scene(ZNetScene __instance) { if (!((Object)(object)gravel == (Object)null) && !((Object)(object)__instance == (Object)null)) { int stableHashCode = StringExtensionMethods.GetStableHashCode("chistix_trails_gravel"); if (!__instance.m_namedPrefabs.ContainsKey(stableHashCode)) { __instance.m_namedPrefabs[stableHashCode] = gravel; __instance.m_prefabs.Add(gravel); } } } private static void Make(ObjectDB db) { //IL_00ed: 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_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_015a: 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_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Expected O, but got Unknown //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Expected O, but got Unknown GameObject itemPrefab = db.GetItemPrefab("Hoe"); PieceTable val = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null)?.m_itemData?.m_shared?.m_buildPieces; if ((Object)(object)val == (Object)null) { return; } Words(); if ((Object)(object)gravel == (Object)null) { GameObject val2 = val.m_pieces.Find(delegate(GameObject p) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Invalid comparison between Unknown and I4 if ((Object)(object)p != (Object)null) { TerrainOp component3 = p.GetComponent<TerrainOp>(); if (component3 != null && component3.m_settings.m_paintCleared) { return (int)component3.m_settings.m_paintType == 2; } } return false; }); GameObject itemPrefab2 = db.GetItemPrefab("Stone"); ItemDrop val3 = ((itemPrefab2 != null) ? itemPrefab2.GetComponent<ItemDrop>() : null); if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null) { Plugin.Warn("gravel road: the hoe has no paving piece (the game changed?)"); return; } gravel = Object.Instantiate<GameObject>(val2, Prefabs.Holder, false); ((Object)gravel).name = "chistix_trails_gravel"; TerrainOp component = gravel.GetComponent<TerrainOp>(); Settings settings = component.m_settings; component.m_settings = new Settings { m_levelOffset = settings.m_levelOffset, m_level = settings.m_level, m_levelRadius = settings.m_levelRadius, m_square = settings.m_square, m_raise = settings.m_raise, m_raiseRadius = settings.m_raiseRadius, m_raisePower = settings.m_raisePower, m_raiseDelta = settings.m_raiseDelta, m_smooth = settings.m_smooth, m_smoothRadius = settings.m_smoothRadius, m_smoothPower = settings.m_smoothPower, m_paintCleared = true, m_paintHeightCheck = settings.m_paintHeightCheck, m_paintType = (PaintType)2, m_paintRadius = settings.m_paintRadius, m_paintStrength = settings.m_paintStrength * 0.35f, m_paintExp = settings.m_paintExp, m_paintCurve = settings.m_paintCurve, m_rotation = settings.m_rotation, m_sides = settings.m_sides, m_halfOffset = settings.m_halfOffset }; Piece component2 = gravel.GetComponent<Piece>(); component2.m_name = "$chistix_trails_gravel"; component2.m_description = "$chistix_trails_gravel_desc"; component2.m_resources = (Requirement[])(object)new Requirement[1] { new Requirement { m_resItem = val3, m_amount = 1, m_recover = false } }; } if (!val.m_pieces.Contains(gravel)) { int num = val.m_pieces.FindIndex(delegate(GameObject p) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 if ((Object)(object)p != (Object)null) { TerrainOp component3 = p.GetComponent<TerrainOp>(); if (component3 != null) { return (int)component3.m_settings.m_paintType == 2; } } return false; }); val.m_pieces.Insert((num >= 0) ? num : val.m_pieces.Count, gravel); } int stableHashCode = StringExtensionMethods.GetStableHashCode("chistix_trails_gravel"); if (!db.m_terrainOpsByHash.ContainsKey(stableHashCode)) { db.m_terrainOpsByHash[stableHashCode] = gravel.GetComponent<TerrainOp>(); } if ((Object)(object)ZNetScene.instance != (Object)null) { Scene(ZNetScene.instance); } } private static void Words() { Localization instance = Localization.instance; if (instance != null) { bool flag = instance.GetSelectedLanguage() == "Russian"; AddWord(instance, "chistix_trails_gravel", flag ? "Гравийная дорога" : "Gravel road"); AddWord(instance, "chistix_trails_gravel_desc", flag ? "Засыпать тропу гравием: дорога быстрее тропы и не зарастает. Сверху можно вымостить камнем (мощёная дорога) — ещё быстрее." : "Lay gravel on a trail: a road, faster than the trail, that never grows back. Pave it with stone on top (paved road) to make it faster still."); } } internal static int Level(Piece piece) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Invalid comparison between Unknown and I4 //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Invalid comparison between Unknown and I4 //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Invalid comparison between Unknown and I4 //IL_0066: Unknown result type (might be due to invalid IL or missing references) TerrainOp val = (((Object)(object)piece != (Object)null) ? ((Component)piece).GetComponent<TerrainOp>() : null); if ((Object)(object)val == (Object)null || !val.m_settings.m_paintCleared) { return -1; } Settings settings = val.m_settings; if ((int)settings.m_paintType == 2) { if (!(Utils.GetPrefabName(((Component)piece).gameObject) == "chistix_trails_gravel")) { return 2; } return 1; } if (Surface.Sphere && settings.m_level && (int)settings.m_paintType == 0) { return -1; } if ((int)settings.m_paintType == 4 || (int)settings.m_paintType == 5) { return -1; } return 0; } [HarmonyPostfix] [HarmonyPatch(typeof(Player), "PlacePiece")] private static void Placed(Player __instance, Piece piece, Vector3 pos) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !Rules.Enabled) { return; } int num = Level(piece); if (num < 0) { return; } float paintRadius = ((Component)piece).GetComponent<TerrainOp>().m_settings.m_paintRadius; if (Rules.Server) { Host.SetRoad(pos, paintRadius, (byte)num); return; } ZPackage val = new ZPackage(); val.Write(pos); val.Write(paintRadius); val.Write((byte)num); ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC("chistix_trails_road", new object[1] { val }); } } catch (Exception ex) { Plugin.Warn("road stroke: " + ex.Message); } } } internal static class Rules { internal const string HelloRpc = "chistix_trails_hello"; internal const string RulesRpc = "chistix_trails_rules"; private const int Version = 4; private static bool received; private static bool enabled; private static bool tamed; private static bool wild; private static bool carts; private static bool crops; private static bool mud; private static int runBonus; private static int staminaSaving; private static int roadStep; private static float nextHello; private static int hellos; internal static bool Server { get { if ((Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.IsServer(); } return false; } } internal static bool Enabled { get { if (!Server) { if (received) { return enabled; } return false; } return Plugin.Enabled.Value; } } internal static int RunBonus { get { if (!Server) { return runBonus; } return Plugin.RunBonus.Value; } } internal static int StaminaSaving { get { if (!Server) { return staminaSaving; } return Plugin.StaminaSaving.Value; } } internal static int RoadStep { get { if (!Server) { return roadStep; } return Plugin.RoadBonus.Value; } } internal static bool Tamed { get { if (!Server) { return tamed; } return Plugin.Tamed.Value; } } internal static bool Wild { get { if (!Server) { return wild; } return Plugin.Wild.Value; } } internal static bool Carts { get { if (!Server) { return carts; } return Plugin.Carts.Value; } } internal static bool Crops { get { if (!Server) { return crops; } return Plugin.CropTrampling.Value; } } internal static bool Mud { get { if (!Server) { return mud; } return Plugin.Mud.Value; } } internal static bool Received { get { if (!Server) { return received; } return true; } } internal static void Register(ZRoutedRpc rpc) { rpc.Register<ZPackage>("chistix_trails_hello", (Action<long, ZPackage>)delegate(long sender, ZPackage pkg) { if (Server) { Send(sender); } }); rpc.Register<ZPackage>("chistix_trails_rules", (Action<long, ZPackage>)delegate(long sender, ZPackage pkg) { if (!Server) { Read(pkg); } }); } internal static void Reset() { received = false; nextHello = 0f; hellos = 0; } internal static void Update() { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown if (!Server && !received && ZRoutedRpc.instance != null && !((Object)(object)Player.m_localPlayer == (Object)null) && !(Time.time < nextHello) && hellos < 6) { nextHello = Time.time + 10f; if (++hellos == 6) { Plugin.Log("the host does not answer: no Trails there, trails are off"); } ZRoutedRpc.instance.InvokeRoutedRPC("chistix_trails_hello", new object[1] { (object)new ZPackage() }); } } internal static void Changed() { if (Server && ZRoutedRpc.instance != null && ZNet.instance.GetPeers().Count > 0) { Send(0L); } } private static void Send(long target) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(4); val.Write(Plugin.Enabled.Value); val.Write(Plugin.RunBonus.Value); val.Write(Plugin.StaminaSaving.Value); val.Write(Plugin.Tamed.Value); val.Write(Plugin.Carts.Value); val.Write(Plugin.RoadBonus.Value); val.Write(Plugin.CropTrampling.Value); val.Write(Plugin.Mud.Value); val.Write(Plugin.Wild.Value); ZRoutedRpc.instance.InvokeRoutedRPC(target, "chistix_trails_rules", new object[1] { val }); } private static void Read(ZPackage pkg) { try { if (pkg.ReadInt() != 4) { Plugin.Warn("the host's Trails is of another version: trails are off here"); received = true; enabled = false; return; } enabled = pkg.ReadBool(); runBonus = Mathf.Clamp(pkg.ReadInt(), 0, 100); staminaSaving = Mathf.Clamp(pkg.ReadInt(), 0, 100); tamed = pkg.ReadBool(); carts = pkg.ReadBool(); roadStep = Mathf.Clamp(pkg.ReadInt(), 0, 50); crops = pkg.ReadBool(); mud = pkg.ReadBool(); wild = pkg.ReadBool(); if (!received) { Plugin.Log(string.Format("host rules: trails {0}, run +{1}% (+{2}% a road step), stamina -{3}%, tamed {4}, wild {5}, carts {6}, crops {7}, mud {8}", enabled ? "on" : "off", runBonus, roadStep, staminaSaving, tamed, wild, carts, crops, mud)); } received = true; } catch (Exception ex) { Plugin.Warn("host rules: " + ex.Message); } } } internal static class Surface { private static bool looked; private static PropertyInfo active; private static PropertyInfo radius; private static Func<Vector3, bool> onSurface; private static Func<Vector3, bool> groundReady; private static MethodInfo groundPoint; private static Func<Vector3, Biome> planetBiome; private static int terrainLayer = -1; private static int sphereFrame = -1; private static bool sphere; internal static bool Sphere { get { int frameCount = Time.frameCount; if (frameCount == sphereFrame) { return sphere; } Look(); try { sphere = active != null && (bool)active.GetValue(null); } catch { sphere = false; } sphereFrame = frameCount; return sphere; } } private static float Radius { get { try { return (float)radius.GetValue(null); } catch { return 0f; } } } internal static int TerrainLayer { get { if (terrainLayer < 0) { terrainLayer = LayerMask.NameToLayer("terrain"); } return terrainLayer; } } internal static bool Flat => !Sphere; private static void Look() { if (looked) { return; } looked = true; try { Type type = (from a in AppDomain.CurrentDomain.GetAssemblies() select a.GetType("PlanetPrototype.PlanetApi", throwOnError: false)).FirstOrDefault((Type t) => t != null); if (type == null) { return; } BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public; PropertyInfo property = type.GetProperty("ApiVersion", bindingAttr); if (property == null || (int)property.GetValue(null) < 2) { Plugin.Warn("PlanetApi is older than v2: trails use the flat grid"); return; } active = type.GetProperty("Active", bindingAttr); radius = type.GetProperty("Radius", bindingAttr); onSurface = Bind(type.GetMethod("OnSurface", bindingAttr, null, new Type[1] { typeof(Vector3) }, null)); groundReady = Bind(type.GetMethod("GroundReady", bindingAttr, null, new Type[1] { typeof(Vector3) }, null)); groundPoint = type.GetMethod("GroundPoint", bindingAttr); MethodInfo method = type.GetMethod("Biome", bindingAttr, null, new Type[1] { typeof(Vector3) }, null); if (method != null && method.ReturnType == typeof(Biome)) { planetBiome = (Func<Vector3, Biome>)Delegate.CreateDelegate(typeof(Func<Vector3, Biome>), method); } if (active == null || radius == null || onSurface == null || groundPoint == null) { active = null; Plugin.Warn("PlanetApi lacks what trails need: flat grid"); } else { Plugin.Log("PlanetApi found: trails follow the planet's surface"); } } catch (Exception ex) { Plugin.Warn("PlanetApi: " + ex.Message); active = null; } } private static Func<Vector3, bool> Bind(MethodInfo m) { if (!(m == null)) { return (Func<Vector3, bool>)Delegate.CreateDelegate(typeof(Func<Vector3, bool>), m); } return null; } internal static bool ToGrid(Vector3 world, out double x, out double y, out double z) { //IL_0072: 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_008b: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) x = (y = (z = 0.0)); if (Sphere) { float num = Radius; if (num <= 0f || ((Vector3)(ref world)).sqrMagnitude < 1f || !onSurface(world)) { return false; } Vector3 val = ((Vector3)(ref world)).normalized * num; x = val.x; y = val.y; z = val.z; return true; } if (world.y > 3000f) { return false; } x = world.x; z = world.z; return true; } internal static bool Ground(long cell, out Vector3 point) { //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) Grid.Unpack(cell, out var x, out var y, out var z); if (Sphere) { Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor((float)x, (float)y, (float)z); point = val; if (groundReady != null && !groundReady(val)) { return false; } try { object[] array = new object[3] { val, null, null }; if (!(bool)groundPoint.Invoke(null, array)) { return false; } point = (Vector3)array[1]; return true; } catch { return false; } } point = new Vector3((float)x, 0f, (float)z); Heightmap val2 = Heightmap.FindHeightmap(point); float y2 = default(float); if ((Object)(object)val2 == (Object)null || !val2.GetWorldHeight(point, ref y2)) { return false; } point.y = y2; return true; } internal static Vector3 RegionPoint(long region, Vector3 near) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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_004c: Unknown result type (might be due to invalid IL or missing references) bool flag = Sphere; Grid.Centre(region, out var x, out var y, out var z, !flag); if (flag) { Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor((float)x, (float)y, (float)z); if (!(((Vector3)(ref val)).sqrMagnitude < 1f)) { return ((Vector3)(ref val)).normalized * Mathf.Max(((Vector3)(ref near)).magnitude, 1f); } return near; } return new Vector3((float)x, near.y, (float)z); } internal static Biome Biome(Vector3 world) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (Sphere && planetBiome != null) { try { return planetBiome(world); } catch { } } if (WorldGenerator.instance == null) { return (Biome)0; } return WorldGenerator.instance.GetBiome(world); } internal static Soil SoilOf(Biome b) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Invalid comparison between Unknown and I4 //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 if ((int)b <= 16) { if ((int)b == 4) { goto IL_001a; } if ((int)b == 16) { goto IL_001e; } } else { if ((int)b == 32) { goto IL_001e; } if ((int)b == 64) { goto IL_001a; } } return Soil.Earth; IL_001e: return Soil.Sand; IL_001a: return Soil.Snow; } internal static bool OnTerrain(Character c) { if ((Object)(object)c == (Object)null || c.IsDead() || !c.IsOnGround() || c.InWater() || c.IsSwimming() || c.InInterior()) { return false; } Collider lastGroundCollider = c.GetLastGroundCollider(); if ((Object)(object)lastGroundCollider != (Object)null) { return ((Component)lastGroundCollider).gameObject.layer == TerrainLayer; } return false; } } internal static class Walkers { private const float SampleEvery = 0.2f; private const float SendEvery = 4f; private const int MaxPerMessage = 3000; private const float WetIn = 300f; private const float DryIn = 900f; private static readonly Dictionary<int, Tracker> trackers = new Dictionary<int, Tracker>(); private static readonly HashSet<int> seen = new HashSet<int>(); private static readonly List<int> lost = new List<int>(); private static readonly Dictionary<long, float> pending = new Dictionary<long, float>(); private static Vector3 anchor; private static float nextSample; private static float nextSend; private static float lastSample; private static int terrainMask; internal static float LocalTrail; internal static float LocalWear; internal static float Wet; internal static byte LocalRoad; internal static bool LocalMuddy; internal static int Sent; internal static int Trampled; internal static readonly Dictionary<int, float> MountFactor = new Dictionary<int, float>(); internal static readonly Dictionary<int, float> CartFactor = new Dictionary<int, float>(); private static readonly Dictionary<ZDOID, Vector3> crops = new Dictionary<ZDOID, Vector3>(); private static readonly Collider[] near = (Collider[])(object)new Collider[16]; private static readonly List<ZDOID> left = new List<ZDOID>(); private static readonly int TrampleHash = StringExtensionMethods.GetStableHashCode("chistix_trails_trample"); private static readonly int TrampleDayHash = StringExtensionMethods.GetStableHashCode("chistix_trails_trample_day"); private static readonly List<KeyValuePair<long, float>> batch = new List<KeyValuePair<long,