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 MoonforgedEventManager v1.0.0
MoonforgedEventManager.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Json; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using TMPro; using UnityEngine; using UnityEngine.Audio; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("0.0.0.0")] namespace MoonforgedEventManager; public sealed class BannerClothMotion : MonoBehaviour { private static readonly Vector4[] players = (Vector4[])(object)new Vector4[16]; private static readonly int playerData = Shader.PropertyToID("_MoonforgedClothPlayers"); private static readonly int playerCount = Shader.PropertyToID("_MoonforgedClothPlayerCount"); private static readonly int enabledId = Shader.PropertyToID("_ClothEnabled"); private static readonly int bottomId = Shader.PropertyToID("_ClothBottom"); private static readonly int topId = Shader.PropertyToID("_ClothTop"); private static int lastFrame = -1; private void Start() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: 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_010e: 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) MaterialPropertyBlock val = new MaterialPropertyBlock(); Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>(true); Vector3 val5 = default(Vector3); foreach (Renderer val2 in componentsInChildren) { if (((Object)val2).name != "Banner_Cloth") { continue; } Mesh val3 = null; SkinnedMeshRenderer val4 = (SkinnedMeshRenderer)(object)((val2 is SkinnedMeshRenderer) ? val2 : null); if (Object.op_Implicit((Object)(object)val4)) { val3 = val4.sharedMesh; } else if (val2 is MeshRenderer) { MeshFilter component = ((Component)val2).GetComponent<MeshFilter>(); if (Object.op_Implicit((Object)(object)component)) { val3 = component.sharedMesh; } } if (!Object.op_Implicit((Object)(object)val3)) { continue; } Bounds bounds = val3.bounds; bool flag = false; Material[] sharedMaterials = val2.sharedMaterials; for (int j = 0; j < sharedMaterials.Length; j++) { if (Object.op_Implicit((Object)(object)sharedMaterials[j]) && sharedMaterials[j].HasProperty(enabledId)) { val.Clear(); val2.GetPropertyBlock(val, j); val.SetFloat(enabledId, 1f); val.SetFloat(bottomId, ((Bounds)(ref bounds)).min.y); val.SetFloat(topId, ((Bounds)(ref bounds)).max.y); val2.SetPropertyBlock(val, j); flag = true; } } if (flag) { Vector3 lossyScale = ((Component)val2).transform.lossyScale; ((Vector3)(ref val5))..ctor(3f / Mathf.Max(Mathf.Abs(lossyScale.x), 0.001f), 3f / Mathf.Max(Mathf.Abs(lossyScale.y), 0.001f), 3f / Mathf.Max(Mathf.Abs(lossyScale.z), 0.001f)); ((Bounds)(ref bounds)).Expand(val5); val2.localBounds = bounds; } } } private void LateUpdate() { //IL_0045: 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_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: 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_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_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_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: 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_00ee: 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_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: 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_0130: 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_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) if (lastFrame == Time.frameCount) { return; } lastFrame = Time.frameCount; int num = 0; List<Player> allPlayers = Player.GetAllPlayers(); Vector3 val = (Object.op_Implicit((Object)(object)Player.m_localPlayer) ? ((Component)Player.m_localPlayer).transform.position : Vector3.zero); foreach (Player item in allPlayers) { if (!Object.op_Implicit((Object)(object)item) || !((Component)item).gameObject.activeInHierarchy) { continue; } Vector3 val2 = ((Component)item).transform.position; CapsuleCollider component = ((Component)item).GetComponent<CapsuleCollider>(); float num2 = 1.8f; if (Object.op_Implicit((Object)(object)component)) { Bounds bounds = ((Collider)component).bounds; val2 = ((Bounds)(ref bounds)).center; bounds = ((Collider)component).bounds; val2.y = ((Bounds)(ref bounds)).min.y; bounds = ((Collider)component).bounds; num2 = ((Bounds)(ref bounds)).size.y; } int num3 = num; if (num == players.Length) { float num4 = -1f; num3 = 0; Vector3 val3; for (int i = 0; i < num; i++) { val3 = Vector4.op_Implicit(players[i]) - val; float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude; if (sqrMagnitude > num4) { num4 = sqrMagnitude; num3 = i; } } val3 = val2 - val; if (((Vector3)(ref val3)).sqrMagnitude >= num4) { continue; } } else { num++; } players[num3] = new Vector4(val2.x, val2.y, val2.z, num2); } Shader.SetGlobalVectorArray(playerData, players); Shader.SetGlobalInt(playerCount, num); } } public sealed class BannerNightEmission : MonoBehaviour { private sealed class Target { internal Renderer Renderer; internal int Index; internal Color Color; internal bool HasIntensity; internal float Intensity; } private static readonly HashSet<string> MaterialNames = new HashSet<string> { "Finish", "Start", "M_EM_Danger_Troll", "M_EM_Down", "M_EM_Left", "M_EM_Right", "M_EM_Safe_Haven", "M_EM_Turn_Around", "M_EM_Up", "M_EV_Other_Danger", "M_EM_Other_Danger" }; private readonly List<Target> targets = new List<Target>(); private readonly MaterialPropertyBlock block = new MaterialPropertyBlock(); private bool initialized; private bool lastNight; private float nextCheck; private void Start() { //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { Material[] sharedMaterials = val.sharedMaterials; for (int j = 0; j < sharedMaterials.Length; j++) { Material val2 = sharedMaterials[j]; if (Object.op_Implicit((Object)(object)val2)) { string text = ((Object)val2).name; if (text.EndsWith(" (Instance)", StringComparison.Ordinal)) { text = text.Substring(0, text.Length - " (Instance)".Length); } if (MaterialNames.Contains(text) && val2.HasProperty("_EmissionColor")) { bool flag = val2.HasProperty("_EmissionIntensity"); targets.Add(new Target { Renderer = val, Index = j, Color = val2.GetColor("_EmissionColor"), HasIntensity = flag, Intensity = (flag ? val2.GetFloat("_EmissionIntensity") : 1f) }); } } } } Update(); } private void Update() { //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)EnvMan.instance) || Time.time < nextCheck) { return; } nextCheck = Time.time + 1f; bool flag = EnvMan.IsNight(); if (initialized && flag == lastNight) { return; } initialized = true; lastNight = flag; foreach (Target target in targets) { if (Object.op_Implicit((Object)(object)target.Renderer)) { block.Clear(); target.Renderer.GetPropertyBlock(block, target.Index); block.SetColor("_EmissionColor", flag ? target.Color : Color.black); if (target.HasIntensity) { block.SetFloat("_EmissionIntensity", flag ? target.Intensity : 0f); } target.Renderer.SetPropertyBlock(block, target.Index); } } } } public class BannerServerText : MonoBehaviour { private static readonly HashSet<BannerServerText> activeBanners = new HashSet<BannerServerText>(); private TMP_Text serverNameText; private void Awake() { FindText(); } private void OnEnable() { activeBanners.Add(this); ApplySettings(); } private void Start() { ApplySettings(); } private void OnDisable() { activeBanners.Remove(this); } private void FindText() { TMP_Text[] componentsInChildren = ((Component)this).GetComponentsInChildren<TMP_Text>(true); TMP_Text[] array = componentsInChildren; foreach (TMP_Text val in array) { if (((Object)val).name == "ServerName_Text") { serverNameText = val; return; } } if (((Object)((Component)this).gameObject).name.StartsWith("M_EM_Hanging_Banner")) { TMP_Text[] array2 = componentsInChildren; foreach (TMP_Text val2 in array2) { if (((Object)val2).name == "Text (TMP)") { serverNameText = val2; return; } } } ManualLogSource modLogger = MoonforgedEventManager.ModLogger; if (modLogger != null) { modLogger.LogWarning((object)("[Moonforged Event Manager] ServerName_Text not found on " + ((Object)((Component)this).gameObject).name + ".")); } } public void ApplySettings() { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)serverNameText == (Object)null) { FindText(); } if (!((Object)(object)serverNameText == (Object)null) && MoonforgedEventManager.ShowServerName != null) { ((Behaviour)serverNameText).enabled = MoonforgedEventManager.ShowServerName.Value; serverNameText.text = MoonforgedEventManager.ServerNameText.Value; serverNameText.fontSize = MoonforgedEventManager.ServerNameFontSize.Value; Color color = default(Color); if (ColorUtility.TryParseHtmlString(MoonforgedEventManager.ServerNameColor.Value, ref color)) { ((Graphic)serverNameText).color = color; } if (((Object)((Component)this).gameObject).name.StartsWith("M_EM_Hanging_Banner")) { serverNameText.transform.localPosition = new Vector3(MoonforgedEventManager.ServerNamePosX.Value, MoonforgedEventManager.ServerNamePosY.Value, MoonforgedEventManager.ServerNamePosZ.Value); } } } public static void RefreshAll() { foreach (BannerServerText activeBanner in activeBanners) { if ((Object)(object)activeBanner != (Object)null) { activeBanner.ApplySettings(); } } } } public class DeathScoreboard : MonoBehaviour { private TMP_Text scoreText; private readonly TMP_Text[] columns = (TMP_Text[])(object)new TMP_Text[3]; private readonly TMP_Text[] glowColumns = (TMP_Text[])(object)new TMP_Text[3]; private readonly List<Material> materials = new List<Material>(); private Material separatorMaterial; private Material carvedMaterial; private Material blueMaterial; private readonly TMP_Text[] rankCells = (TMP_Text[])(object)new TMP_Text[30]; private readonly TMP_Text[] nameCells = (TMP_Text[])(object)new TMP_Text[30]; private readonly TMP_Text[] countCells = (TMP_Text[])(object)new TMP_Text[30]; private readonly TMP_Text[] blueNameCells = (TMP_Text[])(object)new TMP_Text[30]; private void Awake() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_00f6: 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_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: 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_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: 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_0164: 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_0174: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Unknown result type (might be due to invalid IL or missing references) //IL_03e4: Unknown result type (might be due to invalid IL or missing references) //IL_03f4: Unknown result type (might be due to invalid IL or missing references) //IL_0404: Expected O, but got Unknown //IL_0475: Unknown result type (might be due to invalid IL or missing references) //IL_0485: Unknown result type (might be due to invalid IL or missing references) //IL_04a6: Unknown result type (might be due to invalid IL or missing references) Scene scene = ((Component)this).gameObject.scene; if (!((Scene)(ref scene)).IsValid()) { return; } Transform val = ((Component)this).transform.Find("ScoreText"); scoreText = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<TMP_Text>() : ((Component)this).GetComponentInChildren<TMP_Text>(true)); if ((Object)(object)scoreText == (Object)null) { return; } TMP_FontAsset val2 = Resources.Load<TMP_FontAsset>("fonts & materials/valheim_fonts/Valheim-Norsebold"); if ((Object)(object)val2 == (Object)null) { TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>(); foreach (TMP_FontAsset val3 in array) { if (((Object)val3).name.ToLowerInvariant().Contains("norsebold")) { val2 = val3; break; } } } if ((Object)(object)val2 != (Object)null) { scoreText.font = val2; } RectTransform rectTransform = scoreText.rectTransform; Vector4 margin = scoreText.margin; float x = ((Transform)rectTransform).localPosition.x; Rect rect = rectTransform.rect; float num = x + ((Rect)(ref rect)).xMin + margin.x; float x2 = ((Transform)rectTransform).localPosition.x; rect = rectTransform.rect; float num2 = x2 + ((Rect)(ref rect)).xMax - margin.z; float y = ((Transform)rectTransform).localPosition.y; rect = rectTransform.rect; float num3 = y + ((Rect)(ref rect)).yMax - margin.y; float y2 = ((Transform)rectTransform).localPosition.y; rect = rectTransform.rect; float num4 = y2 + ((Rect)(ref rect)).yMin + margin.w; float num5 = (num2 - num) / 3f; float fontSize = scoreText.fontSize; scoreText.text = ""; for (int j = 0; j < 3; j++) { columns[j] = MakeText("CarvedNames_" + j, num + (float)j * num5 + num5 * 0.025f, num5 * 0.95f, num3, num4, fontSize, glow: false); glowColumns[j] = MakeText("BlueNames_" + j, num + (float)j * num5 + num5 * 0.025f, num5 * 0.95f, num3, num4, fontSize, glow: true); } float num6 = (num3 - num4) / 10f; for (int k = 0; k < 30; k++) { int num7 = k / 10; int num8 = k % 10; float num9 = num + (float)num7 * num5 + num5 * 0.025f; float top = num3 - (float)num8 * num6; float num10 = num5 * 0.95f; rankCells[k] = MakeCell("DeathRank_" + k, num9, num10 * 0.13f, top, num6, fontSize, glow: false); nameCells[k] = MakeCell("DeathName_" + k, num9 + num10 * 0.15f, num10 * 0.61f, top, num6, fontSize, glow: false); countCells[k] = MakeCell("DeathCount_" + k, num9 + num10 * 0.8f, num10 * 0.19f, top, num6, fontSize, glow: false); blueNameCells[k] = MakeCell("BlueDeathName_" + k, num9 + num10 * 0.15f, num10 * 0.61f, top, num6, fontSize, glow: true); countCells[k].alignment = (TextAlignmentOptions)4100; } ShowCells(show: false); Shader val4 = Shader.Find("Unlit/Color") ?? Shader.Find("Sprites/Default"); if ((Object)(object)val4 != (Object)null) { separatorMaterial = new Material(val4) { color = new Color(0.16f, 0.17f, 0.18f) }; for (int l = 1; l < 3; l++) { GameObject val5 = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)val5).name = "CarvedColumnSeparator_" + l; Object.Destroy((Object)(object)val5.GetComponent<Collider>()); val5.transform.SetParent(scoreText.transform.parent, false); val5.transform.localPosition = new Vector3(num + num5 * (float)l, (num3 + num4) / 2f, ((Transform)rectTransform).localPosition.z - 0.018f); val5.transform.localScale = new Vector3(0.018f, num3 - num4, 0.003f); val5.GetComponent<Renderer>().sharedMaterial = separatorMaterial; } } } private TMP_Text MakeText(string name, float left, float width, float top, float bottom, float font, bool glow) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: 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_0107: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0126: 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_018f: Expected O, but got Unknown //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: 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_0395: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_03cd: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate<GameObject>(((Component)scoreText).gameObject, scoreText.transform.parent); ((Object)val).name = name; TMP_Text component = val.GetComponent<TMP_Text>(); component.text = ""; component.margin = Vector4.zero; component.alignment = (TextAlignmentOptions)257; component.enableAutoSizing = false; component.fontSize = font; component.fontStyle = (FontStyles)16; component.richText = true; component.textWrappingMode = (TextWrappingModes)0; component.overflowMode = (TextOverflowModes)3; component.lineSpacing = 0f; RectTransform rectTransform = component.rectTransform; rectTransform.pivot = new Vector2(0.5f, 0.5f); rectTransform.sizeDelta = new Vector2(width, Mathf.Max(0.1f, top - bottom)); ((Transform)rectTransform).localPosition = new Vector3(left + width / 2f, (top + bottom) / 2f, ((Transform)scoreText.rectTransform).localPosition.z - (glow ? 0.012f : 0.01f)); ((Graphic)component).color = (glow ? new Color(0.15f, 0.65f, 1f) : new Color(0.12f, 0.13f, 0.14f)); Material val2 = (glow ? blueMaterial : carvedMaterial); if ((Object)(object)val2 != (Object)null) { component.fontSharedMaterial = val2; return component; } Material val3 = new Material(((TMP_Asset)scoreText.font).material); Shader val4 = Shader.Find("TextMeshPro/Distance Field"); if ((Object)(object)val4 != (Object)null) { val3.shader = val4; } if (glow) { blueMaterial = val3; } else { carvedMaterial = val3; } materials.Add(val3); component.fontSharedMaterial = val3; ((Graphic)component).color = (glow ? new Color(0.15f, 0.65f, 1f) : new Color(0.12f, 0.13f, 0.14f)); val3.SetColor("_FaceColor", Color.white); Set(val3, "_FaceDilate", 0f); if (glow) { val3.DisableKeyword("UNDERLAY_ON"); val3.EnableKeyword("GLOW_ON"); Set(val3, "_GlowPower", 0.65f); Set(val3, "_GlowOuter", 0.35f); if (val3.HasProperty("_GlowColor")) { val3.SetColor("_GlowColor", new Color(0.1f, 0.5f, 1.5f, 1f)); } } else { val3.DisableKeyword("GLOW_ON"); val3.EnableKeyword("UNDERLAY_ON"); val3.EnableKeyword("BEVEL_ON"); Set(val3, "_Bevel", 0.2f); Set(val3, "_BevelWidth", 0.3f); Set(val3, "_BevelOffset", -0.15f); Set(val3, "_LightAngle", 3.14f); Set(val3, "_Ambient", 0.6f); Set(val3, "_SpecularPower", 0f); Set(val3, "_OutlineWidth", 0.035f); if (val3.HasProperty("_OutlineColor")) { val3.SetColor("_OutlineColor", new Color(0.34f, 0.36f, 0.38f, 0.7f)); } if (val3.HasProperty("_UnderlayColor")) { val3.SetColor("_UnderlayColor", new Color(0.38f, 0.4f, 0.42f, 0.6f)); } Set(val3, "_UnderlayOffsetX", -0.3f); Set(val3, "_UnderlayOffsetY", 0.3f); Set(val3, "_UnderlaySoftness", 0.08f); } return component; } private TMP_Text MakeCell(string name, float x, float width, float top, float height, float font, bool glow) { TMP_Text val = MakeText(name, x, width, top, top - height, font, glow); val.alignment = (TextAlignmentOptions)4097; val.enableAutoSizing = true; val.fontSizeMax = font * (name.Contains("Name") ? 2f : 2.5f); val.fontSizeMin = font * 0.7f; val.overflowMode = (TextOverflowModes)1; val.richText = false; return val; } private void ShowCells(bool show) { for (int i = 0; i < 30; i++) { if (!((Object)(object)rankCells[i] == (Object)null)) { ((Component)rankCells[i]).gameObject.SetActive(show); ((Component)nameCells[i]).gameObject.SetActive(show); ((Component)countCells[i]).gameObject.SetActive(show); ((Component)blueNameCells[i]).gameObject.SetActive(show); } } } private static void Set(Material mat, string key, float value) { if (mat.HasProperty(key)) { mat.SetFloat(key, value); } } private void OnEnable() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) Scene scene = ((Component)this).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { DeathTracker.Instance?.RegisterBoard(this); } } private void Start() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) Scene scene = ((Component)this).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { DeathTracker.Instance?.RegisterBoard(this); } } private void OnDisable() { DeathTracker.Instance?.UnregisterBoard(this); } private void OnDestroy() { foreach (Material material in materials) { Object.Destroy((Object)(object)material); } if ((Object)(object)separatorMaterial != (Object)null) { Object.Destroy((Object)(object)separatorMaterial); } } public void SetBoardText(string text) { if (!((Object)(object)columns[0] == (Object)null)) { ShowCells(show: false); TMP_Text[] array = columns; foreach (TMP_Text val in array) { ((Component)val).gameObject.SetActive(true); } columns[0].text = text; for (int j = 1; j < 3; j++) { columns[j].text = ""; } TMP_Text[] array2 = glowColumns; foreach (TMP_Text val2 in array2) { val2.text = ""; ((Component)val2).gameObject.SetActive(true); } } } internal void SetRows(List<DeathStoneRow> rows, int start, Func<long, bool> glowing) { if ((Object)(object)columns[0] == (Object)null) { return; } TMP_Text[] array = columns; foreach (TMP_Text val in array) { ((Component)val).gameObject.SetActive(false); } TMP_Text[] array2 = glowColumns; foreach (TMP_Text val2 in array2) { ((Component)val2).gameObject.SetActive(false); } ShowCells(show: true); for (int k = 0; k < 30; k++) { int num = start + k; bool flag = num < rows.Count; rankCells[k].text = (flag ? (num + 1 + ".") : ""); nameCells[k].text = (flag ? DeathTracker.Clean(rows[num].Name) : ""); countCells[k].text = (flag ? rows[num].Deaths.ToString() : ""); bool flag2 = flag && glowing(rows[num].Id); nameCells[k].alpha = (flag2 ? 0f : 1f); blueNameCells[k].text = (flag2 ? nameCells[k].text : ""); if (flag2) { nameCells[k].ForceMeshUpdate(false, false); blueNameCells[k].enableAutoSizing = false; blueNameCells[k].fontSize = nameCells[k].fontSize; } } } internal void Strike() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown //IL_00ee: 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_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: 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_0290: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) Scene scene = ((Component)this).gameObject.scene; if (!((Scene)(ref scene)).IsValid()) { return; } GameObject val = PrefabManager.Instance.GetPrefab("lightningAOE"); if ((Object)(object)val == (Object)null) { GameObject prefab = PrefabManager.Instance.GetPrefab("incinerator"); Incinerator val2 = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Incinerator>() : null); if ((Object)(object)val2 != (Object)null) { object? obj = AccessTools.Field(typeof(Incinerator), "m_lightingAOEs")?.GetValue(val2); val = (GameObject)((obj is GameObject) ? obj : null); } } if ((Object)(object)val == (Object)null) { return; } GameObject val3 = new GameObject("Death stone lightning"); val3.SetActive(false); val3.transform.position = (((Object)(object)scoreText != (Object)null) ? scoreText.transform.position : ((Component)this).transform.position); List<ParticleSystem> list = new List<ParticleSystem>(); ParticleSystem[] componentsInChildren = val.GetComponentsInChildren<ParticleSystem>(true); foreach (ParticleSystem val4 in componentsInChildren) { bool flag = false; Transform parent = ((Component)val4).transform.parent; while ((Object)(object)parent != (Object)null && (Object)(object)parent != (Object)(object)val.transform) { if ((Object)(object)((Component)parent).GetComponent<ParticleSystem>() != (Object)null) { flag = true; break; } parent = parent.parent; } if (!flag) { GameObject val5 = Object.Instantiate<GameObject>(((Component)val4).gameObject, val3.transform); val5.transform.localPosition = val.transform.InverseTransformPoint(((Component)val4).transform.position); val5.transform.localRotation = Quaternion.Inverse(val.transform.rotation) * ((Component)val4).transform.rotation; MonoBehaviour[] componentsInChildren2 = val5.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val6 in componentsInChildren2) { Object.DestroyImmediate((Object)(object)val6); } Collider[] componentsInChildren3 = val5.GetComponentsInChildren<Collider>(true); foreach (Collider val7 in componentsInChildren3) { Object.DestroyImmediate((Object)(object)val7); } AudioSource[] componentsInChildren4 = val5.GetComponentsInChildren<AudioSource>(true); foreach (AudioSource val8 in componentsInChildren4) { Object.DestroyImmediate((Object)(object)val8); } ParticleSystem[] componentsInChildren5 = val5.GetComponentsInChildren<ParticleSystem>(true); foreach (ParticleSystem val9 in componentsInChildren5) { ((Component)val9).gameObject.SetActive(true); MainModule main = val9.main; ((MainModule)(ref main)).playOnAwake = false; ((MainModule)(ref main)).loop = false; list.Add(val9); } val5.SetActive(true); } } val3.SetActive(true); foreach (ParticleSystem item in list) { item.Stop(false, (ParticleSystemStopBehavior)0); item.Play(false); } Object.Destroy((Object)(object)val3, 6f); } } public class DeathSoundGain : MonoBehaviour { private volatile float gain = 1f; private AudioSource source; private void Awake() { source = ((Component)this).GetComponent<AudioSource>(); Apply(); } private void Update() { Apply(); } private void Apply() { gain = DeathTracker.DeathGain; if ((Object)(object)source != (Object)null) { source.volume = Mathf.Clamp01(AudioMan.GetSFXVolume()); } } private void OnAudioFilterRead(float[] data, int channels) { float num = gain; for (int i = 0; i < data.Length; i++) { data[i] *= num; } } } internal sealed class DeathStoneRow { internal long Id; internal string Name; internal int Deaths; } internal static class DeathStoneLayout { internal const int PageSize = 30; internal static List<DeathStoneRow> Preview() { string[] array = new string[30] { "Caen", "Eirik", "Freya", "Bjorn", "Astrid", "Ragnar", "Sigrid", "Ulf", "Thyra", "Leif", "Hakon", "Ingrid", "Torsten", "Ylva", "Gunnar", "Solveig", "Ivar", "Runa", "Harald", "Liv", "Sten", "Helga", "Arne", "Kari", "Vidar", "Sven", "Dag", "Alva", "Torvi", "Einar" }; Random random = new Random(7241); List<DeathStoneRow> list = new List<DeathStoneRow>(); for (int i = 0; i < array.Length; i++) { list.Add(new DeathStoneRow { Id = -i - 1, Name = array[i], Deaths = random.Next(1, 100) }); } list.Sort((DeathStoneRow a, DeathStoneRow b) => b.Deaths.CompareTo(a.Deaths)); return list; } internal static string Row(DeathStoneRow row, int rank, bool hideName) { string text = row.Name.Replace("<", "").Replace(">", "").Replace("\n", " ") .Replace("\r", " "); if (text.Length > 16) { text = text.Substring(0, 15) + "…"; } return rank + ". " + (hideName ? ("<alpha=#00>" + text + "<alpha=#FF>") : text) + " <pos=82%>" + row.Deaths; } } public class DeathTracker : MonoBehaviour { [DataContract] private class DeathReport { [DataMember] public string EventId; [DataMember] public long PlayerId; [DataMember] public string PlayerName; [DataMember] public string Killer; [DataMember] public string Cause; } [DataContract] private class DeathAnnouncement { [DataMember] public long PlayerId; [DataMember] public bool FirstDeath; [DataMember] public string PlayerName; [DataMember] public string Killer; [DataMember] public string Cause; [DataMember] public int Deaths; } [DataContract] private class DeathTotals { [DataMember] public List<DeathEntry> Players = new List<DeathEntry>(); } [DataContract] private class DeathEntry { [DataMember] public long PlayerId; [DataMember] public string PlayerName; [DataMember] public int Deaths; } internal static DeathTracker Instance; internal static ConfigEntry<bool> ShowRaceDeaths; private int effectGeneration; private static ConfigEntry<bool> PreviewBoard; private readonly Dictionary<long, float> firstDeathGlow = new Dictionary<long, float>(); private static ConfigEntry<bool> Announcements; private static ConfigEntry<bool> AnnouncementSound; private static ConfigEntry<float> SoundVolume; private static ConfigEntry<float> SoundDelay; private static ConfigEntry<int> SoundRepeats; private readonly List<GameObject> activeDeathSounds = new List<GameObject>(); private static AudioClip deathClip; private const string ReportRpc = "MoonforgedDeaths_Report"; private const string StateRpc = "MoonforgedDeaths_State"; private const string RequestRpc = "MoonforgedDeaths_Request"; private const string AnnouncementRpc = "MoonforgedDeaths_Announce"; private readonly List<DeathScoreboard> boards = new List<DeathScoreboard>(); private readonly HashSet<string> received = new HashSet<string>(); private DeathTotals totals = new DeathTotals(); private ZRoutedRpc registeredRpc; private string filePath; private string snapshot; private bool canSave; private float pageStarted; private int page; private readonly Queue<string> notices = new Queue<string>(); private string currentNotice; private float noticeUntil; private GUIStyle noticeStyle; internal static float DeathGain => (SoundVolume == null) ? 1f : (Mathf.Clamp(SoundVolume.Value, 0f, 300f) / 100f); internal static void Initialize(ConfigFile config) { //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_0054: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Expected O, but got Unknown //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Expected O, but got Unknown //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Expected O, but got Unknown PreviewBoard = config.Bind<bool>("Deaths", "PreviewDeathBoard", false, "Local visual preview: display 30 sample players without changing saved death totals. Turn off to display real players."); PreviewBoard.SettingChanged += delegate { Instance?.RefreshBoards(); }; ConfigurationManagerAttributes val = new ConfigurationManagerAttributes { IsAdminOnly = true }; ShowRaceDeaths = config.Bind<bool>("Deaths", "ShowRaceDeaths", true, new ConfigDescription("Show race deaths on the right side of the event scoreboard.", (AcceptableValueBase)null, new object[1] { val })); ShowRaceDeaths.SettingChanged += delegate { MoonforgedTriathlonManager.Instance?.RefreshDeathColumns(); }; Announcements = config.Bind<bool>("Deaths", "DeathAnnouncements", true, new ConfigDescription("Announce player deaths and totals at the top of every player's screen.", (AcceptableValueBase)null, new object[1] { val })); AnnouncementSound = config.Bind<bool>("Deaths", "DeathSound", true, new ConfigDescription("Play Death Note once per death, including race deaths.", (AcceptableValueBase)null, new object[1] { val })); SoundVolume = config.Bind<float>("Deaths", "DeathSoundVolumePercent", 250f, new ConfigDescription("Death announcement gain, independent of the horn. 100 = original, 300 = triple gain; high gain may distort.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 300f), new object[1] { val })); SoundDelay = config.Bind<float>("Deaths", "DeathSoundDelaySeconds", 2f, new ConfigDescription("Delay after receiving a death before its sound plays.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 15f), new object[1] { val })); SoundRepeats = config.Bind<int>("Deaths", "DeathSoundRepeats", 1, new ConfigDescription("Number of full plays of the death clip. Two plays are about 8 seconds with the current clip.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 5), new object[1] { val })); } internal static void Load(AssetBundle bundle) { deathClip = bundle.LoadAsset<AudioClip>("assets/death_note.ogg") ?? bundle.LoadAsset<AudioClip>("assets/imperium events/horn/materials/death_note.ogg"); } private void Awake() { Instance = this; ((MonoBehaviour)this).StartCoroutine(NetworkSession()); } private void OnDestroy() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private IEnumerator NetworkSession() { while (true) { if (ZRoutedRpc.instance == null || (Object)(object)ZNet.instance == (Object)null) { registeredRpc = null; yield return null; continue; } if (registeredRpc != ZRoutedRpc.instance) { received.Clear(); firstDeathGlow.Clear(); foreach (GameObject sound in activeDeathSounds) { if ((Object)(object)sound != (Object)null) { Object.Destroy((Object)(object)sound); } } activeDeathSounds.Clear(); notices.Clear(); currentNotice = null; snapshot = null; page = 0; pageStarted = Time.unscaledTime; totals = new DeathTotals(); ZRoutedRpc.instance.Register<string>("MoonforgedDeaths_Report", (Action<long, string>)ReceiveDeath); ZRoutedRpc.instance.Register<string>("MoonforgedDeaths_State", (Action<long, string>)ReceiveState); ZRoutedRpc.instance.Register("MoonforgedDeaths_Request", (Action<long>)SendRequestedState); ZRoutedRpc.instance.Register<string>("MoonforgedDeaths_Announce", (Action<long, string>)ReceiveAnnouncement); registeredRpc = ZRoutedRpc.instance; if (ZNet.instance.IsServer()) { LoadTotals(); } else { RequestState(); } } else if (!ZNet.instance.IsServer() && snapshot == null) { RequestState(); } if (firstDeathGlow.Count == 0 && Time.unscaledTime - pageStarted >= 10f) { page++; pageStarted = Time.unscaledTime; RefreshBoards(); } yield return (object)new WaitForSecondsRealtime(1f); } } internal static string Clean(string value) { if (string.IsNullOrWhiteSpace(value)) { return "Unknown"; } string text = value.Replace("<", "").Replace(">", "").Replace("\n", " ") .Replace("\r", " ") .Replace("\u001f", " ") .Trim(); return (text.Length > 48) ? text.Substring(0, 48) : text; } internal void Report(Player player, HitData hit) { if ((FeatureSwitches.DeathEnabled || FeatureSwitches.EventEnabled) && !((Object)(object)player != (Object)(object)Player.m_localPlayer) && !((Object)(object)ZNet.instance == (Object)null) && ZRoutedRpc.instance != null && registeredRpc != null && registeredRpc == ZRoutedRpc.instance) { Character val = ((hit != null) ? hit.GetAttacker() : null); DeathReport value = new DeathReport { EventId = Guid.NewGuid().ToString("N"), PlayerId = player.GetPlayerID(), PlayerName = Clean(player.GetPlayerName()), Killer = (((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)player) ? Clean(val.GetHoverName()) : ""), Cause = ((hit != null) ? ((object)Unsafe.As<HitType, HitType>(ref hit.m_hitType)/*cast due to .constrained prefix*/).ToString() : "Undefined") }; long num = (ZNet.instance.IsServer() ? ZNet.GetUID() : (ZNet.instance.GetServerPeer()?.m_uid ?? 0)); if (num != 0) { ZRoutedRpc.instance.InvokeRoutedRPC(num, "MoonforgedDeaths_Report", new object[1] { Serialize(value) }); } } } private void ReceiveDeath(long sender, string json) { if ((!FeatureSwitches.DeathEnabled && !FeatureSwitches.EventEnabled) || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || string.IsNullOrEmpty(json) || json.Length > 4096) { return; } DeathReport report; try { report = Deserialize<DeathReport>(json); } catch { return; } if (report == null || report.PlayerId == 0L || string.IsNullOrEmpty(report.EventId) || report.EventId.Length != 32) { return; } if (sender != ZNet.GetUID()) { ZNetPeer peer = ZNet.instance.GetPeer(sender); if (peer == null || string.IsNullOrWhiteSpace(peer.m_playerName)) { return; } report.PlayerName = Clean(peer.m_playerName); } else if ((Object)(object)Player.m_localPlayer == (Object)null || Player.m_localPlayer.GetPlayerID() != report.PlayerId) { return; } string item = sender + ":" + report.EventId; if (received.Contains(item)) { return; } if (received.Count >= 4096) { received.Clear(); } received.Add(item); string playerName = Clean(report.PlayerName); MoonforgedTriathlonManager.Instance?.RecordRaceDeath(playerName); if (FeatureSwitches.DeathEnabled) { DeathEntry deathEntry = totals.Players.FirstOrDefault((DeathEntry x) => x.PlayerId == report.PlayerId); if (deathEntry == null) { deathEntry = new DeathEntry { PlayerId = report.PlayerId, PlayerName = playerName }; totals.Players.Add(deathEntry); } bool firstDeath = deathEntry.Deaths == 0; deathEntry.PlayerName = playerName; deathEntry.Deaths++; SaveTotals(); string text = Serialize(totals); ZRoutedRpc.instance.InvokeRoutedRPC(0L, "MoonforgedDeaths_State", new object[1] { text }); DeathAnnouncement value = new DeathAnnouncement { PlayerName = playerName, Killer = CleanOptional(report.Killer), Cause = report.Cause, Deaths = deathEntry.Deaths, PlayerId = deathEntry.PlayerId, FirstDeath = firstDeath }; ZRoutedRpc.instance.InvokeRoutedRPC(0L, "MoonforgedDeaths_Announce", new object[1] { Serialize(value) }); } } private static string CleanOptional(string value) { return string.IsNullOrWhiteSpace(value) ? "" : Clean(value); } private static bool FromServer(long sender) { if ((Object)(object)ZNet.instance == (Object)null) { return false; } int result; if (!ZNet.instance.IsServer()) { ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); result = ((serverPeer != null && serverPeer.m_uid == sender) ? 1 : 0); } else { result = ((sender == ZNet.GetUID()) ? 1 : 0); } return (byte)result != 0; } private void ReceiveState(long sender, string json) { if (!FromServer(sender) || string.IsNullOrEmpty(json)) { return; } try { DeathTotals deathTotals = Deserialize<DeathTotals>(json); if (deathTotals?.Players != null) { totals = deathTotals; snapshot = json; RefreshBoards(); } } catch { } } private void ReceiveAnnouncement(long sender, string json) { if (!FeatureSwitches.DeathEnabled || !FromServer(sender) || string.IsNullOrEmpty(json) || json.Length > 4096) { return; } DeathAnnouncement data; try { data = Deserialize<DeathAnnouncement>(json); } catch { return; } if (data == null) { return; } if (data.FirstDeath && data.PlayerId != 0) { firstDeathGlow[data.PlayerId] = Time.unscaledTime + 15f; List<DeathEntry> list = (from x in totals.Players orderby x.Deaths descending, x.PlayerName select x).ToList(); int num = list.FindIndex((DeathEntry x) => x.PlayerId == data.PlayerId); if (num >= 0) { page = num / 30; } pageStarted = Time.unscaledTime; RefreshBoards(); if (!PreviewBoard.Value) { foreach (DeathScoreboard board in boards) { if ((Object)(object)board != (Object)null) { board.Strike(); } } } } string text = CauseText(data); if ((Object)(object)Player.m_localPlayer != (Object)null && (Announcements.Value || AnnouncementSound.Value)) { notices.Enqueue(Clean(data.PlayerName) + text + " (Deaths: " + data.Deaths + ")"); if (string.IsNullOrEmpty(currentNotice)) { noticeUntil = 0f; } ((MonoBehaviour)this).StartCoroutine(PlayDeathSoundAfterDelay(registeredRpc, effectGeneration)); } } private IEnumerator PlayDeathSoundAfterDelay(ZRoutedRpc session, int generation) { yield return (object)new WaitForSecondsRealtime(SoundDelay.Value); if (generation == effectGeneration && FeatureSwitches.DeathEnabled && registeredRpc == session && ZRoutedRpc.instance == session && !((Object)(object)Player.m_localPlayer == (Object)null) && AnnouncementSound.Value && !(SoundVolume.Value <= 0f) && !((Object)(object)deathClip == (Object)null)) { GameObject go = new GameObject("Moonforged death announcement sound"); AudioSource source = go.AddComponent<AudioSource>(); source.playOnAwake = false; source.spatialBlend = 0f; source.outputAudioMixerGroup = null; source.clip = deathClip; int repeats = Mathf.Clamp(SoundRepeats.Value, 1, 5); source.loop = repeats > 1; go.AddComponent<DeathSoundGain>(); activeDeathSounds.Add(go); source.Play(); yield return (object)new WaitForSecondsRealtime(deathClip.length * (float)repeats); if ((Object)(object)go != (Object)null) { Object.Destroy((Object)(object)go); } activeDeathSounds.Remove(go); } } private void Update() { if (firstDeathGlow.Count > 0) { List<long> list = (from x in firstDeathGlow where Time.unscaledTime >= x.Value select x.Key).ToList(); foreach (long item in list) { firstDeathGlow.Remove(item); } if (list.Count > 0) { RefreshBoards(); } } if (!((Object)(object)Player.m_localPlayer == (Object)null) && !(Time.unscaledTime < noticeUntil)) { currentNotice = ((notices.Count > 0) ? notices.Dequeue() : null); if (currentNotice != null) { noticeUntil = Time.unscaledTime + 7f; } } } private void OnGUI() { //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0135: 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_0066: 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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown if (FeatureSwitches.DeathEnabled && !((Object)(object)Player.m_localPlayer == (Object)null) && Announcements.Value && !string.IsNullOrEmpty(currentNotice)) { if (noticeStyle == null) { noticeStyle = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)1, wordWrap = true }; } noticeStyle.fontSize = Mathf.Clamp(Screen.height / 40, 18, 36); Rect val = default(Rect); ((Rect)(ref val))..ctor((float)Screen.width * 0.1f, 8f, (float)Screen.width * 0.8f, 100f); noticeStyle.normal.textColor = Color.black; GUI.Label(new Rect(((Rect)(ref val)).x + 2f, ((Rect)(ref val)).y + 2f, ((Rect)(ref val)).width, ((Rect)(ref val)).height), currentNotice, noticeStyle); noticeStyle.normal.textColor = new Color(1f, 0.8f, 0.2f); GUI.Label(val, currentNotice, noticeStyle); } } private static string CauseText(DeathAnnouncement data) { if (!string.IsNullOrEmpty(data.Killer)) { string value = ((Localization.instance != null) ? Localization.instance.Localize(data.Killer) : data.Killer); return " was killed by " + Clean(value); } switch (data.Cause) { case "Fall": return " died from a fall"; case "Drowning": case "Water": return " drowned"; case "Burning": case "CinderFire": return " burned to death"; case "Freezing": return " froze to death"; case "Poisoned": return " died from poison"; case "Smoke": return " died from smoke"; case "Tree": return " was killed by a falling tree"; case "AshlandsLava": return " died in lava"; case "AshlandsOcean": return " died in boiling water"; case "EdgeOfWorld": return " fell off the edge of the world"; default: return " died"; } } private void RequestState() { if (!((Object)(object)ZNet.instance == (Object)null) && ZRoutedRpc.instance != null) { ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer != null) { ZRoutedRpc.instance.InvokeRoutedRPC(serverPeer.m_uid, "MoonforgedDeaths_Request", Array.Empty<object>()); } } } private void SendRequestedState(long sender) { if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && ZNet.instance.GetPeer(sender) != null) { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "MoonforgedDeaths_State", new object[1] { Serialize(totals) }); } } internal void RegisterBoard(DeathScoreboard board) { if (!boards.Contains(board)) { boards.Add(board); } RefreshBoards(); RequestState(); } internal void UnregisterBoard(DeathScoreboard board) { boards.Remove(board); } private void RefreshBoards() { List<DeathStoneRow> list = (PreviewBoard.Value ? DeathStoneLayout.Preview() : (from x in totals.Players orderby x.Deaths descending, x.PlayerName select new DeathStoneRow { Id = x.PlayerId, Name = Clean(x.PlayerName), Deaths = x.Deaths }).ToList()); int num = Math.Max(1, (list.Count + 30 - 1) / 30); int start = page % num * 30; for (int num2 = boards.Count - 1; num2 >= 0; num2--) { if ((Object)(object)boards[num2] == (Object)null) { boards.RemoveAt(num2); } else if (!FeatureSwitches.DeathEnabled) { boards[num2].SetBoardText("Death Note disabled."); } else if (list.Count == 0) { boards[num2].SetBoardText("No deaths recorded yet."); } else { boards[num2].SetRows(list, start, (long id) => firstDeathGlow.TryGetValue(id, out var value) && Time.unscaledTime < value); } } } internal void RefreshFeatureState() { if (!FeatureSwitches.DeathEnabled) { notices.Clear(); firstDeathGlow.Clear(); currentNotice = null; foreach (GameObject activeDeathSound in activeDeathSounds) { if ((Object)(object)activeDeathSound != (Object)null) { Object.Destroy((Object)(object)activeDeathSound); } } activeDeathSounds.Clear(); } RefreshBoards(); if (FeatureSwitches.DeathEnabled) { RequestState(); } } internal bool ClearTotalsForAdmin() { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return false; } DeathTotals value = new DeathTotals(); string text = Serialize(value); try { FeatureSwitches.BackupBeforeReset(filePath); string text2 = filePath + ".tmp"; File.WriteAllText(text2, text); if (File.Exists(filePath)) { File.Replace(text2, filePath, filePath + ".bak"); } else { File.Move(text2, filePath); } } catch (Exception ex) { ManualLogSource modLogger = MoonforgedEventManager.ModLogger; if (modLogger != null) { modLogger.LogError((object)("Could not clear death totals: " + ex.Message)); } return false; } totals = value; canSave = true; snapshot = text; ClearLocalEffects(); ZRoutedRpc.instance.InvokeRoutedRPC(0L, "MoonforgedDeaths_State", new object[1] { text }); return true; } internal void ClearLocalEffects() { PreviewBoard.Value = false; effectGeneration++; firstDeathGlow.Clear(); notices.Clear(); currentNotice = null; foreach (GameObject activeDeathSound in activeDeathSounds) { if ((Object)(object)activeDeathSound != (Object)null) { Object.Destroy((Object)(object)activeDeathSound); } } activeDeathSounds.Clear(); page = 0; RefreshBoards(); } private void LoadTotals() { filePath = Path.Combine(Paths.ConfigPath, "MoonforgedDeaths_" + ZNet.instance.GetWorldUID() + ".json"); canSave = true; if (File.Exists(filePath)) { try { totals = Deserialize<DeathTotals>(File.ReadAllText(filePath)); if (totals?.Players == null) { throw new InvalidDataException("Missing death entries."); } } catch (Exception ex) { totals = new DeathTotals(); canSave = false; ManualLogSource modLogger = MoonforgedEventManager.ModLogger; if (modLogger != null) { modLogger.LogError((object)("Could not read world death totals; preserving the saved file: " + ex.Message)); } } } snapshot = Serialize(totals); RefreshBoards(); } private void SaveTotals() { if (!canSave || string.IsNullOrEmpty(filePath)) { return; } try { string text = filePath + ".tmp"; File.WriteAllText(text, Serialize(totals)); if (File.Exists(filePath)) { File.Replace(text, filePath, filePath + ".bak"); } else { File.Move(text, filePath); } } catch (Exception ex) { ManualLogSource modLogger = MoonforgedEventManager.ModLogger; if (modLogger != null) { modLogger.LogError((object)("Could not save world death totals: " + ex.Message)); } } } private static string Serialize<T>(T value) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) using MemoryStream memoryStream = new MemoryStream(); ((XmlObjectSerializer)new DataContractJsonSerializer(typeof(T))).WriteObject((Stream)memoryStream, (object)value); return Encoding.UTF8.GetString(memoryStream.ToArray()); } private static T Deserialize<T>(string json) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) using MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(json)); return (T)((XmlObjectSerializer)new DataContractJsonSerializer(typeof(T))).ReadObject((Stream)memoryStream); } } [HarmonyPatch(typeof(Player), "OnDeath")] internal static class PlayerDeathReportPatch { private sealed class Capture { internal HitData Hit; } private static readonly FieldInfo LastHit = AccessTools.Field(typeof(Character), "m_lastHit"); private static void Prefix(Player __instance, out Capture __state) { __state = (((Object)(object)__instance == (Object)(object)Player.m_localPlayer && !((Character)__instance).IsDead()) ? new Capture { Hit = (HitData)/*isinst with value type is only supported in some contexts*/ } : null); } private static void Postfix(Player __instance, Capture __state) { if (__state != null && (Object)(object)__instance == (Object)(object)Player.m_localPlayer && ((Character)__instance).IsDead()) { DeathTracker.Instance?.Report(__instance, __state.Hit); } } } [DataContract] internal sealed class EventHistoryFile { [DataMember] public List<CompletedEvent> Events = new List<CompletedEvent>(); } [DataContract] internal sealed class CompletedEvent { [DataMember] public int Number; [DataMember] public string CompletedUtc; [DataMember] public int ParticipantCount; [DataMember] public List<CompletedEventResult> Results = new List<CompletedEventResult>(); } [DataContract] internal sealed class CompletedEventResult { [DataMember] public string PlayerName; [DataMember] public float TimeSeconds; [DataMember] public int Deaths; [DataMember] public bool Finished; } internal static class EventHistoryArchive { internal static EventHistoryFile Read(string path) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (!File.Exists(path)) { return new EventHistoryFile(); } using FileStream fileStream = File.OpenRead(path); EventHistoryFile eventHistoryFile = (EventHistoryFile)((XmlObjectSerializer)new DataContractJsonSerializer(typeof(EventHistoryFile))).ReadObject((Stream)fileStream); if (eventHistoryFile?.Events == null) { throw new InvalidDataException("Missing event history."); } HashSet<int> hashSet = new HashSet<int>(); foreach (CompletedEvent @event in eventHistoryFile.Events) { if (@event == null || @event.Results == null || @event.Number <= 0 || !hashSet.Add(@event.Number)) { throw new InvalidDataException("Invalid event history entry."); } } return eventHistoryFile; } internal static void Write(string path, EventHistoryFile data) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) string text = path + ".tmp"; using (FileStream fileStream = File.Create(text)) { ((XmlObjectSerializer)new DataContractJsonSerializer(typeof(EventHistoryFile))).WriteObject((Stream)fileStream, (object)data); } if (File.Exists(path)) { File.Replace(text, path, path + ".bak"); } else { File.Move(text, path); } } internal static int BrowseIndex(int current, int direction, int count) { if (count <= 0) { return -1; } return Math.Max(0, Math.Min(count - 1, current + direction)); } } internal static class FeatureSwitches { private const string ClearRpc = "Moonforged_AdminClear"; private const string ClearedRpc = "Moonforged_AdminCleared"; private const string ResultRpc = "Moonforged_AdminClearResult"; private static float confirmEventsUntil; private static float confirmDeathsUntil; private static ConfigEntry<bool> events; private static ConfigEntry<bool> deaths; private static readonly Dictionary<Piece, string> pieces = new Dictionary<Piece, string>(); internal static bool EventEnabled => events == null || events.Value; internal static bool DeathEnabled => deaths == null || deaths.Value; internal static void Initialize(ConfigFile config) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown ConfigurationManagerAttributes val = new ConfigurationManagerAttributes(); val.IsAdminOnly = true; val.CustomDrawer = DrawEvents; ConfigurationManagerAttributes val2 = val; val = new ConfigurationManagerAttributes(); val.IsAdminOnly = true; val.CustomDrawer = DrawDeaths; ConfigurationManagerAttributes val3 = val; events = config.Bind<bool>("General", "EventManagerEnabled", true, new ConfigDescription("Enable Event Manager and its hammer pieces. Disabling cancels the current race, but preserves saved event history. Synced from the server.", (AcceptableValueBase)null, new object[1] { val2 })); deaths = config.Bind<bool>("General", "DeathNoteEnabled", true, new ConfigDescription("Enable world death totals, announcements, sounds and the Death Note hammer piece. Saved totals are preserved when disabled. Race-only death counts remain part of Event Manager. Synced from the server.", (AcceptableValueBase)null, new object[1] { val3 })); events.SettingChanged += delegate { Refresh(); }; deaths.SettingChanged += delegate { Refresh(); }; } private static void DrawEvents(ConfigEntryBase entry) { DrawFeature(events, "Delete Events", 0, ref confirmEventsUntil); } private static void DrawDeaths(ConfigEntryBase entry) { DrawFeature(deaths, "Clear Death Names", 1, ref confirmDeathsUntil); } private static void DrawFeature(ConfigEntry<bool> entry, string label, int kind, ref float until) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); bool enabled = GUI.enabled; GUI.enabled = enabled && (Object)(object)ZNet.instance != (Object)null && ZNet.instance.LocalPlayerIsAdminOrHost(); bool flag = GUILayout.Toggle(entry.Value, entry.Value ? "On" : "Off", Array.Empty<GUILayoutOption>()); if (flag != entry.Value) { entry.Value = flag; } bool flag2 = Time.unscaledTime < until; if (GUILayout.Button(flag2 ? ("Confirm " + label) : label, Array.Empty<GUILayoutOption>())) { if (!flag2) { until = Time.unscaledTime + 5f; } else { until = 0f; long num = (ZNet.instance.IsServer() ? ZNet.GetUID() : (ZNet.instance.GetServerPeer()?.m_uid ?? 0)); if (num != 0L && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(num, "Moonforged_AdminClear", new object[1] { kind }); } } } GUI.enabled = enabled; GUILayout.EndHorizontal(); } internal static void RegisterAdminRpcs() { ZRoutedRpc.instance.Register<int>("Moonforged_AdminClear", (Action<long, int>)ServerClear); ZRoutedRpc.instance.Register<int>("Moonforged_AdminCleared", (Action<long, int>)ReceiveCleared); ZRoutedRpc.instance.Register<string>("Moonforged_AdminClearResult", (Action<long, string>)ReceiveResult); } private static bool IsServer(long sender) { int result; if ((Object)(object)ZNet.instance != (Object)null) { if (!ZNet.instance.IsServer()) { ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); result = ((serverPeer != null && serverPeer.m_uid == sender) ? 1 : 0); } else { result = ((sender == ZNet.GetUID()) ? 1 : 0); } } else { result = 0; } return (byte)result != 0; } private static void ServerClear(long sender, int kind) { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || (kind != 0 && kind != 1)) { return; } if (sender != ZNet.GetUID()) { ZNetPeer peer = ZNet.instance.GetPeer(sender); if (peer == null || peer.m_rpc == null || !ZNet.instance.IsAdmin(peer.m_rpc.GetSocket().GetHostName())) { return; } } bool flag = ((kind != 0) ? (DeathTracker.Instance?.ClearTotalsForAdmin() ?? false) : (MoonforgedTriathlonManager.Instance?.ClearEventsForAdmin() ?? false)); if (flag) { ZRoutedRpc.instance.InvokeRoutedRPC(0L, "Moonforged_AdminCleared", new object[1] { kind }); } ZRoutedRpc.instance.InvokeRoutedRPC(sender, "Moonforged_AdminClearResult", new object[1] { (!flag) ? "Could not clear saved data. Check the server log." : ((kind == 0) ? "Events and history cleared." : "Death names and totals cleared.") }); } private static void ReceiveCleared(long sender, int kind) { if (IsServer(sender)) { switch (kind) { case 0: MoonforgedTriathlonManager.PreviewEventBoard.Value = false; MoonforgedTriathlonManager.Instance?.RefreshClearedEvents(); break; case 1: DeathTracker.Instance?.ClearLocalEffects(); break; } } } private static void ReceiveResult(long sender, string message) { if (IsServer(sender) && (Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)2, message, 0, (Sprite)null, false, true); } } internal static void BackupBeforeReset(string path) { if (string.IsNullOrEmpty(path)) { throw new InvalidOperationException("World data is not ready."); } if (File.Exists(path)) { File.Copy(path, path + ".before-reset-" + DateTime.UtcNow.ToString("yyyyMMdd-HHmmss-fffffff") + ".bak", overwrite: false); } } internal static bool PieceEnabled(string name) { return (name == "M_EM_Death_Scoreboard") ? DeathEnabled : EventEnabled; } internal static void RegisterPiece(Piece piece, string name) { pieces[piece] = name; piece.m_enabled = PieceEnabled(name); } internal static void Refresh() { foreach (KeyValuePair<Piece, string> piece in pieces) { if ((Object)(object)piece.Key != (Object)null) { piece.Key.m_enabled = PieceEnabled(piece.Value); } } MoonforgedTriathlonManager.Instance?.RefreshFeatureState(); DeathTracker.Instance?.RefreshFeatureState(); } } public class FinishRuneInteract : MonoBehaviour, Hoverable, Interactable { private Piece m_piece; private void Awake() { m_piece = ((Component)this).GetComponent<Piece>(); } public bool Interact(Humanoid user, bool hold, bool alt) { if (hold) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if ((Object)(object)val == (Object)null || (Object)(object)MoonforgedTriathlonManager.Instance == (Object)null) { return false; } if (MoonforgedTriathlonManager.Instance.IsRaceEnded()) { MessageHud instance = MessageHud.instance; if (instance != null) { instance.ShowMessage((MessageType)2, "Event finished. Use Start Rune to reset.", 0, (Sprite)null, false, true); } return false; } MoonforgedTriathlonManager.Instance.RequestFinish(val); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } public string GetHoverText() { string text = (((Object)(object)m_piece != (Object)null) ? m_piece.m_name : "Finish Rune"); if ((Object)(object)MoonforgedTriathlonManager.Instance != (Object)null && MoonforgedTriathlonManager.Instance.IsRaceEnded()) { return text + "\nEvent finished"; } return text + "\n[<color=yellow><b>E</b></color>] Register my finish"; } public float GetHoverOffset() { return 0f; } public string GetHoverName() { return ((Object)(object)m_piece != (Object)null) ? m_piece.m_name : "Finish Rune"; } } public sealed class GateNightLights : MonoBehaviour { private sealed class Bulb { public Renderer Renderer; public int MaterialIndex; public Color Emission; } private const string StateKey = "MoonforgedGateNight"; private readonly List<GameObject> lightObjects = new List<GameObject>(); private readonly List<Bulb> bulbs = new List<Bulb>(); private ZNetView view; private float nextCheck; private bool initialized; private bool lastState; internal static void PreparePrefab(GameObject prefab) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 Light[] componentsInChildren = prefab.GetComponentsInChildren<Light>(true); foreach (Light val in componentsInChildren) { if ((int)val.type == 2) { if (val.intensity <= 0f) { val.intensity = 3f; } ((Behaviour)val).enabled = true; } } Renderer[] componentsInChildren2 = prefab.GetComponentsInChildren<Renderer>(true); foreach (Renderer val2 in componentsInChildren2) { if (!((Object)val2).name.Equals("bolb", StringComparison.OrdinalIgnoreCase) && !((Object)val2).name.Equals("bulb", StringComparison.OrdinalIgnoreCase)) { continue; } Material[] sharedMaterials = val2.sharedMaterials; foreach (Material val3 in sharedMaterials) { if ((Object)(object)val3 != (Object)null && val3.HasProperty("_EmissionColor")) { val3.EnableKeyword("_EMISSION"); } } } } private void Start() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) view = ((Component)this).GetComponent<ZNetView>(); Light[] componentsInChildren = ((Component)this).GetComponentsInChildren<Light>(true); foreach (Light val in componentsInChildren) { if ((int)val.type == 2 && !lightObjects.Contains(((Component)val).gameObject)) { lightObjects.Add(((Component)val).gameObject); } } Transform[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<Transform>(true); foreach (Transform val2 in componentsInChildren2) { if (((Object)val2).name.Equals("flare", StringComparison.OrdinalIgnoreCase) && !lightObjects.Contains(((Component)val2).gameObject)) { lightObjects.Add(((Component)val2).gameObject); } } Renderer[] componentsInChildren3 = ((Component)this).GetComponentsInChildren<Renderer>(true); foreach (Renderer val3 in componentsInChildren3) { if (!((Object)val3).name.Equals("bolb", StringComparison.OrdinalIgnoreCase) && !((Object)val3).name.Equals("bulb", StringComparison.OrdinalIgnoreCase)) { continue; } Material[] sharedMaterials = val3.sharedMaterials; for (int l = 0; l < sharedMaterials.Length; l++) { if (Object.op_Implicit((Object)(object)sharedMaterials[l]) && sharedMaterials[l].HasProperty("_EmissionColor")) { bulbs.Add(new Bulb { Renderer = val3, MaterialIndex = l, Emission = sharedMaterials[l].GetColor("_EmissionColor") }); } } } if (Player.IsPlacementGhost(((Component)this).gameObject)) { Apply(state: false); ((Behaviour)this).enabled = false; } else { Update(); } } private void Update() { if (Object.op_Implicit((Object)(object)view) && view.IsValid() && Object.op_Implicit((Object)(object)EnvMan.instance) && !(Time.time < nextCheck)) { nextCheck = Time.time + 1f; ZDO zDO = view.GetZDO(); bool flag = EnvMan.IsNight(); if (view.IsOwner() && zDO.GetBool("MoonforgedGateNight", false) != flag) { zDO.Set("MoonforgedGateNight", flag); } bool flag2 = zDO.GetBool("MoonforgedGateNight", false); if (!initialized || flag2 != lastState) { Apply(flag2); } } } private void Apply(bool state) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) initialized = true; lastState = state; foreach (GameObject lightObject in lightObjects) { if (Object.op_Implicit((Object)(object)lightObject)) { lightObject.SetActive(state); } } MaterialPropertyBlock val = new MaterialPropertyBlock(); foreach (Bulb bulb in bulbs) { if (Object.op_Implicit((Object)(object)bulb.Renderer)) { val.Clear(); bulb.Renderer.GetPropertyBlock(val, bulb.MaterialIndex); val.SetColor("_EmissionColor", state ? bulb.Emission : Color.black); bulb.Renderer.SetPropertyBlock(val, bulb.MaterialIndex); } } } } public class HornInteract : MonoBehaviour, Hoverable, Interactable { private Piece m_piece; private void Awake() { m_piece = ((Component)this).GetComponent<Piece>(); } private void Start() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown Switch[] componentsInChildren = ((Component)this).GetComponentsInChildren<Switch>(true); foreach (Switch val in componentsInChildren) { val.m_onUse = (Callback)((Switch source, Humanoid user, ItemData item) => item == null && Interact(user, hold: false, alt: false)); val.m_onHover = new TooltipCallback(GetHoverText); val.m_name = GetHoverName(); } } public bool Interact(Humanoid user, bool hold, bool alt) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) if (hold) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if ((Object)(object)val == (Object)null || (Object)(object)MoonforgedTriathlonManager.Instance == (Object)null) { return false; } if (!MoonforgedTriathlonManager.Instance.IsConfiguredAdmin(val)) { if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)2, "Only configured admin can start the race.", 0, (Sprite)null, false, true); } return false; } MoonforgedTriathlonManager.Instance.RequestStartRace(val, ((Component)this).transform.position); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } public string GetHoverText() { string text = (((Object)(object)m_piece != (Object)null) ? m_piece.m_name : "Horn"); return text + "\n[<color=yellow><b>E</b></color>] Start Moonforged Race"; } public float GetHoverOffset() { return 0f; } public string GetHoverName() { return ((Object)(object)m_piece != (Object)null) ? m_piece.m_name : "Horn"; } } internal static class HornSoundSettings { private static readonly Dictionary<string, AudioClip> clips = new Dictionary<string, AudioClip>(); internal static ConfigEntry<string> SelectedSound; internal static ConfigEntry<string> SelectedEndSound; private static ConfigEntry<float> HornVolumePercent; private static AudioSource preview; private static AudioSource template; private static AudioMixer hornMixer; private static readonly Dictionary<AudioSource, float> activeSources = new Dictionary<AudioSource, float>(); internal static void Initialize(ConfigFile config) { //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_0057: Expected O, but got Unknown //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown //IL_00f7: 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_0105: Expected O, but got Unknown //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Expected O, but got Unknown //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Expected O, but got Unknown //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Expected O, but got Unknown SelectedSound = config.Bind<string>("Race Horn", "HornSound", "Viking War Horn 1", new ConfigDescription("Sound played before the race countdown. Synced from the server.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[4] { "Fart Echo", "Viking War Horn 1", "Viking War Horn 2", "Viking War Horn 3" }), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); SelectedEndSound = config.Bind<string>("Race Horn", "EndSound", "Viking War Horn 3", new ConfigDescription("Sound played automatically when the final registered racer finishes. Synced from the server.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[4] { "Fart Echo", "Viking War Horn 1", "Viking War Horn 2", "Viking War Horn 3" }), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); HornVolumePercent = config.Bind<float>("Race Horn", "HornVolumePercent", 100f, new ConfigDescription("Horn volume percentage for race playback and local previews. 0 = muted, 100 = original, 200 = double gain. High values may distort. Synced from the server.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 300f), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); HornVolumePercent.SettingChanged += delegate { ApplyVolume(); }; object[] array = new object[1]; ConfigurationManagerAttributes val = new ConfigurationManagerAttributes(); val.CustomDrawer = DrawPreview; array[0] = val; config.Bind<bool>("Race Horn", "PreviewSound", false, new ConfigDescription("Preview the selected sound locally without starting a race.", (AcceptableValueBase)null, array)); } internal static void Load(AssetBundle bundle) { clips["Fart Echo"] = bundle.LoadAsset<AudioClip>("valheim_echo_loud_fart"); clips["Viking War Horn 1"] = bundle.LoadAsset<AudioClip>("assets/imperium events/horn/materials/viking-war-horn_1.ogg"); clips["Viking War Horn 2"] = bundle.LoadAsset<AudioClip>("assets/imperium events/horn/materials/viking-war-horn_2.ogg"); clips["Viking War Horn 3"] = bundle.LoadAsset<AudioClip>("assets/imperium events/horn/materials/viking-war-horn_3.ogg"); GameObject val = bundle.LoadAsset<GameObject>("M_EM_Horn"); if ((Object)(object)val != (Object)null) { template = val.GetComponent<AudioSource>(); if ((Object)(object)template != (Object)null && (Object)(object)template.outputAudioMixerGroup != (Object)null) { hornMixer = template.outputAudioMixerGroup.audioMixer; } ZSFX component = val.GetComponent<ZSFX>(); if ((Object)(object)component != (Object)null && component.m_audioClips != null && component.m_audioClips.Length != 0) { clips["Fart Echo"] = component.m_audioClips[0]; } } } internal static float Duration(string selection) { AudioClip value; return (clips.TryGetValue(selection, out value) && (Object)(object)value != (Object)null) ? value.length : 0f; } internal static void Play(string selection, Vector3 position, bool localPreview = false, bool global = false) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_003e: 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) if (clips.TryGetValue(selection, out var value) && !((Object)(object)value == (Object)null)) { GameObject val = new GameObject(localPreview ? "Moonforged horn preview" : "Moonforged race horn sound"); val.transform.position = position; AudioSource val2 = val.AddComponent<AudioSource>(); val2.playOnAwake = false; val2.loop = false; val2.pitch = 1f; val2.spatialBlend = ((localPreview || global) ? 0f : 1f); if ((Object)(object)template != (Object)null) { val2.outputAudioMixerGroup = template.outputAudioMixerGroup; val2.volume = template.volume; val2.minDistance = template.minDistance; val2.maxDistance = template.maxDistance; val2.rolloffMode = template.rolloffMode; } activeSources[val2] = val2.volume; ApplyVolume(); val2.PlayOneShot(value, 1f); if (localPreview) { preview = val2; } Object.Destroy((Object)(object)val, value.length + 0.25f); } } private static void ApplyVolume() { float num = Mathf.Clamp(HornVolumePercent.Value, 0f, 300f) / 100f; float num2 = ((num > 0f) ? Mathf.Clamp(20f * Mathf.Log10(num), -80f, 20f) : (-80f)); bool flag = (Object)(object)hornMixer != (Object)null && hornMixer.SetFloat("HornVolume", num2); List<AudioSource> list = new List<AudioSource>(); foreach (KeyValuePair<AudioSource, float> activeSource in activeSources) { if ((Object)(object)activeSource.Key == (Object)null) { list.Add(activeSource.Key); } else { activeSource.Key.volume = activeSource.Value * ((num <= 0f) ? 0f : (flag ? 1f : Mathf.Clamp01(num))); } } foreach (AudioSource item in list) { activeSources.Remove(item); } } private static void DrawPreview(ConfigEntryBase entry) { //IL_0030: 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) GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Play Preview", Array.Empty<GUILayoutOption>())) { StopPreview(); Play(SelectedSound.Value, Vector3.zero, localPreview: true); } if (GUILayout.Button("Preview End Sound", Array.Empty<GUILayoutOption>())) { StopPreview(); Play(SelectedEndSound.Value, Vector3.zero, localPreview: true); } if (GUILayout.Button("Stop Preview", Array.Empty<GUILayoutOption>())) { StopPreview(); } GUILayout.EndHorizontal(); } internal static void StopRaceSounds() { List<AudioSource> list = new List<AudioSource>(); foreach (KeyValuePair<AudioSource, float> activeSource in activeSources) { if ((Object)(object)activeSource.Key == (Object)null || (Object)(object)activeSource.Key != (Object)(object)preview) { if ((Object)(object)activeSource.Key != (Object)null) { Object.Destroy((Object)(object)((Component)activeSource.Key).gameObject); } list.Add(activeSource.Key); } } foreach (AudioSource item in list) { activeSources.Remove(item); } } private static void StopPreview() { if ((Object)(object)preview != (Object)null) { activeSources.Remove(preview); Object.Destroy((Object)(object)((Component)preview).gameObject); } preview = null; } } [BepInPlugin("Caenos.MoonforgedEventManager", "Moonforged Event Manager", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class MoonforgedEventManager : BaseUnityPlugin { public const string PluginGUID = "Caenos.MoonforgedEventManager"; public const string PluginName = "Moonforged Event Manager"; public const string PluginVersion = "1.0.0"; private AssetBundle relicsBundle; public static ConfigEntry<string> PlayerPreferredCategory; public static ManualLogSource ModLogger; internal static ConfigEntry<bool> ShowServerName; internal static ConfigEntry<string> ServerNameText; internal static ConfigEntry<float> ServerNameFontSize; internal static ConfigEntry<string> ServerNameColor; internal static ConfigEntry<float> ServerNamePosX; internal static ConfigEntry<float> ServerNamePosY; internal static ConfigEntry<float> ServerNamePosZ; private void Awake() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected O, but got Unknown //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Expected O, but got Unknown //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Expected O, but got Unknown //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Expected O, but got Unknown //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Expected O, but got Unknown //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Expected O, but got Unknown ModLogger = ((BaseUnityPlugin)this).Logger; new Harmony("caenos.moonforgedeventmanager.harmony").PatchAll(); PlayerPreferredCategory = ((BaseUnityPlugin)this).Config.Bind<string>("General", "CustomHammerTab", "Moonforged Event Manager", "Custom hammer tab category name"); ConfigurationManagerAttributes val = new ConfigurationManagerAttributes { IsAdminOnly = true }; FeatureSwitches.Initialize(((BaseUnityPlugin)this).Config); ShowServerName = ((BaseUnityPlugin)this).Config.Bind<bool>("Banner Text", "ShowServerName", true, new ConfigDescription("Display the server name on the hanging banner.", (AcceptableValueBase)null, new object[1] { val })); ServerNameText = ((BaseUnityPlugin)this).Config.Bind<string>("Banner Text", "ServerNameText", "MY SERVER NAME", new ConfigDescription("Server name displayed on the hanging banner. Synced to all players.", (AcceptableValueBase)null, new object[1] { val })); ServerNameFontSize = ((BaseUnityPlugin)this).Config.Bind<float>("Banner Text", "ServerNameFontSize", 23f, new ConfigDescription("TextMeshPro font size.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), new object[1] { val })); ServerNameColor = ((BaseUnityPlugin)this).Config.Bind<string>("Banner Text", "ServerNameColor", "#E5C16A", new ConfigDescription("Text color in hexadecimal format (example: #E5C16A).", (AcceptableValueBase)null, new object[1] { val })); ServerNamePosX = ((BaseUnityPlugin)this).Config.Bind<float>("Banner Text", "ServerNamePosX", 0f, new ConfigDescription("Text local horizontal position on Banner_Cloth.", (AcceptableValueBase)null, new object[1] { val })); ServerNamePosY = ((BaseUnityPlugin)this).Config.Bind<float>("Banner Text", "ServerNamePosY", -0.873f, new ConfigDescription("Text local vertical position on Banner_Cloth.", (AcceptableValueBase)null, new object[1] { val })); ServerNamePosZ = ((BaseUnityPlugin)this).Config.Bind<float>("Banner Text", "ServerNamePosZ", 0.025f, new ConfigDescription("Text local depth position on Banner_Cloth.", (AcceptableValueBase)null, new object[1] { val })); ShowServerName.SettingChanged += OnBannerConfigChanged; ServerNameText.SettingChanged += OnBannerConfigChanged; ServerNameFontSize.SettingChanged += OnBannerConfigChanged; ServerNameColor.SettingChanged += OnBannerConfigChanged; ServerNamePosX.SettingChanged += OnBannerConfigChanged; ServerNamePosY.SettingChanged += OnBannerConfigChanged; ServerNamePosZ.SettingChanged += OnBannerConfigChanged; SynchronizationManager.OnConfigurationSynchronized += delegate { BannerServerText.RefreshAll(); }; SynchronizationManager.OnConfigurationSynchronized += delegate { FeatureSwitches.Refresh(); }; DeathTracker.Initialize(((BaseUnityPlugin)this).Config); ((Component)this).gameObject.AddComponent<DeathTracker>(); HornSoundSettings.Initialize(((BaseUnityPlugin)this).Config); MoonforgedTriathlonManager.Initialize(((BaseUnityPlugin)this).Config); ((Component)this).gameObject.AddComponent<MoonforgedTriathlonManager>(); Assembly executingAssembly = Assembly.GetExecutingAssembly(); string text = executingAssembly.GetManifestResourceNames().FirstOrDefault((string r) => r.ToLower().Contains("moonforgedeventmanager")); if (string.IsNullOrEmpty(text)) { ((BaseUnityPlugin)this).Logger.LogError((object)"Could not find embedded asset bundle resource containing 'moonforgedeventmanager'."); return; } using (Stream stream = executingAssembly.GetManifestResourceStream(text)) { if (stream == null) { ((BaseUnityPlugin)this).Logger.LogError((object)("Embedded asset bundle stream was null for '" + text + "'.")); return; } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); relicsBundle = AssetBundle.LoadFromMemory(memoryStream.ToArray()); } if ((Object)(object)relicsBundle == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)"Failed to load AssetBundle from embedded resource!"); return; } HornSoundSettings.Load(relicsBundle); DeathTracker.Load(relicsBundle); PrefabManager.OnPrefabsRegistered -= RegisterNow; PrefabManager.OnPrefabsRegistered += RegisterNow; } private void OnBannerConfigChanged(object sender, EventArgs args) { BannerServerText.RefreshAll(); } private void RegisterNow() { if (!((Object)(object)relicsBundle == (Object)null)) { RelicRegistrar.RegisterAllRelics(relicsBundle); MoonforgedTriathlonBootstrap.AttachTriathlonComponents(((BaseUnityPlugin)this).Logger); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[Moonforged Event Manager] Registration complete. Hammer tab: '" + PlayerPreferredCategory.Value + "'.")); } } } public static class MoonforgedTriathlonBootstrap { public static void AttachTriathlonComponents(ManualLogSource logger) { AttachIfFound("M_EM_Horn", typeof(HornInteract), logger); AttachIfFound("M_EM_Start_Rune", typeof(StartRuneInteract), logger); AttachIfFound("M_EM_Finish_Rune", typeof(FinishRuneInteract), logger); AttachIfFound("M_EM_Scoreboard", typeof(RaceScoreboard), logger); AttachIfFound("M_EM_Death_Scoreboard", typeof(DeathScoreboard), logger); AttachNightLight("M_EM_Death_Scoreboard", logger); } private static void AttachIfFound(string prefabName, Type componentType, ManualLogSource logger) { GameObject prefab = PrefabManager.Instance.GetPrefab(prefabName); if ((Object)(object)prefab == (Object)null) { if (logger != null) { logger.LogWarning((object)("[MoonforgedEventManager] Prefab not found for triathlon hookup: " + prefabName)); } } else if ((Object)(object)prefab.GetComponent(componentType) == (Object)null) { prefab.AddComponent(componentType); } } private static void AttachNightLight(string prefabName, ManualLogSource logger) { GameObject prefab = PrefabManager.Instance.GetPrefab(prefabName); if ((Object)(object)prefab == (Object)null) { if (logger != null) { logger.LogWarning((object)("[MoonforgedEventManager] " + prefabName + " prefab not found.")); } return; } Transform val = prefab.transform.Find("NightLight"); if (!((Object)(object)val == (Object)null) && (Object)(object)((Component)val).GetComponent<ScoreboardEmissionNight>() == (Object)null) { ((Component)val).gameObject.AddComponent<ScoreboardEmissionNight>(); } } } public class MoonforgedTriathlonManager : MonoBehaviour { [Serializable] private struct EntrantState { public string PlayerName; public int Deaths; public bool Registered; public bool Finished; public double StartTime; public double FinishTime; } [Serializable] private class RaceResultsFile { public string EventName; public string SavedAt; public List<RaceResultEntry> Results = new List<RaceResultEntry>(); } [Serializable] private class RaceResultEntry { public string PlayerName; public int Deaths; public float TimeSeconds; public string TimeFormatted; } private static class MiniJson { public static string Serialize(RaceResultsFile file) { if (file == null) { return "{}"; } string text = "{\n"; text = text + " \"EventName\": " + Quote(file.EventName) + ",\n"; text = text + " \"SavedAt\": " + Quote(file.SavedAt) + ",\n"; text += " \"Results\": [\n"; for (int i = 0; i < file.Results.Count; i++) { RaceResultEntry raceResultEntry = file.Results[i]; text += " {\n"; text = text + " \"PlayerName\": " + Quote(raceResultEntry.PlayerName) + ",\n"; text = text + " \"Deaths\": " + raceResultEntry.Deaths + ",\n"; text = text + " \"TimeSeconds\": " + raceResultEntry.TimeSeconds.ToString(CultureInfo.InvariantCulture) + ",\n"; text = text + " \"TimeFormatted\": " + Quote(raceResultEntry.TimeFormatted) + "\n"; text += " }"; if (i < file.Results.Count - 1) { text += ","; } text += "\n"; } text += " ]\n"; return text + "}"; } private static string Quote(string value) { if (value == null) { return "\"\""; } return "\"" + value.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\n", "\\n") .Replace("\r", "\\r") .Replace("\t", "\\t") + "\""; } } public static MoonforgedTriathlonManager Instance; private const string RpcRegister = "MoonforgedTriathlon_Register"; private const string RpcFinish = "MoonforgedTriathlon_Finish"; private const string RpcStartRace = "MoonforgedTriathlon_StartRace"; private const string RpcAdminReset = "MoonforgedTriathlon_AdminReset"; private const string RpcBoardText = "MoonforgedTriathlon_BoardText"; private const string RpcCenterMessage = "MoonforgedTriathlon_CenterMessage"; private const string RpcResultsPopup = "MoonforgedTriathlon_ResultsPopup"; private EventHistoryFile eventHistory = new EventHistoryFile(); private string historyPath; private bool historyWritable; private int selectedHistoryIndex = -1; private int pendingHistoryIndex = -1; private string lastHistoryColumn = "EVENT HISTORY\n\nNo completed events yet."; private string lastHistorySelection = "No saved events"; private const string RpcHistorySelect = "MoonforgedTriathlon_HistorySelect"; private const string RpcHistoryDisplay = "MoonforgedTriathlon_HistoryDisplay"; private string raceStartSound; private Vector3 raceHornPosition; private const string RpcFinishHorn = "MoonforgedTriathlon_FinishHorn"; private const string RpcCancelRace = "MoonforgedTriathlon_CancelRace"; private const string RpcStopHorn = "MoonforgedTriathlon_StopHorn"; private Coroutine startSequence; private int deathPage; private float nextDeathPage; private const string RpcHornSound = "MoonforgedTriathlon_HornSound"; private const string RpcState = "MoonforgedTriathlon_State"; private const string RpcRequestState = "MoonforgedTriathlon_RequestState"; internal static ConfigEntry<bool> PreviewEventBoard; private static ConfigEntry<string> AdminPlayerNames; private static ConfigEntry<string> ResultsFileName; private static ConfigEntry<float> CountdownSeconds; private static ConfigEntry<bool> RequireConfiguredAdminForStartAndReset; private readonly Dictionary<string, EntrantState> entrants = new Dictionary<string, EntrantState>(StringComparer.OrdinalIgnoreCase); private readonly List<RaceScoreboard> localBoards = new List<RaceScoreboard>(); private bool registrationOpen = true; private bool raceStarted = false; private bool raceEnded = false; private double raceStartServerTime = 0.0; private bool rpcsRegistered = false; private ZRoutedRpc registeredRpc; private string lastBoardText; public static void Initialize(ConfigFile config) { //IL_003a: 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_0048: Expected O, but got Unknown //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_00a2: 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_00b0: Expected O, but got Unknown //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Expected O, but got Unknown //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Expected O, but got Unknown PreviewEventBoard = config.Bind<bool>("Moonforged Event Manager", "PreviewEventBoard", false, "Local layout preview with ten sample racers. Does not register players or change saved race results. Turn off to show the real race."); AdminPlayerNames = config.Bind<string>("Moonforged Event Manager", "AdminPlayerNames", "Caenos", new ConfigDescription("Comma separated character names allowed to start/reset the event. Example: Caenos,Caen", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); ResultsFileName = config.Bind<string>("Moonforged Event Manager", "ResultsFileName", "MoonforgedTriathlonResults.json", "JSON file written into BepInEx/config."); CountdownSeconds = config.Bind<float>("Moonforged Event Manager", "CountdownSeconds", 5f, new ConfigDescription("Countdown after the horn sound finishes.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); RequireConfiguredAdminForStartAndReset = config.Bind<bool>("Moonforged Event Manager", "RequireConfiguredAdminForStartAndReset", true, new ConfigDescription("If true, only names in AdminPlayerNames can start/reset the race.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); } private void Awake() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)this); return; } Instance = this; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); ((MonoBehaviour)this).StartCoroutine(RegisterRpcsWhenReady()); } private IEnumerator RegisterRpcsWhenReady() { while (true) { if (ZRoutedRpc.instance == null || (Object)(object)ZNet.instance == (Object)null) { yield return null; continue; } if (registeredRpc != ZRoutedRpc.instance) { if (startSequence != null) { ((MonoBehaviour)this).StopCoroutine(startSequence); } startSequence = null; ResetRaceServer(); MoonforgedTriathlonManager moonforgedTriathlonManager = this; MoonforgedTriathlonManager moonforgedTriathlonManager2 = this; int num = -1; moonforgedTriathlonManager2.pendingHistoryIndex = -1; moonforgedTriathlonManager.selectedHistoryIndex = num; lastHistoryColumn = "EVENT HISTORY\n\nLoading history..."; lastHistorySelection = "Loading history..."; if (ZNet.instance.IsServer()) { LoadEventHistory(); } lastBoardText = null; FeatureSwitches.RegisterAdminRpcs(); ZRoutedRpc.instance.Register<string, int>("MoonforgedTriathlon_HistorySelect", (Action<long, string, int>)RPC_HistorySelect); ZRoutedRpc.instance.Register<string, string>("MoonforgedTriathlon_HistoryDisplay", (Action<long, string, string>)RPC_HistoryDisplay); ZRoutedRpc.instance.Register<string, Vector3>("MoonforgedTriathlon_FinishHorn", (Action<long, string, Vector3>)RPC_FinishHorn); ZRoutedRpc.instance.Register<string>("MoonforgedTriathlon_CancelRace", (Action<long, string>)RPC_CancelRace); ZRoutedRpc.instance.Register("MoonforgedTriathlon_StopHorn", (Action<long>)RPC_StopHorn); ZRoutedRpc.instance.Register<string>("MoonforgedTriathlon_Register", (Action<long, string>)RPC_Register); ZRoutedRpc.instance.Register<string>("MoonforgedTriathlon_Finish", (Action<long, string>)RPC_Finish); ZRoutedRpc.instance.Register<string, Vector3>("MoonforgedTriathlon_StartRace", (Action<long, string, Vector3>)RPC_StartRace); ZRoutedRpc.instance.Register<string, Vector3>("MoonforgedTriathlon_HornSound", (Action<long, string, Vector3>)RPC_HornSound); ZRoutedRpc.instance.Register<string>("MoonforgedTriathlon_AdminReset", (Action<long, string>)RPC_AdminReset); ZRoutedRpc.instance.Register<string>("MoonforgedTriathlon_BoardText", (Action<long, string>)RPC_BoardText); ZRoutedRpc.instance.Register<string>("MoonforgedTriathlon_CenterMessage", (Action<long, string>)RPC_CenterMessage); ZRoutedRpc.instance.Register<string>("MoonforgedTriathlon_ResultsPopup", (Action<long, string>)RPC_ResultsPopup); ZRoutedRpc.instance.Register<string>("MoonforgedTriathlon_State", (Action<long, string>)RPC_State); ZRoutedRpc.instance.Register("MoonforgedTriathlon_RequestState", (Action<long>)RPC_RequestState); registeredRpc = ZRoutedRpc.instance; rpcsRegistered = true; RequestState(); } else if (FeatureSwitches.EventEnabled && !ZNet.instance.IsServer() && lastBoardText == null) { RequestState(); } if (FeatureSwitches.EventEnabled && ZNet.instance.IsServer() && Time.unscaledTime >= nextDeathPage) { nextDeathPage = Time.unscaledTime + 10f; deathPage++; BroadcastBoardText(BuildBoardText()); } yield return (object)new WaitForSecondsRealtime(1f); } } public void ForceEndRace(