using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("NetKit.Core")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+f5c3eb8170447e518d8135c1b536619a5acb5844")] [assembly: AssemblyProduct("NetKit.Core")] [assembly: AssemblyTitle("NetKit.Core")] [assembly: AssemblyMetadata("BuildStamp", "f5c3eb8 2026-07-24")] [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] internal sealed class IsReadOnlyAttribute : Attribute { } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace NetKit.Core { public static class BuildStampCompat { public const string Unknown = "unknown"; public static bool IsKnown(string stamp) { if (!string.IsNullOrEmpty(stamp)) { return !string.Equals(stamp, "unknown", StringComparison.OrdinalIgnoreCase); } return false; } public static bool ShouldWarn(string ours, string theirs) { if (IsKnown(ours) && IsKnown(theirs)) { return !string.Equals(ours, theirs, StringComparison.Ordinal); } return false; } } public static class ChannelCompat { public enum Kind { Compatible, ProtoMismatch, VersionMismatch, PeerMissingChannel } public static bool ProtoCompatible(int localProto, int remoteProto) { return localProto == remoteProto; } public static Kind Evaluate(int localProto, int remoteProto, string localVersion, string remoteVersion) { if (localProto != remoteProto) { return Kind.ProtoMismatch; } if (remoteVersion == null) { return Kind.PeerMissingChannel; } if (!string.Equals(localVersion, remoteVersion, StringComparison.Ordinal)) { return Kind.VersionMismatch; } return Kind.Compatible; } public static bool IsReady(Kind kind) { return kind == Kind.Compatible; } } public static class ExtensionChange { public static bool ShouldRaiseChanged(bool wasReady, bool hadPrevious, string previousExtension, string newExtension) { if (!wasReady) { return false; } if (!hadPrevious) { return false; } return !string.Equals(previousExtension ?? "", newExtension ?? "", StringComparison.Ordinal); } } public static class Heartbeat { public static string Line(string tag, bool isMaster, int peers, int ready, int tx, int rx, int drops, string fragment, double photonTime) { string text = string.Format("[{0}] hb role={1} peers={2} ready={3}/{4}", tag, isMaster ? "M" : "G", peers, ready, peers) + $" pt={photonTime:F1} tx={tx} rx={rx} drops={drops}"; if (!string.IsNullOrEmpty(fragment)) { text = text + " " + fragment; } return text; } } public static class HelloCodec { public struct HelloMsg { public int Proto; public List Channels; public string Stamp; } public struct ChannelHello { public string Channel; public string Version; public string Extension; } public const int Version = 1; public static string Encode(HelloMsg m) { List list = m.Channels ?? new List(); List list2 = new List(2 + list.Count * 3) { NetWire.I(m.Proto), NetWire.I(list.Count) }; foreach (ChannelHello item in list) { list2.Add(NetWire.Esc(item.Channel)); list2.Add(NetWire.Esc(item.Version)); list2.Add(NetWire.Esc(item.Extension)); } list2.Add(NetWire.Esc(m.Stamp ?? "")); return NetWire.Join(list2.ToArray()); } public static bool TryDecode(string payload, out HelloMsg m) { m = default(HelloMsg); m.Channels = new List(); m.Stamp = ""; List list = NetWire.Split(payload); if (list == null || list.Count < 2) { return false; } if (!NetWire.TryI(list[0], out m.Proto) || m.Proto <= 0) { return false; } if (!NetWire.TryI(list[1], out var v) || v < 0) { return false; } if (list.Count < 2 + v * 3) { return false; } for (int i = 0; i < v; i++) { int num = 2 + i * 3; string text = list[num]; if (string.IsNullOrEmpty(text)) { return false; } m.Channels.Add(new ChannelHello { Channel = text, Version = list[num + 1], Extension = list[num + 2] }); } int num2 = 2 + v * 3; if (list.Count > num2) { m.Stamp = list[num2]; } return true; } public static string? VersionOf(in HelloMsg m, string channel) { if (m.Channels == null) { return null; } foreach (ChannelHello channel2 in m.Channels) { if (string.Equals(channel2.Channel, channel, StringComparison.Ordinal)) { return channel2.Version; } } return null; } public static string? ExtensionOf(in HelloMsg m, string channel) { if (m.Channels == null) { return null; } foreach (ChannelHello channel2 in m.Channels) { if (string.Equals(channel2.Channel, channel, StringComparison.Ordinal)) { return channel2.Extension; } } return null; } } public sealed class NetCounters { private sealed class VerbTrace { public int Sends; public int Recvs; public int Drops; public double LastSendAt = -1.0; public double LastRecvAt = -1.0; public double LastDropAt = -1.0; public readonly Dictionary DropReasons = new Dictionary(); } private readonly Dictionary _trace = new Dictionary(); public bool Empty => _trace.Count == 0; public int TotalSends { get { int num = 0; foreach (VerbTrace value in _trace.Values) { num += value.Sends; } return num; } } public int TotalRecvs { get { int num = 0; foreach (VerbTrace value in _trace.Values) { num += value.Recvs; } return num; } } public int TotalDrops { get { int num = 0; foreach (VerbTrace value in _trace.Values) { num += value.Drops; } return num; } } private VerbTrace For(string verb) { verb = verb ?? "?"; if (!_trace.TryGetValue(verb, out VerbTrace value)) { value = (_trace[verb] = new VerbTrace()); } return value; } public void RecordSend(string verb, double now) { VerbTrace verbTrace = For(verb); verbTrace.Sends++; verbTrace.LastSendAt = now; } public void RecordRecv(string verb, double now) { VerbTrace verbTrace = For(verb); verbTrace.Recvs++; verbTrace.LastRecvAt = now; } public void RecordDrop(string verb, string reason, double now) { VerbTrace verbTrace = For(verb); verbTrace.Drops++; verbTrace.LastDropAt = now; reason = reason ?? "?"; verbTrace.DropReasons.TryGetValue(reason, out var value); verbTrace.DropReasons[reason] = value + 1; } public string Summary(string tag, double now) { if (_trace.Count == 0) { return "[" + tag + "] no traffic recorded."; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append($"[{tag}] traffic (t={now:F0}s):"); List list = new List(_trace.Keys); list.Sort(StringComparer.Ordinal); foreach (string item in list) { VerbTrace verbTrace = _trace[item]; string arg = ""; if (verbTrace.Drops > 0) { List list2 = new List(); foreach (KeyValuePair dropReason in verbTrace.DropReasons) { list2.Add($"{dropReason.Key}×{dropReason.Value}"); } list2.Sort(StringComparer.Ordinal); arg = string.Format(" drop={0} ({1}) lastDrop={2:F0}s", verbTrace.Drops, string.Join(", ", list2.ToArray()), verbTrace.LastDropAt); } stringBuilder.Append(string.Format("\n[{0}] {1}: send={2}{3}", tag, item, verbTrace.Sends, (verbTrace.Sends > 0) ? $" lastSend={verbTrace.LastSendAt:F0}s" : "") + string.Format(" recv={0}{1}{2}", verbTrace.Recvs, (verbTrace.Recvs > 0) ? $" lastRecv={verbTrace.LastRecvAt:F0}s" : "", arg)); } return stringBuilder.ToString(); } } internal static class NetWire { public static string I(int v) { return v.ToString(CultureInfo.InvariantCulture); } public static string F(float v) { return v.ToString("R", CultureInfo.InvariantCulture); } public static bool TryI(string s, out int v) { return int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out v); } public static bool TryF(string s, out float v) { return float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out v); } public static string Join(params string[] fields) { return string.Join(";", fields); } public static string Esc(string s) { if (string.IsNullOrEmpty(s)) { return ""; } StringBuilder stringBuilder = new StringBuilder(s.Length + 4); foreach (char c in s) { switch (c) { case '\\': stringBuilder.Append("\\\\"); break; case ';': stringBuilder.Append("\\s"); break; case '\n': stringBuilder.Append("\\n"); break; default: stringBuilder.Append(c); break; } } return stringBuilder.ToString(); } public static List? Split(string payload) { if (payload == null) { return null; } List list = new List(); StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < payload.Length; i++) { char c = payload[i]; switch (c) { case '\\': if (i + 1 >= payload.Length) { return null; } switch (payload[++i]) { case '\\': stringBuilder.Append('\\'); break; case 's': stringBuilder.Append(';'); break; case 'n': stringBuilder.Append('\n'); break; default: return null; } break; case ';': list.Add(stringBuilder.ToString()); stringBuilder.Length = 0; break; default: stringBuilder.Append(c); break; } } list.Add(stringBuilder.ToString()); return list; } } public sealed class NoHandlerDrops { public readonly struct Entry { public string Channel { get; } public string Verb { get; } public int Count { get; } public Entry(string channel, string verb, int count) { Channel = channel; Verb = verb; Count = count; } } private readonly Dictionary> _byChannel = new Dictionary>(StringComparer.Ordinal); public bool Empty { get { foreach (Dictionary value in _byChannel.Values) { if (value.Count > 0) { return false; } } return true; } } public bool Record(string channel, string verb) { channel = channel ?? "?"; verb = verb ?? "?"; if (!_byChannel.TryGetValue(channel, out Dictionary value)) { value = (_byChannel[channel] = new Dictionary(StringComparer.Ordinal)); } bool result = !value.ContainsKey(verb); value.TryGetValue(verb, out var value2); value[verb] = value2 + 1; return result; } public int Count(string channel, string verb) { if (channel != null && verb != null && _byChannel.TryGetValue(channel, out Dictionary value) && value.TryGetValue(verb, out var value2)) { return value2; } return 0; } public IEnumerable NonZero() { List list = new List(_byChannel.Keys); list.Sort(StringComparer.Ordinal); foreach (string c in list) { List list2 = new List(_byChannel[c].Keys); list2.Sort(StringComparer.Ordinal); foreach (string item in list2) { yield return new Entry(c, item, _byChannel[c][item]); } } } public string Summary(string tag) { List list = new List(); foreach (Entry item in NonZero()) { list.Add($"{item.Channel}.{item.Verb}×{item.Count}"); } if (list.Count != 0) { return "[" + tag + "] droppedVerbs: " + string.Join(", ", list.ToArray()); } return "[" + tag + "] droppedVerbs: none"; } } public sealed class PeerLedger { private readonly Dictionary _expectedSince = new Dictionary(); private readonly HashSet _helloed = new HashSet(); public int PendingCount => _expectedSince.Count; public int HelloedCount => _helloed.Count; public IReadOnlyDictionary Pending => _expectedSince; public bool HasHello(int actor) { return _helloed.Contains(actor); } public bool Expect(int actor, double now) { if (_helloed.Contains(actor)) { return false; } if (_expectedSince.ContainsKey(actor)) { return false; } _expectedSince[actor] = now; return true; } public void MarkHello(int actor) { _expectedSince.Remove(actor); _helloed.Add(actor); } public List? DueForWarning(double now, double warnSeconds) { List list = null; if (_expectedSince.Count == 0) { return null; } foreach (KeyValuePair item in _expectedSince) { if (now - item.Value > warnSeconds) { (list ?? (list = new List())).Add(item.Key); } } if (list != null) { foreach (int item2 in list) { _expectedSince.Remove(item2); } } return list; } public double GraceElapsed(int actor, double now) { if (!_expectedSince.TryGetValue(actor, out var value)) { return -1.0; } return now - value; } public void Reset() { _expectedSince.Clear(); _helloed.Clear(); } } public static class PunLog { public static readonly string[] Signatures = new string[3] { "Received OnSerialization for view ID", "has no method", "PhotonView ID duplicate found" }; public static int Match(string condition) { if (string.IsNullOrEmpty(condition)) { return -1; } for (int i = 0; i < Signatures.Length; i++) { if (condition.IndexOf(Signatures[i], StringComparison.Ordinal) >= 0) { return i; } } return -1; } public static bool TryParseViewId(string condition, out int id) { id = 0; if (string.IsNullOrEmpty(condition)) { return false; } int num = condition.IndexOf(Signatures[0], StringComparison.Ordinal); if (num < 0) { return false; } int i; for (i = num + Signatures[0].Length; i < condition.Length && !char.IsDigit(condition[i]); i++) { } int j; for (j = i; j < condition.Length && char.IsDigit(condition[j]); j++) { } if (j <= i) { return false; } return int.TryParse(condition.Substring(i, j - i), out id); } } public sealed class PunSignatureCounters { private readonly int[] _counts = new int[PunLog.Signatures.Length]; private readonly double[] _firstAt; private readonly double[] _lastAt; public int UnknownViewCount => _counts[0]; public PunSignatureCounters() { _firstAt = new double[PunLog.Signatures.Length]; _lastAt = new double[PunLog.Signatures.Length]; for (int i = 0; i < _firstAt.Length; i++) { _firstAt[i] = -1.0; _lastAt[i] = -1.0; } } public void Record(int signatureIndex, double now) { if (signatureIndex >= 0 && signatureIndex < _counts.Length) { _counts[signatureIndex]++; if (_firstAt[signatureIndex] < 0.0) { _firstAt[signatureIndex] = now; } _lastAt[signatureIndex] = now; } } public int Count(int signatureIndex) { if (signatureIndex < 0 || signatureIndex >= _counts.Length) { return 0; } return _counts[signatureIndex]; } public string Summary(string tag) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < PunLog.Signatures.Length; i++) { if (_counts[i] > 0) { stringBuilder.Append($"\n[{tag}] PUN-signature '{PunLog.Signatures[i]}': {_counts[i]}× " + $"(first {_firstAt[i]:F0}s, last {_lastAt[i]:F0}s)"); } } if (stringBuilder.Length != 0) { return stringBuilder.ToString(1, stringBuilder.Length - 1); } return ""; } } public sealed class UnknownViewTable { private sealed class Row { public int Count; public double FirstAt; public double LastAt; } private readonly Dictionary _rows = new Dictionary(); private readonly int _cap; public int IdCount => _rows.Count; public UnknownViewTable(int cap = 64) { _cap = ((cap < 1) ? 1 : cap); } public bool Record(int id, double now) { if (_rows.TryGetValue(id, out Row value)) { value.Count++; value.LastAt = now; return false; } if (_rows.Count >= _cap) { return false; } _rows[id] = new Row { Count = 1, FirstAt = now, LastAt = now }; return true; } public string Format(string tag) { if (_rows.Count == 0) { return "[" + tag + "] unknown-view table: empty."; } StringBuilder stringBuilder = new StringBuilder($"[{tag}] unknown-view table ({_rows.Count} id(s)):"); foreach (KeyValuePair row in _rows) { stringBuilder.Append($"\n[{tag}] id={row.Key}: {row.Value.Count}× (first {row.Value.FirstAt:F0}s, last {row.Value.LastAt:F0}s)"); } return stringBuilder.ToString(); } } public static class TimeoutConfig { public const int Vanilla = 10000; public static int Resolve(int configured, out bool negativeWasInvalid) { negativeWasInvalid = configured < 0; if (configured <= 0) { return 0; } return configured; } public static bool Armed(int configured) { bool negativeWasInvalid; return Resolve(configured, out negativeWasInvalid) > 0; } } public sealed class TraceRing { public struct Entry { public double T; public string Line; } private readonly Entry[] _ring; private int _next; public int Capacity => _ring.Length; public TraceRing(int capacity = 32) { if (capacity < 1) { capacity = 1; } _ring = new Entry[capacity]; } public void Add(double now, string line) { _ring[_next] = new Entry { T = now, Line = line }; _next = (_next + 1) % _ring.Length; } public IEnumerable Ordered() { for (int i = 0; i < _ring.Length; i++) { Entry entry = _ring[(_next + i) % _ring.Length]; if (entry.Line != null) { yield return entry; } } } } }