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 One in 10000 v1.0.0
One_in_10000.dll
Decompiled 3 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.UI; using UnityEngine.Video; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("1 in 10000")] [assembly: AssemblyProduct("1 in 10000")] [assembly: AssemblyCompany("ModdedWolf")] [assembly: AssemblyDescription("1 in 10000 chance of a Foxy jumpscare in Valheim.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace OneIn10000 { internal static class ChromaKey { internal static Color32[] Apply(RenderTexture source, Texture2D destination, Color32[] buffer) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_0093: 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_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_010c: 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) if ((Object)(object)source == (Object)null || (Object)(object)destination == (Object)null) { return buffer; } int num = ((Texture)destination).width * ((Texture)destination).height; RenderTexture active = RenderTexture.active; try { RenderTexture.active = source; destination.ReadPixels(new Rect(0f, 0f, (float)((Texture)destination).width, (float)((Texture)destination).height), 0, 0, false); } finally { RenderTexture.active = active; } buffer = destination.GetPixels32(); if (buffer == null || buffer.Length != num) { return buffer; } int num2 = 32; for (int i = 0; i < num; i++) { Color32 val = buffer[i]; int num3 = ((val.r > val.b) ? val.r : val.b); int num4 = val.g - num3; if (num4 >= 72) { buffer[i] = new Color32((byte)0, (byte)0, (byte)0, (byte)0); } else if (num4 > num2) { int num5 = 255 - (num4 - num2) * 255 / 40; if (num5 < 0) { num5 = 0; } if (val.g > num3) { val.g = (byte)num3; } val.a = (byte)num5; buffer[i] = val; } else { if (val.g > num3 + 10) { val.g = (byte)(num3 + 10); } val.a = byte.MaxValue; buffer[i] = val; } } destination.SetPixels32(buffer); destination.Apply(false, false); return buffer; } } internal static class EmbeddedVideo { internal const string ResourceName = "foxy.mp4"; internal static bool TryExtract(out string path, out string error) { Stream manifestResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("foxy.mp4"); if (manifestResourceStream == null) { path = null; error = "1 in 10000: embedded foxy.mp4 is missing from the DLL."; return false; } try { string text = Path.Combine(Path.GetTempPath(), "OneIn10000"); Directory.CreateDirectory(text); path = Path.Combine(text, "foxy.mp4"); if (!File.Exists(path) || new FileInfo(path).Length != manifestResourceStream.Length) { using FileStream destination = File.Create(path); manifestResourceStream.CopyTo(destination); } error = null; return true; } catch (IOException ex) { path = null; error = "1 in 10000: failed to unpack the embedded video. " + ex.Message; return false; } finally { manifestResourceStream.Dispose(); } } } internal static class FoxyNet { internal const string PlayRpc = "ModdedWolf_OneIn10000_Play"; internal const string SettingsRpc = "ModdedWolf_OneIn10000_Settings"; internal const string HelloRpc = "ModdedWolf_OneIn10000_Hello"; private static ZRoutedRpc _registeredOn; internal static bool IsServer() { if ((Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.IsServer(); } return false; } internal static bool IsDedicated() { if ((Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.IsDedicated(); } return false; } internal static bool IsWorldHost() { return IsServer(); } internal static bool IsInPlayableWorld() { if ((Object)(object)ZNet.instance == (Object)null) { return false; } if (IsDedicated()) { return true; } return (Object)(object)Player.m_localPlayer != (Object)null; } internal static void TryRegister(Action<long> onPlay, Action<long, float> onSettings, Action<long, string> onHello) { if (ZRoutedRpc.instance != null && _registeredOn != ZRoutedRpc.instance) { ZRoutedRpc.instance.Register("ModdedWolf_OneIn10000_Play", onPlay); ZRoutedRpc.instance.Register<float>("ModdedWolf_OneIn10000_Settings", onSettings); ZRoutedRpc.instance.Register<string>("ModdedWolf_OneIn10000_Hello", onHello); _registeredOn = ZRoutedRpc.instance; OneIn10000Plugin.Log.LogInfo((object)"Registered jumpscare RPCs."); } } internal static bool IsRegistered() { if (_registeredOn != null) { return _registeredOn == ZRoutedRpc.instance; } return false; } internal static void Unregister() { _registeredOn = null; } internal static void SendPlay(long peerId) { if (ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(peerId, "ModdedWolf_OneIn10000_Play", Array.Empty<object>()); } } internal static void SendSettings(long peerId, float chancePercent) { if (ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(peerId, "ModdedWolf_OneIn10000_Settings", new object[1] { chancePercent }); } } internal static void SendHello(string version) { if (ZRoutedRpc.instance != null && !((Object)(object)ZNet.instance == (Object)null)) { ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer != null && serverPeer.m_uid != 0L) { ZRoutedRpc.instance.InvokeRoutedRPC(serverPeer.m_uid, "ModdedWolf_OneIn10000_Hello", new object[1] { version }); } } } internal static void KickPeer(ZNetPeer peer, string reason) { if (peer == null || (Object)(object)ZNet.instance == (Object)null) { return; } OneIn10000Plugin.Log.LogWarning((object)$"Kicking peer {peer.m_uid} ({peer.m_playerName}): {reason}"); try { string playerName = peer.m_playerName; if (!string.IsNullOrEmpty(playerName)) { ZNet.instance.Kick(playerName); return; } MethodInfo method = typeof(ZNet).GetMethod("InternalKick", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[1] { typeof(ZNetPeer) }, null); if (method != null) { method.Invoke(ZNet.instance, new object[1] { peer }); return; } typeof(ZNet).GetMethod("SendDisconnect", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[1] { typeof(ZNetPeer) }, null)?.Invoke(ZNet.instance, new object[1] { peer }); ZNet.instance.Disconnect(peer); } catch (Exception ex) { OneIn10000Plugin.Log.LogError((object)$"Failed to kick peer {peer.m_uid}: {ex.Message}"); } } internal static ZNetPeer FindPeer(long peerId) { List<ZNetPeer> remotePeers = GetRemotePeers(); for (int i = 0; i < remotePeers.Count; i++) { ZNetPeer val = remotePeers[i]; if (val != null && val.m_uid == peerId) { return val; } } return null; } internal static List<ZNetPeer> GetRemotePeers() { if ((Object)(object)ZNet.instance == (Object)null) { return new List<ZNetPeer>(); } List<ZNetPeer> connectedPeers = ZNet.instance.GetConnectedPeers(); if (connectedPeers != null && connectedPeers.Count > 0) { return connectedPeers; } return ZNet.instance.GetPeers() ?? new List<ZNetPeer>(); } internal static bool IsTrustedSender(long sender) { if ((Object)(object)ZNet.instance == (Object)null) { return false; } if (IsServer()) { return true; } if (sender == 0L) { return true; } ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer == null) { return true; } return sender == serverPeer.m_uid; } } internal sealed class JumpscareController { private const float PrepareTimeoutSeconds = 8f; private const float StallTimeoutSeconds = 8f; private GameObject _root; private RawImage _image; private AspectRatioFitter _aspectFitter; private VideoPlayer _player; private AudioSource _audio; private RenderTexture _videoRt; private Texture2D _keyed; private Color32[] _chromaBuffer; private bool _started; private bool _framePending; private bool _finished; private bool _endFramePresented; private bool _loggedPlayError; private float _lastFrameTime; private int _playId; internal bool IsPlaying { get; private set; } internal void EnsureOverlay() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_010f: 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_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Expected O, but got Unknown //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Expected O, but got Unknown //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Expected O, but got Unknown if (!((Object)(object)_root != (Object)null)) { _root = new GameObject("OneIn10000Overlay", new Type[1] { typeof(RectTransform) }); Object.DontDestroyOnLoad((Object)(object)_root); Canvas obj = _root.AddComponent<Canvas>(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 32767; obj.pixelPerfect = false; CanvasScaler obj2 = _root.AddComponent<CanvasScaler>(); obj2.uiScaleMode = (ScaleMode)1; obj2.referenceResolution = new Vector2(1920f, 1080f); obj2.screenMatchMode = (ScreenMatchMode)0; obj2.matchWidthOrHeight = 0.5f; GameObject val = new GameObject("Foxy", new Type[1] { typeof(RectTransform) }); val.transform.SetParent(_root.transform, false); _image = val.AddComponent<RawImage>(); ((Graphic)_image).raycastTarget = false; ((Graphic)_image).color = Color.white; _image.uvRect = new Rect(0f, 0f, 1f, 1f); ((Behaviour)_image).enabled = false; RectTransform rectTransform = ((Graphic)_image).rectTransform; rectTransform.anchorMin = Vector2.zero; rectTransform.anchorMax = Vector2.one; rectTransform.pivot = new Vector2(0.5f, 0.5f); rectTransform.offsetMin = Vector2.zero; rectTransform.offsetMax = Vector2.zero; _aspectFitter = val.AddComponent<AspectRatioFitter>(); _aspectFitter.aspectMode = (AspectMode)3; _audio = _root.AddComponent<AudioSource>(); _audio.playOnAwake = false; _audio.loop = false; _audio.spatialBlend = 0f; _audio.ignoreListenerPause = true; _audio.bypassListenerEffects = true; _player = _root.AddComponent<VideoPlayer>(); _player.playOnAwake = false; _player.isLooping = false; _player.waitForFirstFrame = true; _player.skipOnDrop = false; _player.playbackSpeed = 1f; _player.timeUpdateMode = (VideoTimeUpdateMode)2; _player.sendFrameReadyEvents = true; _player.source = (VideoSource)1; _player.renderMode = (VideoRenderMode)2; _player.aspectRatio = (VideoAspectRatio)3; _player.audioOutputMode = (VideoAudioOutputMode)1; _player.controlledAudioTrackCount = 1; _player.frameReady += new FrameReadyEventHandler(OnFrameReady); _player.loopPointReached += new EventHandler(OnFinished); _player.errorReceived += new ErrorEventHandler(OnError); } } internal IEnumerator Play(string path) { EnsureOverlay(); Stop(); int playId = ++_playId; IsPlaying = true; _loggedPlayError = false; _audio.volume = 1f; _player.url = path; _player.Prepare(); float timeout = Time.realtimeSinceStartup + 8f; while (IsPlaying && playId == _playId && !_player.isPrepared && Time.realtimeSinceStartup < timeout) { yield return null; } if (!IsPlaying || playId != _playId) { yield break; } if (!_player.isPrepared) { OneIn10000Plugin.Log.LogError((object)("Video failed to prepare: " + path)); Stop(); yield break; } EnsureTargets(); if (_player.audioTrackCount > 0) { _player.EnableAudioTrack((ushort)0, true); _player.SetTargetAudioSource((ushort)0, _audio); } _started = true; _lastFrameTime = Time.realtimeSinceStartup; _player.Play(); } internal void TickPlayback() { if (IsPlaying && _started) { if (_finished && _endFramePresented) { Stop(); } else if (!_finished && Time.realtimeSinceStartup - _lastFrameTime >= 8f) { OneIn10000Plugin.Log.LogError((object)"1 in 10000: video playback stalled."); Stop(); } } } internal void TickChroma() { if (IsPlaying && _framePending && !((Object)(object)_videoRt == (Object)null) && !((Object)(object)_keyed == (Object)null)) { _framePending = false; _chromaBuffer = ChromaKey.Apply(_videoRt, _keyed, _chromaBuffer); _image.texture = (Texture)(object)_keyed; ((Behaviour)_image).enabled = true; if (_finished) { _endFramePresented = true; } } } internal void Dispose() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown Stop(); if ((Object)(object)_player != (Object)null) { _player.frameReady -= new FrameReadyEventHandler(OnFrameReady); _player.loopPointReached -= new EventHandler(OnFinished); _player.errorReceived -= new ErrorEventHandler(OnError); } ReleaseTargets(); if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)_root); _root = null; } } private void EnsureTargets() { //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0124: 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_0132: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Expected O, but got Unknown //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Expected O, but got Unknown int num = (int)((_player.width != 0) ? _player.width : 640); int num2 = (int)((_player.height != 0) ? _player.height : 360); float num3 = Mathf.Min(1f, 640f / (float)Mathf.Max(num, num2)); int num4 = Mathf.Max(1, Mathf.RoundToInt((float)num * num3)); int num5 = Mathf.Max(1, Mathf.RoundToInt((float)num2 * num3)); float num6 = ((_player.pixelAspectRatioNumerator != 0 && _player.pixelAspectRatioDenominator != 0) ? ((float)_player.pixelAspectRatioNumerator / (float)_player.pixelAspectRatioDenominator) : 1f); _aspectFitter.aspectRatio = (float)num * num6 / (float)num2; if ((Object)(object)_videoRt != (Object)null && (((Texture)_videoRt).width != num4 || ((Texture)_videoRt).height != num5)) { ReleaseTargets(); } if ((Object)(object)_videoRt == (Object)null) { _videoRt = new RenderTexture(num4, num5, 0, (RenderTextureFormat)0) { name = "OneIn10000RT", wrapMode = (TextureWrapMode)1, filterMode = (FilterMode)1, antiAliasing = 1 }; _videoRt.Create(); _keyed = new Texture2D(num4, num5, (TextureFormat)4, false) { name = "OneIn10000Keyed", wrapMode = (TextureWrapMode)1, filterMode = (FilterMode)1 }; } _player.targetTexture = _videoRt; _image.texture = (Texture)(object)_keyed; } private void ReleaseTargets() { if ((Object)(object)_player != (Object)null) { _player.targetTexture = null; } if ((Object)(object)_videoRt != (Object)null) { _videoRt.Release(); Object.Destroy((Object)(object)_videoRt); _videoRt = null; } if ((Object)(object)_keyed != (Object)null) { Object.Destroy((Object)(object)_keyed); _keyed = null; } _chromaBuffer = null; } private void OnFrameReady(VideoPlayer _, long frame) { if (IsPlaying && _started) { _lastFrameTime = Time.realtimeSinceStartup; _framePending = true; } } private void OnFinished(VideoPlayer _) { if (IsPlaying && _started) { _finished = true; _framePending = true; } } private void OnError(VideoPlayer _, string message) { if (!_loggedPlayError) { _loggedPlayError = true; OneIn10000Plugin.Log.LogError((object)("1 in 10000 video error: " + message)); } Stop(); } private void Stop() { _playId++; IsPlaying = false; _started = false; _framePending = false; _finished = false; _endFramePresented = false; if ((Object)(object)_image != (Object)null) { ((Behaviour)_image).enabled = false; } if ((Object)(object)_player != (Object)null) { _player.Stop(); } if ((Object)(object)_audio != (Object)null) { _audio.Stop(); } } } [BepInPlugin("ModdedWolf.OneIn10000", "1 in 10000", "1.0.0")] public class OneIn10000Plugin : BaseUnityPlugin { public const string GUID = "ModdedWolf.OneIn10000"; public const string NAME = "1 in 10000"; public const string VERSION = "1.0.0"; internal const int ProcessWidth = 640; private const float RollIntervalSeconds = 1f; private const float PerPlayerCooldown = 2f; private const float SettingsSyncInterval = 3f; private const float HelloResendInterval = 3f; private const float HelloGraceSeconds = 20f; internal static OneIn10000Plugin Instance; internal static ManualLogSource Log; internal static ConfigEntry<float> ChancePercent; private JumpscareController _jumpscare; private float _nextRollTime; private float _nextSettingsSync; private float _nextHelloSend; private bool _loggedMissingVideo; private float _appliedChance = 0.01f; private readonly Dictionary<long, float> _cooldownUntil = new Dictionary<long, float>(); private readonly HashSet<long> _verifiedPeers = new HashSet<long>(); private readonly Dictionary<long, float> _peerFirstSeen = new Dictionary<long, float>(); internal const float PlaybackVolume = 1f; private void Awake() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; ChancePercent = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ChancePercent", 0.01f, new ConfigDescription("Host/server only. Percent chance each second, rolled separately for every player. Client values are ignored.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 100f), Array.Empty<object>())); _appliedChance = ChancePercent.Value; _jumpscare = new JumpscareController(); _nextRollTime = Time.unscaledTime + 5f; _nextSettingsSync = Time.unscaledTime + 2f; _nextHelloSend = 0f; ((BaseUnityPlugin)this).Logger.LogInfo((object)"1 in 10000 v1.0.0 loaded. Host/server owns ChancePercent. Volume is fixed. Matching client version is required."); } private void Update() { FoxyNet.TryRegister(RPC_Play, RPC_Settings, RPC_Hello); if (!FoxyNet.IsDedicated()) { _jumpscare.TickPlayback(); } if (!FoxyNet.IsWorldHost()) { TrySendHello(); } else if (FoxyNet.IsInPlayableWorld()) { EnforceClientVersions(); if (Time.unscaledTime >= _nextSettingsSync) { _nextSettingsSync = Time.unscaledTime + 3f; SyncSettingsToPeers(); } if (!(Time.unscaledTime < _nextRollTime)) { _nextRollTime = Time.unscaledTime + 1f; RollEveryPlayer(); } } } private void LateUpdate() { if (!FoxyNet.IsDedicated() && _jumpscare.IsPlaying) { _jumpscare.TickChroma(); } } private void OnDestroy() { FoxyNet.Unregister(); _jumpscare?.Dispose(); if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void TrySendHello() { if (!FoxyNet.IsRegistered() || (Object)(object)ZNet.instance == (Object)null || FoxyNet.IsWorldHost()) { return; } if (FoxyNet.IsInPlayableWorld()) { if (!float.IsPositiveInfinity(_nextHelloSend)) { FoxyNet.SendHello("1.0.0"); _nextHelloSend = float.PositiveInfinity; } return; } if (float.IsPositiveInfinity(_nextHelloSend)) { _nextHelloSend = 0f; } if (!(Time.unscaledTime < _nextHelloSend)) { _nextHelloSend = Time.unscaledTime + 3f; FoxyNet.SendHello("1.0.0"); } } private void EnforceClientVersions() { List<ZNetPeer> remotePeers = FoxyNet.GetRemotePeers(); HashSet<long> hashSet = new HashSet<long>(); for (int i = 0; i < remotePeers.Count; i++) { ZNetPeer val = remotePeers[i]; if (val == null || !IsPeerConnected(val)) { continue; } hashSet.Add(val.m_uid); if (!IsPeerReadyForHandshake(val)) { continue; } if (!_peerFirstSeen.ContainsKey(val.m_uid)) { _peerFirstSeen[val.m_uid] = Time.unscaledTime; } if (!_verifiedPeers.Contains(val.m_uid)) { float num = _peerFirstSeen[val.m_uid]; if (!(Time.unscaledTime - num < 20f)) { FoxyNet.KickPeer(val, string.Format("missing {0} v{1} handshake (no Hello within {2:0}s)", "1 in 10000", "1.0.0", 20f)); _peerFirstSeen.Remove(val.m_uid); } } } PrunePeerTracking(hashSet); } private static bool IsPeerReadyForHandshake(ZNetPeer peer) { if (!string.IsNullOrEmpty(peer.m_playerName)) { return true; } try { return peer.IsReady(); } catch { return false; } } private void PrunePeerTracking(HashSet<long> present) { List<long> list = null; foreach (long key in _peerFirstSeen.Keys) { if (!present.Contains(key)) { if (list == null) { list = new List<long>(); } list.Add(key); } } if (list != null) { for (int i = 0; i < list.Count; i++) { long num = list[i]; _peerFirstSeen.Remove(num); _verifiedPeers.Remove(num); _cooldownUntil.Remove(num); } } } private void SyncSettingsToPeers() { List<ZNetPeer> remotePeers = FoxyNet.GetRemotePeers(); for (int i = 0; i < remotePeers.Count; i++) { ZNetPeer val = remotePeers[i]; if (val != null && IsPeerConnected(val) && _verifiedPeers.Contains(val.m_uid)) { FoxyNet.SendSettings(val.m_uid, ChancePercent.Value); } } } private void RollEveryPlayer() { if (!FoxyNet.IsDedicated() && (Object)(object)Player.m_localPlayer != (Object)null) { long uID = ZNet.GetUID(); if (RolledHit(uID)) { Log.LogInfo((object)$"Jumpscare hit for host at {ChancePercent.Value}%."); PlayLocal(); } } List<ZNetPeer> remotePeers = FoxyNet.GetRemotePeers(); for (int i = 0; i < remotePeers.Count; i++) { ZNetPeer val = remotePeers[i]; if (val != null && IsPeerConnected(val) && _verifiedPeers.Contains(val.m_uid) && RolledHit(val.m_uid)) { Log.LogInfo((object)$"Jumpscare hit for peer {val.m_uid} at {ChancePercent.Value}%."); FoxyNet.SendPlay(val.m_uid); } } } private static bool IsPeerConnected(ZNetPeer peer) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (peer.m_uid == 0L) { return false; } try { if (!peer.IsReady()) { return peer.m_characterID != ZDOID.None; } } catch { } return true; } private bool RolledHit(long playerId) { if (_cooldownUntil.TryGetValue(playerId, out var value) && Time.unscaledTime < value) { return false; } if (Random.Range(0f, 100f) >= ChancePercent.Value) { return false; } _cooldownUntil[playerId] = Time.unscaledTime + 2f; return true; } private void RPC_Play(long sender) { if (!FoxyNet.IsTrustedSender(sender)) { Log.LogWarning((object)$"Ignored jumpscare RPC from untrusted sender {sender}."); return; } Log.LogInfo((object)"Received jumpscare from the server."); PlayLocal(); } private void RPC_Settings(long sender, float chancePercent) { if (!FoxyNet.IsWorldHost() && FoxyNet.IsTrustedSender(sender)) { chancePercent = Mathf.Clamp(chancePercent, 0.01f, 100f); if (!(Mathf.Abs(_appliedChance - chancePercent) < 0.0001f)) { _appliedChance = chancePercent; Log.LogInfo((object)$"Server jumpscare chance is {chancePercent}% per player each second."); } } } private void RPC_Hello(long sender, string version) { if (!FoxyNet.IsWorldHost()) { return; } if (string.IsNullOrEmpty(version)) { version = "(empty)"; } ZNetPeer val = FoxyNet.FindPeer(sender); if (val == null) { Log.LogWarning((object)$"Hello from unknown peer {sender} with version {version}."); return; } if (!_peerFirstSeen.ContainsKey(sender)) { _peerFirstSeen[sender] = Time.unscaledTime; } if (version != "1.0.0") { FoxyNet.KickPeer(val, "need 1 in 10000 v1.0.0, got " + version); _verifiedPeers.Remove(sender); _peerFirstSeen.Remove(sender); } else if (_verifiedPeers.Add(sender)) { Log.LogInfo((object)string.Format("Peer {0} verified with {1} v{2}.", sender, "1 in 10000", "1.0.0")); FoxyNet.SendSettings(sender, ChancePercent.Value); } } private void PlayLocal() { if (FoxyNet.IsDedicated() || _jumpscare.IsPlaying) { return; } if (!EmbeddedVideo.TryExtract(out var path, out var error)) { if (!_loggedMissingVideo) { Log.LogWarning((object)error); _loggedMissingVideo = true; } } else { _loggedMissingVideo = false; ((MonoBehaviour)this).StartCoroutine(_jumpscare.Play(path)); } } } }