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 Ravengates v1.3.0
plugins/Ravengates.Core.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using Microsoft.CodeAnalysis; using Ravengates.Core; using Ravengates.Mathematics; using Ravengates.Physics; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Ravengates.Core")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.3.0.0")] [assembly: AssemblyInformationalVersion("1.3.0")] [assembly: AssemblyProduct("Ravengates.Core")] [assembly: AssemblyTitle("Ravengates.Core")] [assembly: AssemblyVersion("1.3.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 Ravengates.Streaming { public enum RemoteInterestTier { RenderOnly, Interactive, CrossingReady } [Flags] public enum PortalRemoteSimulation { None = 0, ExistingCharacters = 1, ExistingRigidbodies = 2, Physics = 4, Projectiles = 8, AI = 0x10, Spawners = 0x20, Environment = 0x40, Full = 0x7F } public readonly struct ZoneCoordinate : IEquatable<ZoneCoordinate> { public int X { get; } public int Y { get; } public ZoneCoordinate(int x, int y) { X = x; Y = y; } public static ZoneCoordinate FromWorld(Vector3 position, float zoneSize = 64f) { if (zoneSize <= 0f) { throw new ArgumentOutOfRangeException("zoneSize"); } float num = zoneSize * 0.5f; return new ZoneCoordinate((int)Math.Floor((position.X + num) / zoneSize), (int)Math.Floor((position.Z + num) / zoneSize)); } public bool Equals(ZoneCoordinate other) { if (X == other.X) { return Y == other.Y; } return false; } public override bool Equals(object? obj) { if (obj is ZoneCoordinate other) { return Equals(other); } return false; } public override int GetHashCode() { return (X * 397) ^ Y; } public override string ToString() { return $"{X},{Y}"; } } public readonly struct RemoteInterestRequest { public string OwnerKey { get; } public string SourcePortalId { get; } public string DestinationPortalId { get; } public Vector3 DestinationPosition { get; } public int Radius { get; } public RemoteInterestTier Tier { get; } public PortalRemoteSimulation Simulation { get; } public RemoteInterestRequest(string ownerKey, string sourcePortalId, string destinationPortalId, Vector3 destinationPosition, int radius, RemoteInterestTier tier, PortalRemoteSimulation simulation) { OwnerKey = ownerKey ?? throw new ArgumentNullException("ownerKey"); SourcePortalId = sourcePortalId ?? throw new ArgumentNullException("sourcePortalId"); DestinationPortalId = destinationPortalId ?? throw new ArgumentNullException("destinationPortalId"); DestinationPosition = destinationPosition; Radius = Math.Max(0, radius); Tier = tier; Simulation = simulation; } } public sealed class RemoteZoneInterest { public ZoneCoordinate Zone { get; } public int ReferenceCount { get; internal set; } public RemoteInterestTier Tier { get; internal set; } public PortalRemoteSimulation Simulation { get; internal set; } public double UnloadAt { get; internal set; } public bool IsGraceUnloading { get { if (ReferenceCount == 0) { return !double.IsPositiveInfinity(UnloadAt); } return false; } } internal RemoteZoneInterest(ZoneCoordinate zone) { Zone = zone; UnloadAt = double.PositiveInfinity; } } public sealed class PortalInterestManager { private readonly Dictionary<ZoneCoordinate, RemoteZoneInterest> _zones = new Dictionary<ZoneCoordinate, RemoteZoneInterest>(); private readonly Dictionary<string, HashSet<ZoneCoordinate>> _owners = new Dictionary<string, HashSet<ZoneCoordinate>>(StringComparer.Ordinal); private readonly Stack<HashSet<ZoneCoordinate>> _freeSets = new Stack<HashSet<ZoneCoordinate>>(); private readonly HashSet<ZoneCoordinate> _requested = new HashSet<ZoneCoordinate>(); private readonly List<ZoneCoordinate> _expired = new List<ZoneCoordinate>(); public int MaxRemoteZones { get; private set; } public double UnloadGraceSeconds { get; private set; } public float ZoneSize { get; } public IEnumerable<RemoteZoneInterest> ActiveZones => _zones.Values; public PortalInterestManager(int maxRemoteZones = 49, double unloadGraceSeconds = 10.0, float zoneSize = 64f) { if (maxRemoteZones < 1) { throw new ArgumentOutOfRangeException("maxRemoteZones"); } if (unloadGraceSeconds < 0.0) { throw new ArgumentOutOfRangeException("unloadGraceSeconds"); } if (zoneSize <= 0f) { throw new ArgumentOutOfRangeException("zoneSize"); } MaxRemoteZones = maxRemoteZones; UnloadGraceSeconds = unloadGraceSeconds; ZoneSize = zoneSize; } public void Configure(int maxRemoteZones, double unloadGraceSeconds) { if (maxRemoteZones < 1) { throw new ArgumentOutOfRangeException("maxRemoteZones"); } if (double.IsNaN(unloadGraceSeconds) || double.IsInfinity(unloadGraceSeconds) || unloadGraceSeconds < 0.0) { throw new ArgumentOutOfRangeException("unloadGraceSeconds"); } MaxRemoteZones = maxRemoteZones; UnloadGraceSeconds = unloadGraceSeconds; } public void Clear() { _owners.Clear(); _zones.Clear(); } public bool TryAcquire(RemoteInterestRequest request, double now) { HashSet<ZoneCoordinate> hashSet = CalculateZones(request, _requested); int num = hashSet.Count; if (_owners.TryGetValue(request.OwnerKey, out HashSet<ZoneCoordinate> value)) { foreach (ZoneCoordinate item in value) { if (hashSet.Contains(item)) { num--; } } } if (CountNonGraceZones() + Math.Max(0, num) > MaxRemoteZones) { return false; } Release(request.OwnerKey, now); HashSet<ZoneCoordinate> hashSet2 = ((_freeSets.Count > 0) ? _freeSets.Pop() : new HashSet<ZoneCoordinate>()); foreach (ZoneCoordinate item2 in hashSet) { if (!_zones.TryGetValue(item2, out RemoteZoneInterest value2)) { value2 = new RemoteZoneInterest(item2); _zones.Add(item2, value2); } bool flag = value2.ReferenceCount == 0; value2.ReferenceCount++; value2.Tier = (flag ? request.Tier : ((RemoteInterestTier)Math.Max((int)value2.Tier, (int)request.Tier))); value2.Simulation = (flag ? request.Simulation : (value2.Simulation | request.Simulation)); value2.UnloadAt = double.PositiveInfinity; hashSet2.Add(item2); } _owners[request.OwnerKey] = hashSet2; return true; } public void Release(string ownerKey, double now) { if (!_owners.TryGetValue(ownerKey, out HashSet<ZoneCoordinate> value)) { return; } foreach (ZoneCoordinate item in value) { if (_zones.TryGetValue(item, out RemoteZoneInterest value2)) { value2.ReferenceCount = Math.Max(0, value2.ReferenceCount - 1); if (value2.ReferenceCount == 0) { value2.UnloadAt = now + UnloadGraceSeconds; } } } _owners.Remove(ownerKey); value.Clear(); _freeSets.Push(value); } public int Tick(double now) { int num = 0; List<ZoneCoordinate> expired = _expired; expired.Clear(); foreach (KeyValuePair<ZoneCoordinate, RemoteZoneInterest> zone in _zones) { if (zone.Value.ReferenceCount == 0 && zone.Value.UnloadAt <= now) { expired.Add(zone.Key); } } foreach (ZoneCoordinate item in expired) { _zones.Remove(item); num++; } return num; } public bool TryGet(ZoneCoordinate zone, out RemoteZoneInterest interest) { return _zones.TryGetValue(zone, out interest); } private HashSet<ZoneCoordinate> CalculateZones(RemoteInterestRequest request, HashSet<ZoneCoordinate> zones) { ZoneCoordinate zoneCoordinate = ZoneCoordinate.FromWorld(request.DestinationPosition, ZoneSize); zones.Clear(); for (int i = zoneCoordinate.X - request.Radius; i <= zoneCoordinate.X + request.Radius; i++) { for (int j = zoneCoordinate.Y - request.Radius; j <= zoneCoordinate.Y + request.Radius; j++) { zones.Add(new ZoneCoordinate(i, j)); } } return zones; } private int CountNonGraceZones() { int num = 0; foreach (RemoteZoneInterest value in _zones.Values) { if (value.ReferenceCount > 0) { num++; } } return num; } } } namespace Ravengates.Rendering { public sealed class PortalRenderBudget { public int MaxPassesPerFrame { get; } public int MaxRecursionDepth { get; } public float MinPortalScreenPixels { get; } public int PassesUsed { get; private set; } public PortalRenderBudget(int maxPassesPerFrame = 6, int maxRecursionDepth = 2, float minPortalScreenPixels = 64f) { if (maxPassesPerFrame < 0) { throw new ArgumentOutOfRangeException("maxPassesPerFrame"); } if (maxRecursionDepth < 0) { throw new ArgumentOutOfRangeException("maxRecursionDepth"); } if (minPortalScreenPixels < 0f) { throw new ArgumentOutOfRangeException("minPortalScreenPixels"); } MaxPassesPerFrame = maxPassesPerFrame; MaxRecursionDepth = maxRecursionDepth; MinPortalScreenPixels = minPortalScreenPixels; } public void BeginFrame() { PassesUsed = 0; } public bool TryAcquire(float projectedPixels, int requestedDepth, out int depth) { depth = 0; if (projectedPixels < MinPortalScreenPixels || PassesUsed >= MaxPassesPerFrame) { return false; } depth = Math.Max(0, Math.Min(MaxRecursionDepth, requestedDepth)); PassesUsed++; return true; } } public readonly struct PortalRenderCandidate { public Portal Portal { get; } public float ProjectedPixels { get; } public int RequestedDepth { get; } public float Priority { get; } public PortalRenderCandidate(Portal portal, float projectedPixels, int requestedDepth, float priority) { Portal = portal; ProjectedPixels = projectedPixels; RequestedDepth = requestedDepth; Priority = priority; } } public readonly struct PortalRenderPass { public Portal Portal { get; } public int RecursionDepth { get; } public float ResolutionScale { get; } public PortalRenderPass(Portal portal, int recursionDepth, float resolutionScale) { Portal = portal; RecursionDepth = recursionDepth; ResolutionScale = resolutionScale; } } public sealed class PortalRenderManager { private readonly PortalRenderBudget _budget; public PortalRenderManager(PortalRenderBudget budget) { _budget = budget ?? throw new ArgumentNullException("budget"); } public IReadOnlyList<PortalRenderPass> BuildPlan(IEnumerable<PortalRenderCandidate> candidates) { List<PortalRenderCandidate> list = new List<PortalRenderCandidate>(candidates); list.Sort((PortalRenderCandidate a, PortalRenderCandidate b) => b.Priority.CompareTo(a.Priority)); List<PortalRenderPass> list2 = new List<PortalRenderPass>(); _budget.BeginFrame(); foreach (PortalRenderCandidate item in list) { if (_budget.TryAcquire(item.ProjectedPixels, item.RequestedDepth, out var depth)) { float resolutionScale = ((depth == 0) ? 1f : Math.Max(0.35f, 1f - (float)depth * 0.2f)); list2.Add(new PortalRenderPass(item.Portal, depth, resolutionScale)); } } return list2; } } public sealed class PortalViewHistory { private readonly Dictionary<string, string> _signatures = new Dictionary<string, string>(StringComparer.Ordinal); public bool BeginView(string viewKey, PortalPath path) { if (!_signatures.TryGetValue(viewKey, out string value) || value != path.Signature) { _signatures[viewKey] = path.Signature; return true; } return false; } public void Invalidate(string viewKey) { _signatures.Remove(viewKey); } public void Clear() { _signatures.Clear(); } } public enum PortalViewTier { High, Medium, Low, Minimal } public readonly struct PortalViewSchedule { public PortalViewTier Tier { get; } public float ResolutionScale { get; } public int FrameInterval { get; } public PortalViewSchedule(PortalViewTier tier, float resolutionScale, int frameInterval) { Tier = tier; ResolutionScale = resolutionScale; FrameInterval = Math.Max(1, frameInterval); } } public static class PortalViewScheduler { public const float HighCoverage = 0.35f; public const float MediumCoverage = 0.12f; public const float EveryFrameMediumCoverage = 0.2f; public const int LowTierInterval = 4; public const int MinimalTierInterval = 8; public static PortalViewSchedule Select(float screenCoverage, bool nearCamera, bool adaptive, float baseScale, bool belowMinimumSize = false) { baseScale = ((float.IsNaN(baseScale) || float.IsInfinity(baseScale)) ? 1f : Math.Max(0.05f, Math.Min(1f, baseScale))); if (belowMinimumSize && !nearCamera) { return new PortalViewSchedule(PortalViewTier.Minimal, baseScale, 8); } if (!adaptive || nearCamera || screenCoverage >= 0.35f) { return new PortalViewSchedule(PortalViewTier.High, baseScale, 1); } if (screenCoverage >= 0.12f) { return new PortalViewSchedule(PortalViewTier.Medium, baseScale, (screenCoverage >= 0.2f) ? 1 : 2); } return new PortalViewSchedule(PortalViewTier.Low, baseScale, 4); } public static void RaiseRatesWithinBudget(PortalViewSchedule[] schedules, int count, int rendersPerFrame) { if (schedules == null) { throw new ArgumentNullException("schedules"); } count = Math.Min(count, schedules.Length); float num = 0f; for (int i = 0; i < count; i++) { num += 1f / (float)schedules[i].FrameInterval; } float num2 = (float)Math.Max(1, rendersPerFrame) + 0.0001f; for (int j = 0; j < count; j++) { PortalViewSchedule portalViewSchedule = schedules[j]; if (portalViewSchedule.FrameInterval != 1) { float num3 = num - 1f / (float)portalViewSchedule.FrameInterval + 1f; if (!(num3 > num2)) { schedules[j] = new PortalViewSchedule(portalViewSchedule.Tier, portalViewSchedule.ResolutionScale, 1); num = num3; } } } } public static bool IsDue(int frame, int lastRenderedFrame, int frameInterval) { if (lastRenderedFrame >= 0 && frame - lastRenderedFrame < Math.Max(1, frameInterval)) { return frame < lastRenderedFrame; } return true; } public static int QuantizeTextureSize(float pixels, int quantum = 32, int minimum = 32, int maximum = 4096) { if (quantum <= 0) { throw new ArgumentOutOfRangeException("quantum"); } if (float.IsNaN(pixels) || pixels <= 0f) { return minimum; } int val = (int)Math.Ceiling(Math.Min(pixels, maximum) / (float)quantum) * quantum; return Math.Max(minimum, Math.Min(maximum, val)); } } } namespace Ravengates.Physics { public readonly struct PortalHearingSettings { public float Multiplier { get; } public float MaxRange { get; } public float MetresLostPer100 { get; } public float MinimumRange { get; } public bool FollowsDirection { get; } public PortalHearingSettings(float multiplier, float maxRange, float metresLostPer100, float minimumRange = 0.5f, bool followsDirection = true) { Multiplier = multiplier; MaxRange = maxRange; MetresLostPer100 = metresLostPer100; MinimumRange = minimumRange; FollowsDirection = followsDirection; } } public static class PortalAcoustics { public static float RangeThrough(Portal entrance, Vector3 origin, float range, in PortalHearingSettings settings) { Portal pair = entrance.Pair; if (pair == null || range <= 0f || (settings.FollowsDirection && !entrance.AllowsTraversalToPair)) { return 0f; } float linkLength = (pair.Pose.Position - entrance.Pose.Position).Length(); return RangeThrough(range, (origin - entrance.Pose.Position).Length(), linkLength, in settings); } public static float RangeThrough(float range, float toEntrance, float linkLength, in PortalHearingSettings settings) { float num = range - toEntrance; if (num <= 0f) { return 0f; } num *= Math.Max(0f, settings.Multiplier); num -= Math.Max(0f, settings.MetresLostPer100) * linkLength / 100f; num = Math.Min(num, settings.MaxRange); if (!(num >= settings.MinimumRange)) { return 0f; } return num; } public static bool Hears(float toExit, float hearRange, float rangeThrough, in PortalHearingSettings settings) { if (rangeThrough > 0f && toExit <= Math.Min(hearRange, settings.MaxRange)) { return toExit < rangeThrough; } return false; } } public readonly struct PortalCrossing { public Portal Portal { get; } public PortalHit Hit { get; } public Vector3 TravelDirection { get; } public float Fraction => Hit.Fraction; public int SourceSide => Hit.SourceSide; public PortalCrossing(Portal portal, PortalHit hit, Vector3 travelDirection) { Portal = portal; Hit = hit; TravelDirection = travelDirection; } } public static class PortalCrossingSolver { public static bool TryFindCrossing(Portal portal, Vector3 previousPosition, Vector3 currentPosition, out PortalCrossing crossing) { if (portal.IsTraversable && portal.SegmentIntersects(previousPosition, currentPosition, out var hit)) { crossing = new PortalCrossing(portal, hit, currentPosition - previousPosition); return true; } crossing = default(PortalCrossing); return false; } public static PortalTravellerState ApplyCrossing(PortalTravellerState stateAtCrossing, PortalCrossing crossing, PortalTransform transform, float remainingSeconds, float planeEpsilon) { if (remainingSeconds < 0f) { throw new ArgumentOutOfRangeException("remainingSeconds"); } if (planeEpsilon < 0f) { throw new ArgumentOutOfRangeException("planeEpsilon"); } PortalTravellerState result = transform.TransformState(stateAtCrossing); Vector3 value = transform.TransformDirection(crossing.TravelDirection); if (value.LengthSquared() > 1E-07f) { value = Vector3.Normalize(value); result.Position += value * planeEpsilon; } result.Position += result.Velocity * remainingSeconds; return result; } public static PortalTravellerState StateAtCrossing(PortalTravellerState previous, PortalTravellerState current, PortalCrossing crossing) { float amount = Math.Max(0f, Math.Min(1f, crossing.Fraction)); return new PortalTravellerState(Vector3.Lerp(previous.Position, current.Position, amount), Quaternion.Slerp(previous.Rotation, current.Rotation, amount), Vector3.Lerp(previous.Velocity, current.Velocity, amount), Vector3.Lerp(previous.AngularVelocity, current.AngularVelocity, amount)); } } public interface IPortalTraveller { string TravellerId { get; } PortalBounds GetPortalBounds(); PortalTravellerState GetState(); void OnPortalEnter(Portal portal); void OnPortalStraddle(Portal portal, float fraction); void OnPortalCross(Portal source, Portal destination, PortalTravellerState transformedState); void OnPortalExit(Portal portal); } public sealed class PortalTravellerRegistry { private readonly Dictionary<string, IPortalTraveller> _travellers = new Dictionary<string, IPortalTraveller>(StringComparer.Ordinal); public bool Register(IPortalTraveller traveller) { if (_travellers.ContainsKey(traveller.TravellerId)) { return false; } _travellers.Add(traveller.TravellerId, traveller); return true; } public bool Unregister(string travellerId) { return _travellers.Remove(travellerId); } public bool TryGet(string travellerId, out IPortalTraveller traveller) { return _travellers.TryGetValue(travellerId, out traveller); } } public enum PortalRaycastTermination { Hit, NoHit, MaximumPortalTraversals, InvalidPortal } public readonly struct PortalRayHit { public Vector3 Point { get; } public Vector3 Normal { get; } public float Distance { get; } public string ColliderId { get; } public PortalRayHit(Vector3 point, Vector3 normal, float distance, string colliderId = "") { Point = point; Normal = normal; Distance = distance; ColliderId = colliderId ?? string.Empty; } } public interface IPortalRaycastWorld { IEnumerable<Portal> Portals { get; } bool TryRaycast(PortalRay ray, float maxDistance, out PortalRayHit hit); } public sealed class PortalRaycastResult { public bool Hit { get; internal set; } public PortalRayHit SurfaceHit { get; internal set; } public PortalPath Path { get; internal set; } = new PortalPath(); public PortalRaycastTermination Termination { get; internal set; } } public static class PortalRaycast { public static PortalRaycastResult Cast(IPortalRaycastWorld world, PortalRay ray, float maxDistance, int maxPortalTraversals = 8, float planeEpsilon = 0.02f) { if (maxDistance < 0f) { throw new ArgumentOutOfRangeException("maxDistance"); } if (maxPortalTraversals < 0) { throw new ArgumentOutOfRangeException("maxPortalTraversals"); } PortalRaycastResult portalRaycastResult = new PortalRaycastResult { Path = new PortalPath(Math.Max(1, maxPortalTraversals)) }; PortalRay ray2 = ray; float num = maxDistance; float num2 = 0f; for (int i = 0; i <= maxPortalTraversals; i++) { Portal nearestPortal; PortalHit nearestHit; float num3 = FindNearestPortalDistance(world.Portals, ray2, num, out nearestPortal, out nearestHit); if (world.TryRaycast(ray2, num, out var hit)) { if (nearestPortal == null || hit.Distance <= num3) { portalRaycastResult.Hit = true; portalRaycastResult.SurfaceHit = new PortalRayHit(hit.Point, portalRaycastResult.Path.TransformDirection(hit.Normal), num2 + hit.Distance, hit.ColliderId); portalRaycastResult.Termination = PortalRaycastTermination.Hit; portalRaycastResult.Path.AddLogicalDistance(hit.Distance); return portalRaycastResult; } } else if (nearestPortal == null) { portalRaycastResult.Termination = PortalRaycastTermination.NoHit; return portalRaycastResult; } if (nearestPortal == null || !nearestPortal.IsTraversable || nearestPortal.Pair == null) { portalRaycastResult.Termination = PortalRaycastTermination.InvalidPortal; return portalRaycastResult; } if (i == maxPortalTraversals) { portalRaycastResult.Termination = PortalRaycastTermination.MaximumPortalTraversals; return portalRaycastResult; } float num4 = nearestHit.Fraction * num; if (!portalRaycastResult.Path.TryAppend(nearestPortal, nearestPortal.Pair, num4)) { portalRaycastResult.Termination = PortalRaycastTermination.InvalidPortal; return portalRaycastResult; } PortalTransform transformToPair = nearestPortal.GetTransformToPair(); Vector3 vector = transformToPair.TransformPoint(nearestHit.Point); Vector3 vector2 = Vector3.Normalize(transformToPair.TransformDirection(ray2.Direction)); ray2 = new PortalRay(vector + vector2 * planeEpsilon, vector2); num -= num4; num -= planeEpsilon; num2 += num4; if (num <= 0f) { portalRaycastResult.Termination = PortalRaycastTermination.NoHit; return portalRaycastResult; } } portalRaycastResult.Termination = PortalRaycastTermination.MaximumPortalTraversals; return portalRaycastResult; } private static float FindNearestPortalDistance(IEnumerable<Portal> portals, PortalRay ray, float maxDistance, out Portal? nearestPortal, out PortalHit nearestHit) { nearestPortal = null; nearestHit = default(PortalHit); float num = float.PositiveInfinity; Vector3 point = ray.GetPoint(maxDistance); foreach (Portal portal in portals) { if (portal.IsTraversable && portal.SegmentIntersects(ray.Origin, point, out var hit)) { float num2 = hit.Fraction * maxDistance; if (num2 < num) { num = num2; nearestPortal = portal; nearestHit = hit; } } } return num; } } public struct PortalTraversalGuard { public string? PortalId { get; private set; } public int ExitSide { get; private set; } public bool IsActive => PortalId != null; public void Arm(Portal destination, Vector3 referencePoint) { if (destination == null) { throw new ArgumentNullException("destination"); } float z = destination.Pose.ToLocalPoint(referencePoint).Z; PortalId = destination.Id; ExitSide = ((z >= 0f) ? 1 : (-1)); } public void Refresh(Portal? guardedPortal, Vector3 referencePoint, float clearance) { if (PortalId != null) { if (guardedPortal == null || !string.Equals(guardedPortal.Id, PortalId, StringComparison.Ordinal)) { Clear(); } else if (guardedPortal.Pose.ToLocalPoint(referencePoint).Z * (float)ExitSide >= clearance) { Clear(); } } } public bool ShouldDefer(PortalCrossing crossing, Vector3 currentPoint, float clearance) { if (PortalId == null || crossing.Portal == null) { return false; } if (!string.Equals(crossing.Portal.Id, PortalId, StringComparison.Ordinal)) { return false; } if (crossing.SourceSide != ExitSide) { return false; } return Math.Abs(crossing.Portal.Pose.ToLocalPoint(currentPoint).Z) < clearance; } public void Clear() { PortalId = null; ExitSide = 0; } } public static class PortalTraversal { public static int ExitSide(PortalCrossing crossing) { if (crossing.SourceSide < 0) { return -1; } return 1; } public static Vector3 ExitCorrection(Portal destination, Vector3 mappedReferencePoint, int exitSide, float epsilon) { if (destination == null) { throw new ArgumentNullException("destination"); } float num = ((exitSide >= 0) ? 1f : (-1f)); float num2 = destination.Pose.ToLocalPoint(mappedReferencePoint).Z * num; if (num2 >= epsilon) { return Vector3.Zero; } return destination.Pose.ToWorldDirection(Vector3.UnitZ) * (num * (epsilon - num2)); } } } namespace Ravengates.Networking { public readonly struct PortalTraversalRequest { public string TravellerId { get; } public string SourcePortalId { get; } public string DestinationPortalId { get; } public int ConnectionRevision { get; } public Vector3 ClientPosition { get; } public Vector3 ClientVelocity { get; } public uint Sequence { get; } public PortalTraversalRequest(string travellerId, string sourcePortalId, string destinationPortalId, int connectionRevision, Vector3 clientPosition, Vector3 clientVelocity, uint sequence) { TravellerId = travellerId ?? throw new ArgumentNullException("travellerId"); SourcePortalId = sourcePortalId ?? throw new ArgumentNullException("sourcePortalId"); DestinationPortalId = destinationPortalId ?? throw new ArgumentNullException("destinationPortalId"); ConnectionRevision = connectionRevision; ClientPosition = clientPosition; ClientVelocity = clientVelocity; Sequence = sequence; } } public readonly struct PortalTraversalTicket { public string TravellerId { get; } public Portal Source { get; } public Portal Destination { get; } public PortalTransform Transform { get; } public PortalCrossing Crossing { get; } public PortalTraversalTicket(string travellerId, Portal source, Portal destination, PortalTransform transform, PortalCrossing crossing) { TravellerId = travellerId; Source = source; Destination = destination; Transform = transform; Crossing = crossing; } } public sealed class PortalAuthority { private readonly PortalManager _portals; public float MaxTravellerSpeed { get; } public PortalAuthority(PortalManager portals, float maxTravellerSpeed = 250f) { _portals = portals ?? throw new ArgumentNullException("portals"); if (maxTravellerSpeed <= 0f) { throw new ArgumentOutOfRangeException("maxTravellerSpeed"); } MaxTravellerSpeed = maxTravellerSpeed; } public bool TryValidate(PortalTraversalRequest request, Vector3 serverPreviousPosition, Vector3 serverCurrentPosition, Vector3 serverVelocity, out PortalTraversalTicket ticket) { ticket = default(PortalTraversalTicket); if (!_portals.TryResolveLinkedPair(request.SourcePortalId, request.DestinationPortalId, out Portal source, out Portal destination)) { return false; } if (request.ConnectionRevision != source.ConnectionRevision || !source.IsTraversable) { return false; } if (serverVelocity.Length() > MaxTravellerSpeed) { return false; } if (!PortalCrossingSolver.TryFindCrossing(source, serverPreviousPosition, serverCurrentPosition, out var crossing)) { return false; } ticket = new PortalTraversalTicket(request.TravellerId, source, destination, source.GetTransformToPair(), crossing); return true; } } } namespace Ravengates.Mathematics { public readonly struct Vector3 : IEquatable<Vector3> { public float X { get; } public float Y { get; } public float Z { get; } public static Vector3 Zero => new Vector3(0f, 0f, 0f); public static Vector3 One => new Vector3(1f, 1f, 1f); public static Vector3 UnitX => new Vector3(1f, 0f, 0f); public static Vector3 UnitY => new Vector3(0f, 1f, 0f); public static Vector3 UnitZ => new Vector3(0f, 0f, 1f); public Vector3(float x, float y, float z) { X = x; Y = y; Z = z; } public float LengthSquared() { return X * X + Y * Y + Z * Z; } public float Length() { return (float)Math.Sqrt(LengthSquared()); } public static float Dot(Vector3 left, Vector3 right) { return left.X * right.X + left.Y * right.Y + left.Z * right.Z; } public static Vector3 Normalize(Vector3 value) { float num = value.Length(); if (!(num <= 1E-07f)) { return value / num; } return Zero; } public static Vector3 Lerp(Vector3 a, Vector3 b, float amount) { return a + (b - a) * amount; } public static Vector3 Transform(Vector3 value, Quaternion rotation) { return Quaternion.Transform(value, rotation); } public bool Equals(Vector3 other) { if (X.Equals(other.X) && Y.Equals(other.Y)) { return Z.Equals(other.Z); } return false; } public override bool Equals(object? obj) { if (obj is Vector3 other) { return Equals(other); } return false; } public override int GetHashCode() { return (X.GetHashCode() * 397) ^ (Y.GetHashCode() * 17) ^ Z.GetHashCode(); } public override string ToString() { return $"({X}, {Y}, {Z})"; } public static Vector3 operator +(Vector3 left, Vector3 right) { return new Vector3(left.X + right.X, left.Y + right.Y, left.Z + right.Z); } public static Vector3 operator -(Vector3 left, Vector3 right) { return new Vector3(left.X - right.X, left.Y - right.Y, left.Z - right.Z); } public static Vector3 operator -(Vector3 value) { return new Vector3(0f - value.X, 0f - value.Y, 0f - value.Z); } public static Vector3 operator *(Vector3 value, float scalar) { return new Vector3(value.X * scalar, value.Y * scalar, value.Z * scalar); } public static Vector3 operator *(float scalar, Vector3 value) { return value * scalar; } public static Vector3 operator /(Vector3 value, float scalar) { return new Vector3(value.X / scalar, value.Y / scalar, value.Z / scalar); } } public readonly struct Quaternion : IEquatable<Quaternion> { public float X { get; } public float Y { get; } public float Z { get; } public float W { get; } public static Quaternion Identity => new Quaternion(0f, 0f, 0f, 1f); public Quaternion(float x, float y, float z, float w) { X = x; Y = y; Z = z; W = w; } public static Quaternion CreateFromAxisAngle(Vector3 axis, float angle) { Vector3 vector = Vector3.Normalize(axis); float num = angle * 0.5f; float num2 = (float)Math.Sin(num); return Normalize(new Quaternion(vector.X * num2, vector.Y * num2, vector.Z * num2, (float)Math.Cos(num))); } public static Quaternion Normalize(Quaternion value) { float num = (float)Math.Sqrt(value.X * value.X + value.Y * value.Y + value.Z * value.Z + value.W * value.W); if (!(num <= 1E-07f)) { return new Quaternion(value.X / num, value.Y / num, value.Z / num, value.W / num); } return Identity; } public static Quaternion Inverse(Quaternion value) { float num = value.X * value.X + value.Y * value.Y + value.Z * value.Z + value.W * value.W; if (num <= 1E-07f) { return Identity; } return new Quaternion((0f - value.X) / num, (0f - value.Y) / num, (0f - value.Z) / num, value.W / num); } public static Quaternion Slerp(Quaternion a, Quaternion b, float amount) { a = Normalize(a); b = Normalize(b); float num = a.X * b.X + a.Y * b.Y + a.Z * b.Z + a.W * b.W; if (num < 0f) { b = new Quaternion(0f - b.X, 0f - b.Y, 0f - b.Z, 0f - b.W); num = 0f - num; } if (num > 0.9995f) { return Normalize(new Quaternion(a.X + amount * (b.X - a.X), a.Y + amount * (b.Y - a.Y), a.Z + amount * (b.Z - a.Z), a.W + amount * (b.W - a.W))); } float num2 = (float)Math.Acos(Math.Max(-1f, Math.Min(1f, num))); float num3 = (float)Math.Sin(num2); float num4 = (float)Math.Sin((1f - amount) * num2) / num3; float num5 = (float)Math.Sin(amount * num2) / num3; return new Quaternion(a.X * num4 + b.X * num5, a.Y * num4 + b.Y * num5, a.Z * num4 + b.Z * num5, a.W * num4 + b.W * num5); } public static Vector3 Transform(Vector3 value, Quaternion rotation) { Quaternion quaternion = Normalize(rotation); Vector3 left = new Vector3(quaternion.X, quaternion.Y, quaternion.Z); Vector3 vector = Cross(left, value); Vector3 vector2 = Cross(left, vector); return value + vector * (2f * quaternion.W) + vector2 * 2f; } private static Vector3 Cross(Vector3 left, Vector3 right) { return new Vector3(left.Y * right.Z - left.Z * right.Y, left.Z * right.X - left.X * right.Z, left.X * right.Y - left.Y * right.X); } public bool Equals(Quaternion other) { if (X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z)) { return W.Equals(other.W); } return false; } public override bool Equals(object? obj) { if (obj is Quaternion other) { return Equals(other); } return false; } public override int GetHashCode() { return (((((X.GetHashCode() * 397) ^ Y.GetHashCode()) * 397) ^ Z.GetHashCode()) * 397) ^ W.GetHashCode(); } public override string ToString() { return $"({X}, {Y}, {Z}, {W})"; } public static Quaternion operator *(Quaternion left, Quaternion right) { return new Quaternion(left.W * right.X + left.X * right.W + left.Y * right.Z - left.Z * right.Y, left.W * right.Y - left.X * right.Z + left.Y * right.W + left.Z * right.X, left.W * right.Z + left.X * right.Y - left.Y * right.X + left.Z * right.W, left.W * right.W - left.X * right.X - left.Y * right.Y - left.Z * right.Z); } } } namespace Ravengates.Core { public enum PortalTraversalDirection { Bidirectional, OutboundOnly, InboundOnly } public enum PortalSealedSide { None, Front, Back } [Flags] public enum PortalFaces { None = 0, Front = 1, Back = 2, Both = 3 } public sealed class Portal { private Portal? _pair; public string Id { get; } public PortalPose Pose { get; private set; } public PortalAperture Aperture { get; private set; } public string Tag { get; private set; } public int ConnectionRevision { get; private set; } public int TransformRevision { get; private set; } public Portal? Pair => _pair; public bool IsLinked => _pair != null; public bool IsMutual { get { if (_pair != null) { return _pair._pair == this; } return false; } } public bool IsTraversable { get { if (IsLinked && Pose.HasFiniteValues() && Pair.Pose.HasFiniteValues() && Pose.HasUniformUnitScale()) { return Pair.Pose.HasUniformUnitScale(); } return false; } } public PortalTraversalDirection Direction { get; private set; } public bool AllowsTraversalToPair { get { if (IsLinked && Direction != PortalTraversalDirection.InboundOnly) { return Pair.Direction != PortalTraversalDirection.OutboundOnly; } return false; } } public PortalSealedSide SealedSide { get; private set; } public PortalFaces BlockedFaces { get; private set; } public Portal(string id, PortalPose pose, PortalAperture aperture, string? tag = null) { if (string.IsNullOrWhiteSpace(id)) { throw new ArgumentException("A portal id is required.", "id"); } Id = id; Pose = pose; Aperture = aperture; Tag = tag ?? string.Empty; ConnectionRevision = 1; TransformRevision = 1; } public void SetDirection(PortalTraversalDirection direction) { Direction = direction; } public void SetSealedSide(PortalSealedSide side) { SealedSide = side; } public bool IsSideOpen(int side) { if (IsLinked && !Closes(side)) { return !Pair.Closes(side); } return false; } public void SetBlockedFaces(PortalFaces faces) { BlockedFaces = faces & PortalFaces.Both; } public bool IsSideBlocked(int side) { if (IsLinked) { if (!Blocks(BlockedFaces, side)) { return Blocks(Pair.BlockedFaces, side); } return true; } return false; } private bool Closes(int side) { if (!Seals(SealedSide, side)) { return Blocks(BlockedFaces, side); } return true; } private static bool Blocks(PortalFaces faces, int side) { if (side <= 0) { if (side < 0) { return (faces & PortalFaces.Back) != 0; } return false; } return (faces & PortalFaces.Front) != 0; } private static bool Seals(PortalSealedSide sealedSide, int side) { if (side <= 0) { if (side < 0) { return sealedSide == PortalSealedSide.Back; } return false; } return sealedSide == PortalSealedSide.Front; } public PortalTransform GetTransformToPair() { if (!IsLinked) { throw new InvalidOperationException("Portal '" + Id + "' is not linked."); } return new PortalTransform(Id, Pair.Id, Pose, Pair.Pose); } public bool ContainsWorldPoint(Vector3 point, float margin = 0f) { return Aperture.ContainsWorldPoint(Pose, point, margin); } public bool SegmentIntersects(Vector3 start, Vector3 end, out PortalHit hit) { return Aperture.SegmentIntersects(Pose, start, end, out hit); } public bool ShapeFits(PortalBounds bounds) { return Aperture.ShapeFits(Pose, bounds); } public void SetPose(PortalPose pose) { if (!pose.HasFiniteValues()) { throw new ArgumentException("Portal pose must be finite.", "pose"); } Pose = pose; TransformRevision++; } public void SetAperture(PortalAperture aperture) { Aperture = aperture; TransformRevision++; } public void SetTag(string tag) { Tag = tag ?? string.Empty; ConnectionRevision++; } internal void SetPair(Portal? pair) { _pair = pair; ConnectionRevision++; } public override string ToString() { return "Portal(" + Id + ", tag='" + Tag + "', pair='" + (Pair?.Id ?? "none") + "')"; } } public sealed class PortalManager { private readonly Dictionary<string, Portal> _portals = new Dictionary<string, Portal>(StringComparer.Ordinal); public IEnumerable<Portal> Portals => _portals.Values; public bool Register(Portal portal) { if (_portals.ContainsKey(portal.Id)) { return false; } _portals.Add(portal.Id, portal); return true; } public bool Unregister(string id) { if (!_portals.TryGetValue(id, out Portal value)) { return false; } Unlink(value); foreach (Portal value2 in _portals.Values) { if (value2.Pair == value) { value2.SetPair(null); } } return _portals.Remove(id); } public bool TryGet(string id, out Portal portal) { return _portals.TryGetValue(id, out portal); } public bool TryLink(string firstId, string secondId) { if (!TryGet(firstId, out Portal portal) || !TryGet(secondId, out Portal portal2)) { return false; } return TryLink(portal, portal2); } public bool TryLink(Portal first, Portal second) { if (first == second || !_portals.ContainsKey(first.Id) || !_portals.ContainsKey(second.Id)) { return false; } if (first.IsMutual && first.Pair == second) { return true; } if (first.IsLinked) { Unlink(first); } if (second.IsLinked) { Unlink(second); } first.SetPair(second); second.SetPair(first); return true; } public bool TryLinkOneWay(Portal source, Portal exit) { if (source == exit || !_portals.ContainsKey(source.Id) || !_portals.ContainsKey(exit.Id)) { return false; } if (source.Pair == exit) { return true; } if (source.IsLinked) { Unlink(source); } source.SetPair(exit); return true; } public void Unlink(Portal portal) { Portal pair = portal.Pair; portal.SetPair(null); if (pair != null && pair.Pair == portal) { pair.SetPair(null); } } public bool TryResolveLinkedPair(string sourceId, string destinationId, out Portal source, out Portal destination) { source = null; destination = null; if (!TryGet(sourceId, out source) || !TryGet(destinationId, out destination)) { return false; } if (source.IsLinked) { return source.Pair == destination; } return false; } } public enum PortalApertureShape { Ellipse, RoundedRectangle, RadialProfile } public readonly struct PortalHit { public float Fraction { get; } public Vector3 Point { get; } public Vector3 LocalPoint { get; } public int SourceSide { get; } public PortalHit(float fraction, Vector3 point, Vector3 localPoint, int sourceSide) { Fraction = fraction; Point = point; LocalPoint = localPoint; SourceSide = sourceSide; } } public readonly struct PortalAperture { private readonly float[]? _radii; public float Width { get; } public float Height { get; } public PortalApertureShape Shape { get; } public float CornerRadius { get; } public int RadialSampleCount { get { float[]? radii = _radii; if (radii == null) { return 0; } return radii.Length; } } public PortalAperture(float width, float height, PortalApertureShape shape = PortalApertureShape.Ellipse, float cornerRadius = 0.25f) { if (width <= 0f) { throw new ArgumentOutOfRangeException("width"); } if (height <= 0f) { throw new ArgumentOutOfRangeException("height"); } if (shape == PortalApertureShape.RadialProfile) { throw new ArgumentException("Use the radial-profile constructor for measured openings.", "shape"); } Width = width; Height = height; Shape = shape; CornerRadius = Math.Max(0f, cornerRadius); _radii = null; } public PortalAperture(float[] radialProfile) { if (radialProfile == null) { throw new ArgumentNullException("radialProfile"); } if (radialProfile.Length < 8) { throw new ArgumentException("At least eight radial samples are required.", "radialProfile"); } float[] array = new float[radialProfile.Length]; float num = 0f; float num2 = 0f; float num3 = 0f; float num4 = 0f; for (int i = 0; i < array.Length; i++) { float num5 = radialProfile[i]; if (float.IsNaN(num5) || float.IsInfinity(num5) || num5 <= 0f) { throw new ArgumentOutOfRangeException("radialProfile", "Radial samples must be finite and positive."); } array[i] = num5; double num6 = Math.PI * 2.0 * (double)i / (double)array.Length; float val = (float)(Math.Cos(num6) * (double)num5); float val2 = (float)(Math.Sin(num6) * (double)num5); num = Math.Min(num, val); num2 = Math.Max(num2, val); num3 = Math.Min(num3, val2); num4 = Math.Max(num4, val2); } _radii = array; Width = Math.Max(0.0001f, 2f * Math.Max(0f - num, num2)); Height = Math.Max(0.0001f, 2f * Math.Max(0f - num3, num4)); Shape = PortalApertureShape.RadialProfile; CornerRadius = 0f; } public float RadiusAtAngle(float angle) { if (_radii != null) { double num = (double)angle / (Math.PI * 2.0); double num2 = (num - Math.Floor(num)) * (double)_radii.Length; int num3 = (int)Math.Floor(num2); float num4 = (float)(num2 - (double)num3); float num5 = _radii[num3 % _radii.Length]; float num6 = _radii[(num3 + 1) % _radii.Length]; return num5 + (num6 - num5) * num4; } double num7 = Math.Cos(angle); double num8 = Math.Sin(angle); double num9 = (double)Width * 0.5; double num10 = (double)Height * 0.5; if (Shape == PortalApertureShape.RoundedRectangle) { double val = ((Math.Abs(num7) < 1E-06) ? double.MaxValue : (num9 / Math.Abs(num7))); double val2 = ((Math.Abs(num8) < 1E-06) ? double.MaxValue : (num10 / Math.Abs(num8))); return (float)Math.Min(val, val2); } double d = num7 * num7 / (num9 * num9) + num8 * num8 / (num10 * num10); return (float)(1.0 / Math.Sqrt(d)); } public bool ContainsWorldPoint(PortalPose portalPose, Vector3 point, float margin = 0f) { Vector3 localPoint = portalPose.ToLocalPoint(point); return ContainsLocalPoint(localPoint, margin); } public bool ContainsLocalPoint(Vector3 localPoint, float margin = 0f) { if (Shape == PortalApertureShape.RadialProfile) { float num = (float)Math.Sqrt(localPoint.X * localPoint.X + localPoint.Y * localPoint.Y); float angle = (float)Math.Atan2(localPoint.Y, localPoint.X); if (num <= RadiusAtAngle(angle) + margin) { return Math.Abs(localPoint.Z) <= 0.05f; } return false; } float num2 = Math.Max(0.0001f, Width * 0.5f + margin); float num3 = Math.Max(0.0001f, Height * 0.5f + margin); if (Shape == PortalApertureShape.RoundedRectangle) { float num4 = Math.Min(CornerRadius + Math.Max(0f, margin), Math.Min(num2, num3)); float num5 = Math.Max(Math.Abs(localPoint.X) - (num2 - num4), 0f); float num6 = Math.Max(Math.Abs(localPoint.Y) - (num3 - num4), 0f); if (num5 * num5 + num6 * num6 <= num4 * num4) { return Math.Abs(localPoint.Z) <= 0.05f; } return false; } float num7 = localPoint.X / num2; float num8 = localPoint.Y / num3; if (num7 * num7 + num8 * num8 <= 1f) { return Math.Abs(localPoint.Z) <= 0.05f; } return false; } public bool SegmentIntersects(PortalPose portalPose, Vector3 start, Vector3 end, out PortalHit hit) { Vector3 vector = portalPose.ToLocalPoint(start); Vector3 vector2 = portalPose.ToLocalPoint(end); float z = vector.Z; float z2 = vector2.Z; bool num = (z < -1E-05f && z2 > 1E-05f) || (z > 1E-05f && z2 < -1E-05f); float num2 = 0f; if (num) { num2 = z / (z - z2); } else { if (!(Math.Abs(z) <= 1E-05f) || !(Math.Abs(z2) > 1E-05f)) { hit = default(PortalHit); return false; } num2 = 0f; } num2 = Math.Max(0f, Math.Min(1f, num2)); Vector3 localPoint = vector + (vector2 - vector) * num2; if (!ContainsLocalPoint(localPoint)) { hit = default(PortalHit); return false; } int num3 = Math.Sign(z); if (num3 == 0) { num3 = Math.Sign(z2); } hit = new PortalHit(num2, portalPose.ToWorldPoint(localPoint), localPoint, num3); return true; } public bool FitsUprightCapsule(float radius, float height, float margin = 0f) { radius = Math.Max(0f, radius); height = Math.Max(height, radius * 2f); float num = 0f - RadiusAtAngle(4.712389f); float y = num + radius; float y2 = num + height - radius; if (ContainsLocalPoint(new Vector3(0f - radius, y, 0f), 0f - margin) && ContainsLocalPoint(new Vector3(radius, y, 0f), 0f - margin) && ContainsLocalPoint(new Vector3(0f - radius, y2, 0f), 0f - margin) && ContainsLocalPoint(new Vector3(radius, y2, 0f), 0f - margin)) { return ContainsLocalPoint(new Vector3(0f, num + height, 0f), 0f - margin); } return false; } public bool ShapeFits(PortalPose portalPose, PortalBounds bounds) { Vector3 vector = portalPose.ToLocalPoint(bounds.Center); Vector3 vector2 = new Vector3(Math.Abs(bounds.Extents.X) + Math.Abs(bounds.Extents.Y) + Math.Abs(bounds.Extents.Z), Math.Abs(bounds.Extents.X) + Math.Abs(bounds.Extents.Y) + Math.Abs(bounds.Extents.Z), 0f); if (Shape == PortalApertureShape.RadialProfile) { for (int i = -1; i <= 1; i += 2) { for (int j = -1; j <= 1; j += 2) { if (!ContainsLocalPoint(new Vector3(vector.X + (float)i * vector2.X, vector.Y + (float)j * vector2.Y, 0f))) { return false; } } } return true; } if (Shape == PortalApertureShape.RoundedRectangle) { if (Math.Abs(vector.X) + vector2.X <= Width * 0.5f) { return Math.Abs(vector.Y) + vector2.Y <= Height * 0.5f; } return false; } float num = Math.Max(0.0001f, Width * 0.5f); float num2 = Math.Max(0.0001f, Height * 0.5f); float num3 = (Math.Abs(vector.X) + vector2.X) / num; float num4 = (Math.Abs(vector.Y) + vector2.Y) / num2; return num3 * num3 + num4 * num4 <= 1f; } } public readonly struct PortalPathStep { public PortalTransform Transform { get; } public int SourceConnectionRevision { get; } public int DestinationConnectionRevision { get; } public PortalPathStep(PortalTransform transform, int sourceConnectionRevision, int destinationConnectionRevision) { Transform = transform; SourceConnectionRevision = sourceConnectionRevision; DestinationConnectionRevision = destinationConnectionRevision; } } public sealed class PortalPath { private readonly List<PortalPathStep> _steps = new List<PortalPathStep>(); public int MaxTraversals { get; } public int Count => _steps.Count; public float LogicalDistance { get; private set; } public IReadOnlyList<PortalPathStep> Steps => _steps; public string Signature { get { if (_steps.Count == 0) { return "root"; } string text = string.Empty; for (int i = 0; i < _steps.Count; i++) { PortalPathStep portalPathStep = _steps[i]; text = text + ((i == 0) ? string.Empty : "/") + portalPathStep.Transform.SourcePortalId + ">" + portalPathStep.Transform.DestinationPortalId + ":" + portalPathStep.SourceConnectionRevision + ":" + portalPathStep.DestinationConnectionRevision; } return text; } } public PortalPath(int maxTraversals = 8) { if (maxTraversals < 1) { throw new ArgumentOutOfRangeException("maxTraversals"); } MaxTraversals = maxTraversals; } public bool TryAppend(Portal source, Portal destination, float distanceBeforeCrossing = 0f) { if (_steps.Count >= MaxTraversals || !source.IsLinked || source.Pair != destination) { return false; } _steps.Add(new PortalPathStep(new PortalTransform(source.Id, destination.Id, source.Pose, destination.Pose), source.ConnectionRevision, destination.ConnectionRevision)); LogicalDistance += Math.Max(0f, distanceBeforeCrossing); return true; } public void AddLogicalDistance(float distance) { LogicalDistance += Math.Max(0f, distance); } public Vector3 TransformPoint(Vector3 point) { for (int i = 0; i < _steps.Count; i++) { point = _steps[i].Transform.TransformPoint(point); } return point; } public Vector3 TransformDirection(Vector3 direction) { for (int i = 0; i < _steps.Count; i++) { direction = _steps[i].Transform.TransformDirection(direction); } return direction; } public PortalRay TransformRay(PortalRay ray) { for (int i = 0; i < _steps.Count; i++) { ray = _steps[i].Transform.TransformRay(ray); } return ray; } public bool HasCurrentRevisions() { for (int i = 0; i < _steps.Count; i++) { if (_steps[i].Transform.SourcePortalId == null) { return false; } } return true; } } public readonly struct PortalPose { public Vector3 Position { get; } public Quaternion Rotation { get; } public Vector3 Scale { get; } public static PortalPose Identity => new PortalPose(Vector3.Zero, Quaternion.Identity, Vector3.One); public PortalPose(Vector3 position, Quaternion rotation) : this(position, rotation, Vector3.One) { } public PortalPose(Vector3 position, Quaternion rotation, Vector3 scale) { Position = position; Rotation = Quaternion.Normalize(rotation); Scale = scale; } public bool HasFiniteValues() { if (IsFinite(Position) && IsFinite(Scale) && IsFinite(Rotation.X) && IsFinite(Rotation.Y) && IsFinite(Rotation.Z) && IsFinite(Rotation.W) && Scale.X != 0f && Scale.Y != 0f) { return Scale.Z != 0f; } return false; } public bool HasUniformUnitScale(float tolerance = 0.0001f) { if (Math.Abs(Scale.X - 1f) <= tolerance && Math.Abs(Scale.Y - 1f) <= tolerance) { return Math.Abs(Scale.Z - 1f) <= tolerance; } return false; } public Vector3 ToLocalPoint(Vector3 worldPoint) { Vector3 vector = Vector3.Transform(worldPoint - Position, Quaternion.Inverse(Rotation)); return new Vector3(vector.X / Scale.X, vector.Y / Scale.Y, vector.Z / Scale.Z); } public Vector3 ToWorldPoint(Vector3 localPoint) { Vector3 value = new Vector3(localPoint.X * Scale.X, localPoint.Y * Scale.Y, localPoint.Z * Scale.Z); return Position + Vector3.Transform(value, Rotation); } public Vector3 ToLocalDirection(Vector3 worldDirection) { return Vector3.Transform(worldDirection, Quaternion.Inverse(Rotation)); } public Vector3 ToWorldDirection(Vector3 localDirection) { return Vector3.Transform(localDirection, Rotation); } private static bool IsFinite(Vector3 value) { if (IsFinite(value.X) && IsFinite(value.Y)) { return IsFinite(value.Z); } return false; } private static bool IsFinite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } } public readonly struct PortalRay { public Vector3 Origin { get; } public Vector3 Direction { get; } public PortalRay(Vector3 origin, Vector3 direction) { Origin = origin; Direction = ((direction.LengthSquared() > 0f) ? Vector3.Normalize(direction) : Vector3.Zero); } public Vector3 GetPoint(float distance) { return Origin + Direction * distance; } } public readonly struct PortalPlane { public Vector3 Normal { get; } public float Distance { get; } public PortalPlane(Vector3 normal, float distance) { float num = normal.Length(); if (num <= 0f) { throw new ArgumentException("A portal plane needs a non-zero normal.", "normal"); } Normal = normal / num; Distance = distance / num; } public float SignedDistanceTo(Vector3 point) { return Vector3.Dot(Normal, point) + Distance; } } public readonly struct PortalBounds { public Vector3 Center { get; } public Vector3 Extents { get; } public PortalBounds(Vector3 center, Vector3 extents) { if (extents.X < 0f || extents.Y < 0f || extents.Z < 0f) { throw new ArgumentOutOfRangeException("extents", "Bounds extents cannot be negative."); } Center = center; Extents = extents; } } public struct PortalTravellerState { public Vector3 Position; public Quaternion Rotation; public Vector3 Velocity; public Vector3 AngularVelocity; public PortalTravellerState(Vector3 position, Quaternion rotation, Vector3 velocity, Vector3 angularVelocity) { Position = position; Rotation = Quaternion.Normalize(rotation); Velocity = velocity; AngularVelocity = angularVelocity; } } public readonly struct PortalTransform { private static readonly Quaternion HalfTurn = Quaternion.CreateFromAxisAngle(Vector3.UnitY, MathF.PI); public string SourcePortalId { get; } public string DestinationPortalId { get; } public PortalPose Source { get; } public PortalPose Destination { get; } public Quaternion Rotation { get; } public PortalTransform(string sourcePortalId, string destinationPortalId, PortalPose source, PortalPose destination) { if (string.IsNullOrWhiteSpace(sourcePortalId)) { throw new ArgumentException("A source portal id is required.", "sourcePortalId"); } if (string.IsNullOrWhiteSpace(destinationPortalId)) { throw new ArgumentException("A destination portal id is required.", "destinationPortalId"); } if (!source.HasFiniteValues() || !destination.HasFiniteValues()) { throw new ArgumentException("Portal poses must contain finite, non-zero values."); } SourcePortalId = sourcePortalId; DestinationPortalId = destinationPortalId; Source = source; Destination = destination; Rotation = Quaternion.Normalize(destination.Rotation * HalfTurn * Quaternion.Inverse(source.Rotation)); } public Vector3 TransformPoint(Vector3 worldPoint) { Vector3 vector = Source.ToLocalPoint(worldPoint); Vector3 localPoint = new Vector3(0f - vector.X, vector.Y, 0f - vector.Z); return Destination.ToWorldPoint(localPoint); } public Vector3 TransformDirection(Vector3 worldDirection) { return Vector3.Transform(worldDirection, Rotation); } public Quaternion TransformRotation(Quaternion worldRotation) { return Quaternion.Normalize(Rotation * worldRotation); } public PortalTravellerState TransformState(PortalTravellerState state) { return new PortalTravellerState(TransformPoint(state.Position), TransformRotation(state.Rotation), TransformDirection(state.Velocity), TransformDirection(state.AngularVelocity)); } public PortalRay TransformRay(PortalRay ray) { return new PortalRay(TransformPoint(ray.Origin), TransformDirection(ray.Direction)); } public PortalPlane TransformPlane(PortalPlane plane) { Vector3 worldPoint = plane.Normal * (0f - plane.Distance); Vector3 right = TransformPoint(worldPoint); Vector3 vector = Vector3.Normalize(TransformDirection(plane.Normal)); return new PortalPlane(vector, 0f - Vector3.Dot(vector, right)); } public Vector3 TransformNormal(Vector3 worldNormal) { return Vector3.Normalize(TransformDirection(worldNormal)); } public int TransformSide(int sourceSide) { if (sourceSide == 0) { return 0; } return -Math.Sign(sourceSide); } public override string ToString() { return SourcePortalId + "->" + DestinationPortalId; } } } namespace Ravengates.Configuration { public enum PortalFallbackMode { Block, UnstableEffect, VanillaTeleport } public sealed class PortalConfiguration { public bool PortalRenderEnabled { get; set; } = true; public bool EnablePlayerTraversal { get; set; } = true; public int MaxRecursionDepth { get; set; } = 2; public int MaxPortalRenderPassesPerFrame { get; set; } = 6; public float PortalRenderScale { get; set; } = 0.75f; public float MaxPortalViewDistance { get; set; } = 400f; public float MinPortalScreenPixels { get; set; } = 64f; public int RenderZoneRadius { get; set; } = 1; public int InteractiveZoneRadius { get; set; } = 2; public int CrossingReadyZoneRadius { get; set; } = 3; public double RemoteUnloadGraceSeconds { get; set; } = 10.0; public int MaxRemoteInterestRegionsPerPlayer { get; set; } = 4; public int MaxRemoteZonesPerPlayer { get; set; } = 98; public float PortalInterestActivationDistance { get; set; } = 128f; public int MaxCrossingsPerFixedStep { get; set; } = 8; public float PortalPlaneEpsilon { get; set; } = 0.02f; public bool EnableVisualStraddling { get; set; } = true; public bool EnableRemoteProxyCollision { get; set; } public bool RespectVanillaPortalRestrictions { get; set; } = true; public bool AllowInteractionThroughPortal { get; set; } public bool AllowAITraversal { get; set; } public bool ServerAuthoritativeTraversal { get; set; } = true; public bool ClientPrediction { get; set; } = true; public int MaxRemoteSimulatedCharacters { get; set; } = 50; public PortalFallbackMode FallbackMode { get; set; } public void Validate() { MaxRecursionDepth = Clamp(MaxRecursionDepth, 0, 5); MaxPortalRenderPassesPerFrame = Clamp(MaxPortalRenderPassesPerFrame, 0, 16); PortalRenderScale = ClampFinite(PortalRenderScale, 0.25f, 1f, 0.75f); MaxPortalViewDistance = ClampFinite(MaxPortalViewDistance, 50f, 1000f, 400f); MinPortalScreenPixels = ClampFinite(MinPortalScreenPixels, 0f, 512f, 64f); RenderZoneRadius = Clamp(RenderZoneRadius, 0, 6); InteractiveZoneRadius = Clamp(InteractiveZoneRadius, 0, 6); CrossingReadyZoneRadius = Clamp(CrossingReadyZoneRadius, 0, 6); if (InteractiveZoneRadius < RenderZoneRadius) { InteractiveZoneRadius = RenderZoneRadius; } if (CrossingReadyZoneRadius < InteractiveZoneRadius) { CrossingReadyZoneRadius = InteractiveZoneRadius; } RemoteUnloadGraceSeconds = ClampFinite(RemoteUnloadGraceSeconds, 0.0, 60.0, 10.0); MaxRemoteInterestRegionsPerPlayer = Clamp(MaxRemoteInterestRegionsPerPlayer, 1, 32); MaxRemoteZonesPerPlayer = Clamp(MaxRemoteZonesPerPlayer, 1, 512); PortalInterestActivationDistance = ClampFinite(PortalInterestActivationDistance, 0f, 512f, 128f); MaxCrossingsPerFixedStep = Clamp(MaxCrossingsPerFixedStep, 1, 32); PortalPlaneEpsilon = ClampFinite(PortalPlaneEpsilon, 0f, 0.25f, 0.02f); MaxRemoteSimulatedCharacters = Clamp(MaxRemoteSimulatedCharacters, 0, 500); } private static int Clamp(int value, int min, int max) { return Math.Max(min, Math.Min(max, value)); } private static float ClampFinite(float value, float min, float max, float fallback) { if (!float.IsNaN(value) && !float.IsInfinity(value)) { return Math.Max(min, Math.Min(max, value)); } return fallback; } private static double ClampFinite(double value, double min, double max, double fallback) { if (!double.IsNaN(value) && !double.IsInfinity(value)) { return Math.Max(min, Math.Min(max, value)); } return fallback; } } }
plugins/Ravengates.Valheim.dll
Decompiled 2 weeks 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.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using Ravengates.Configuration; using Ravengates.Core; using Ravengates.Mathematics; using Ravengates.Physics; using Ravengates.Rendering; using Ravengates.Streaming; using SoftReferenceableAssets; using Splatform; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Experimental.Rendering; using UnityEngine.PostProcessing; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Ravengates.Valheim")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.3.0.0")] [assembly: AssemblyInformationalVersion("1.3.0")] [assembly: AssemblyProduct("Ravengates.Valheim")] [assembly: AssemblyTitle("Ravengates.Valheim")] [assembly: AssemblyVersion("1.3.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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; } } } public sealed class VrtNoLightProxy : MonoBehaviour { } namespace Ravengates.Valheim { internal static class MjolnirPortalCompat { internal static readonly Type? ActorType = AccessTools.TypeByName("ValheimMjolnir.Gameplay.MjolnirWorldActor"); private static readonly Type? DriverType = AccessTools.TypeByName("ValheimMjolnir.Presentation.MjolnirAnimationDriver"); private static readonly FieldInfo? PreviousPosition = Field("previousPosition"); private static readonly FieldInfo? ReleasePosition = Field("releasePosition"); private static readonly FieldInfo? OutboundVelocity = Field("outboundVelocityBeforePhysics"); private static readonly FieldInfo? OutboundAngularVelocity = Field("outboundAngularVelocityBeforePhysics"); private static readonly FieldInfo? RecallVelocity = Field("recallVelocity"); private static readonly FieldInfo? AnimationDriver = Field("animationDriver"); private static readonly PropertyInfo? OwnerProperty = ((ActorType == null) ? null : AccessTools.Property(ActorType, "Owner")); private static readonly PropertyInfo? HandPositionProperty = ((DriverType == null) ? null : AccessTools.Property(DriverType, "HandPosition")); [ThreadStatic] private static Component? _returningActor; internal static bool Available => ActorType != null; internal static MethodInfo? DistanceToOwnerGetter { get { if (!(ActorType == null)) { return AccessTools.PropertyGetter(ActorType, "DistanceToOwner"); } return null; } } internal static MethodInfo? TickReturnMethod { get { if (!(ActorType == null)) { return AccessTools.Method(ActorType, "TickReturn", (Type[])null, (Type[])null); } return null; } } internal static MethodInfo? HandPositionGetter => HandPositionProperty?.GetGetMethod(nonPublic: true); private static FieldInfo? Field(string name) { if (!(ActorType == null)) { return AccessTools.Field(ActorType, name); } return null; } internal static bool IsActor(GameObject gameObject) { if (ActorType != null) { return (Object)(object)gameObject.GetComponent(ActorType) != (Object)null; } return false; } internal static void OnTraversed(GameObject gameObject, Matrix4x4 pointMap, Quaternion turn) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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) Component val = ((ActorType == null) ? null : gameObject.GetComponent(ActorType)); if ((Object)(object)val == (Object)null) { return; } try { PreviousPosition?.SetValue(val, gameObject.transform.position); if (ReleasePosition?.GetValue(val) is Vector3 val2) { ReleasePosition.SetValue(val, ((Matrix4x4)(ref pointMap)).MultiplyPoint3x4(val2)); } Rotate(OutboundVelocity, val, turn); Rotate(OutboundAngularVelocity, val, turn); Rotate(RecallVelocity, val, turn); } catch (Exception ex) { RavengatesPlugin.LogWarning("Mjolnir portal support failed after a crossing: " + ex.GetBaseException().Message); } } private static void Rotate(FieldInfo? field, Component actor, Quaternion turn) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (field?.GetValue(actor) is Vector3 val) { field.SetValue(actor, turn * val); } } internal static bool TryRouteThroughPortal(Component actor, Vector3 point, out Vector3 mapped, out float routeDistance) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: 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_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: 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_00e3: Unknown result type (might be due to invalid IL or missing references) mapped = point; routeDistance = 0f; RavengateManager manager = RavengatesPlugin.Manager; RavengateTraveller component = actor.GetComponent<RavengateTraveller>(); if ((Object)(object)manager == (Object)null || (Object)(object)component == (Object)null || component.LastSourcePortalId == null || component.LastDestinationPortalId == null) { return false; } if (!manager.TryGetPortal(component.LastSourcePortalId, out Portal portal) || !portal.IsTraversable || portal.Pair == null || portal.Pair.Id != component.LastDestinationPortalId) { return false; } Vector3 position = actor.transform.position; PortalPose pose = portal.Pose; Vector3 val = ValheimPortalMath.ToUnity(((PortalPose)(ref pose)).Position); pose = portal.Pair.Pose; Vector3 val2 = ValheimPortalMath.ToUnity(((PortalPose)(ref pose)).Position); routeDistance = Vector3.Distance(position, val2) + Vector3.Distance(val, point); if (routeDistance >= Vector3.Distance(position, point)) { return false; } mapped = ValheimPortalMath.TransformPoint(portal.GetTransformToPair(), point); return true; } internal static void DistanceToOwnerPostfix(Component __instance, ref float __result) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (RavengatesPlugin.IsEnabled) { object? obj = OwnerProperty?.GetValue(__instance); Player val = (Player)((obj is Player) ? obj : null); if (val != null && !((Object)(object)val == (Object)null) && TryRouteThroughPortal(__instance, ((Component)val).transform.position, out var _, out var routeDistance) && routeDistance < __result) { __result = routeDistance; } } } internal static void TickReturnPrefix(Component __instance) { _returningActor = __instance; } internal static Exception? TickReturnFinalizer(Exception? __exception) { _returningActor = null; return __exception; } internal static void HandPositionPostfix(Component __instance, ref Vector3 __result) { //IL_002f: 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_0041: Unknown result type (might be due to invalid IL or missing references) Component returningActor = _returningActor; if (!((Object)(object)returningActor == (Object)null) && RavengatesPlugin.IsEnabled && AnimationDriver?.GetValue(returningActor) == __instance && TryRouteThroughPortal(returningActor, __result, out var mapped, out var _)) { __result = mapped; } } } [HarmonyPatch] internal static class MjolnirDistanceToOwnerPatch { private static bool Prepare() { return MjolnirPortalCompat.DistanceToOwnerGetter != null; } private static MethodBase TargetMethod() { return MjolnirPortalCompat.DistanceToOwnerGetter; } private static void Postfix(Component __instance, ref float __result) { MjolnirPortalCompat.DistanceToOwnerPostfix(__instance, ref __result); } } [HarmonyPatch] internal static class MjolnirTickReturnPatch { private static bool Prepare() { if (MjolnirPortalCompat.TickReturnMethod != null) { return MjolnirPortalCompat.HandPositionGetter != null; } return false; } private static MethodBase TargetMethod() { return MjolnirPortalCompat.TickReturnMethod; } private static void Prefix(Component __instance) { MjolnirPortalCompat.TickReturnPrefix(__instance); } private static Exception? Finalizer(Exception? __exception) { return MjolnirPortalCompat.TickReturnFinalizer(__exception); } } [HarmonyPatch] internal static class MjolnirHandPositionPatch { private static bool Prepare() { if (MjolnirPortalCompat.TickReturnMethod != null) { return MjolnirPortalCompat.HandPositionGetter != null; } return false; } private static MethodBase TargetMethod() { return MjolnirPortalCompat.HandPositionGetter; } private static void Postfix(Component __instance, ref Vector3 __result) { MjolnirPortalCompat.HandPositionPostfix(__instance, ref __result); } } internal static class OdinPortalObjMesh { internal sealed class Part { internal string Name = string.Empty; internal Mesh Mesh; internal string[] Materials = Array.Empty<string>(); } private sealed class Builder { internal readonly string Name; internal readonly List<Vector3> Positions = new List<Vector3>(); internal readonly List<Vector3> Normals = new List<Vector3>(); internal readonly List<Vector2> Uvs = new List<Vector2>(); internal readonly Dictionary<string, int> Remap = new Dictionary<string, int>(StringComparer.Ordinal); internal readonly List<string> Materials = new List<string>(); internal readonly List<List<int>> Indices = new List<List<int>>(); internal Builder(string name) { Name = name; } internal int Material(string name) { int num = Materials.IndexOf(name); if (num >= 0) { return num; } Materials.Add(name); Indices.Add(new List<int>()); return Materials.Count - 1; } internal int Vertex(string token, List<Vector3> positions, List<Vector3> normals, List<Vector2> uvs) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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_0089: Unknown result type (might be due to invalid IL or missing references) if (Remap.TryGetValue(token, out var value)) { return value; } string[] fields = token.Split('/'); int num = Index(fields, 0, positions.Count); int num2 = Index(fields, 1, uvs.Count); int num3 = Index(fields, 2, normals.Count); Positions.Add((num >= 0) ? positions[num] : Vector3.zero); Normals.Add((num3 >= 0) ? normals[num3] : Vector3.up); Uvs.Add((num2 >= 0) ? uvs[num2] : Vector2.zero); int num4 = Positions.Count - 1; Remap.Add(token, num4); return num4; } internal Part? Finish() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown if (Positions.Count == 0 || Indices.Count == 0) { return null; } Mesh val = new Mesh { name = Name }; if (Positions.Count > 65000) { val.indexFormat = (IndexFormat)1; } val.SetVertices(Positions); val.SetNormals(Normals); val.SetUVs(0, Uvs); val.subMeshCount = Indices.Count; for (int i = 0; i < Indices.Count; i++) { val.SetTriangles(Indices[i], i); } val.RecalculateBounds(); return new Part { Name = Name, Mesh = val, Materials = Materials.ToArray() }; } } private static readonly char[] Spaces = new char[3] { ' ', '\t', '\r' }; internal static List<Part> Build(string text) { //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) List<Vector3> list = new List<Vector3>(); List<Vector3> list2 = new List<Vector3>(); List<Vector2> list3 = new List<Vector2>(); List<Part> list4 = new List<Part>(); Builder builder = null; int num = -1; string[] array = text.Split('\n'); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length == 0 || text2[0] == '#') { continue; } string[] array2 = text2.Split(Spaces, StringSplitOptions.RemoveEmptyEntries); switch (array2[0]) { case "v": if (array2.Length >= 4) { list.Add(new Vector3(0f - Number(array2[1]), Number(array2[2]), Number(array2[3]))); } break; case "vn": if (array2.Length >= 4) { list2.Add(new Vector3(0f - Number(array2[1]), Number(array2[2]), Number(array2[3]))); } break; case "vt": if (array2.Length >= 3) { list3.Add(new Vector2(Number(array2[1]), Number(array2[2]))); } break; case "g": if (array2.Length >= 2) { Part part = builder?.Finish(); if (part != null) { list4.Add(part); } builder = new Builder(array2[1]); num = -1; } break; case "usemtl": if (array2.Length >= 2) { if (builder == null) { builder = new Builder("OdinPortal_Unnamed"); } num = builder.Material(array2[1]); } break; case "f": if (array2.Length >= 4) { if (builder == null) { builder = new Builder("OdinPortal_Unnamed"); } if (num < 0) { num = builder.Material("MAT_Wood"); } int[] array3 = new int[array2.Length - 1]; for (int j = 1; j < array2.Length; j++) { array3[j - 1] = builder.Vertex(array2[j], list, list2, list3); } List<int> list5 = builder.Indices[num]; for (int k = 1; k + 1 < array3.Length; k++) { list5.Add(array3[0]); list5.Add(array3[k + 1]); list5.Add(array3[k]); } } break; } } Part part2 = builder?.Finish(); if (part2 != null) { list4.Add(part2); } return list4; } private static int Index(string[] fields, int slot, int count) { if (slot >= fields.Length || !int.TryParse(fields[slot], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return -1; } int num = ((result > 0) ? (result - 1) : (count + result)); if (num < 0 || num >= count) { return -1; } return num; } private static float Number(string text) { return float.Parse(text, NumberStyles.Float, CultureInfo.InvariantCulture); } } internal static class OdinPortalAsset { internal const float VisualScale = 1.1f; private const string ObjResource = "Ravengates.Assets.OdinPortal.obj"; private const string MtlResource = "Ravengates.Assets.OdinPortal.mtl"; private const string WoodResource = "Ravengates.Assets.OdinWood.png"; private const string StoneResource = "Ravengates.Assets.OdinStone.png"; private static bool _attempted; private static List<OdinPortalObjMesh.Part>? _parts; private static Dictionary<string, Color>? _colors; private static Texture2D? _wood; private static Texture2D? _stone; private static readonly Dictionary<string, Texture2D> RavenEyeMasks = new Dictionary<string, Texture2D>(StringComparer.Ordinal); private static readonly Dictionary<string, Material> CarvedRavenMaterials = new Dictionary<string, Material>(StringComparer.Ordinal); internal static readonly Vector3 HuginPerch = new Vector3(0.84f, 2.15f, 0.4f); internal static readonly Vector3 MuninPerch = new Vector3(-0.8f, 2.24f, -0.435f); internal const float HuginYaw = 0f; internal static readonly float MuninYaw = FacingYaw(-Vector3.forward); internal const float HuginLean = 5f; internal const float MuninLean = 3f; internal static readonly Vector2 HuginReach = new Vector2(-95f, 70f); internal static readonly Vector2 MuninReach = new Vector2(-40f, 40f); internal static readonly Vector3 OpeningCenter = new Vector3(0f, 1.12f, 0.035f); internal const float OpeningHalfWidth = 0.93f; internal const float OpeningHalfHeight = 1.01f; private static float FacingYaw(Vector3 direction) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Mathf.Atan2(direction.x, direction.z) * 57.29578f; } internal static bool TryApply(GameObject prefab, Ravengate portal, ManualLogSource? logger) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown //IL_0077: 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_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Expected O, but got Unknown //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0386: Unknown result type (might be due to invalid IL or missing references) //IL_039a: Unknown result type (might be due to invalid IL or missing references) //IL_03c2: Unknown result type (might be due to invalid IL or missing references) //IL_03d6: Unknown result type (might be due to invalid IL or missing references) //IL_03fe: Unknown result type (might be due to invalid IL or missing references) //IL_0412: Unknown result type (might be due to invalid IL or missing references) //IL_0461: Unknown result type (might be due to invalid IL or missing references) //IL_0475: Unknown result type (might be due to invalid IL or missing references) if (!Load(logger) || _parts == null) { return false; } GameObject val = null; List<(Collider, bool)> list = new List<(Collider, bool)>(); List<(MeshRenderer, bool)> list2 = new List<(MeshRenderer, bool)>(); try { Material donor = FindFrameMaterial(prefab); Material val2 = FindNativeMaterial("darkwood_beam", "DarkWood_mat"); Material val3 = FindNativeMaterial("stone_wall_2x1", "stone_mat"); Dictionary<string, Material> cache = new Dictionary<string, Material>(StringComparer.Ordinal); val = new GameObject("OdinPortalVisual"); val.transform.SetParent(prefab.transform, false); val.transform.localScale = Vector3.one * 1.1f; OdinPortalVisual odinVisual = val.AddComponent<OdinPortalVisual>(); Transform val4 = AddGroup(val.transform, "Raven_Huginn", HuginPerch); Transform val5 = AddGroup(val.transform, "Raven_Muninn", MuninPerch); Material material = GetMaterial("MAT_Raven_CarvedWood", donor, val2, val3, cache); if (material.HasProperty("_Cull")) { material.SetInt("_Cull", 0); } if (material.HasProperty("_CullMode")) { material.SetInt("_CullMode", 0); } Texture grain = (Texture)(((Object)(object)val2 != (Object)null && val2.HasProperty("_MainTex")) ? (((object)val2.GetTexture("_MainTex")) ?? ((object)_wood)) : _wood); bool flag = TryAddNativeRaven(val4, "Hugin", 0f, material, grain, logger); bool flag2 = TryAddNativeRaven(val5, "Munin", MuninYaw, material, grain, logger); foreach (OdinPortalObjMesh.Part part in _parts) { if ((!flag || !part.Name.StartsWith("Huginn_", StringComparison.Ordinal)) && (!flag2 || !part.Name.StartsWith("Muninn_", StringComparison.Ordinal))) { GameObject val6 = new GameObject(part.Name); Transform val7 = (part.Name.StartsWith("Huginn_", StringComparison.Ordinal) ? val4 : (part.Name.StartsWith("Muninn_", StringComparison.Ordinal) ? val5 : val.transform)); val6.transform.SetParent(val7, false); if ((Object)(object)val7 != (Object)(object)val.transform) { val6.transform.localPosition = -val7.localPosition; } val6.AddComponent<MeshFilter>().sharedMesh = part.Mesh; MeshRenderer val8 = val6.AddComponent<MeshRenderer>(); Material[] array = (Material[])(object)new Material[part.Materials.Length]; for (int i = 0; i < array.Length; i++) { array[i] = GetMaterial(part.Materials[i], donor, val2, val3, cache); } ((Renderer)val8).sharedMaterials = array; } } int layer = prefab.layer; Collider[] componentsInChildren = prefab.GetComponentsInChildren<Collider>(true); foreach (Collider val9 in componentsInChildren) { list.Add((val9, val9.enabled)); if (!val9.isTrigger) { layer = ((Component)val9).gameObject.layer; } val9.enabled = false; } MeshRenderer[] componentsInChildren2 = prefab.GetComponentsInChildren<MeshRenderer>(true); foreach (MeshRenderer val10 in componentsInChildren2) { if (!((Component)val10).transform.IsChildOf(val.transform)) { list2.Add((val10, ((Renderer)val10).enabled)); ((Renderer)val10).enabled = false; } } AddBox(val.transform, "COL_Left", new Vector3(-1.18f, 0.94f, 0f), new Vector3(0.39f, 1.62f, 0.62f), layer, trigger: false); AddBox(val.transform, "COL_Right", new Vector3(1.18f, 0.94f, 0f), new Vector3(0.39f, 1.62f, 0.62f), layer, trigger: false); AddBox(val.transform, "COL_Top", new Vector3(0f, 2.33f, 0f), new Vector3(1.35f, 0.24f, 0.52f), layer, trigger: false); AddRamp(val.transform, "COL_Base", 1.8f, 0.11f, 0.3f, 0.78f, layer); portal.m_openingVolume = AddBox(val.transform, "OdinOpeningVolume", new Vector3(0f, 1.12f, 0f), new Vector3(1.86f, 2.02f, 0.3f), layer, trigger: true); portal.m_odinVisual = odinVisual; portal.m_model = null; int num = _parts.Count - (flag ? 1 : 0) - (flag2 ? 1 : 0); if (logger != null) { logger.LogInfo((object)($"Applied Odin portal model: {num} authored mesh groups, " + $"{(flag ? 1 : 0) + (flag2 ? 1 : 0)} native wooden ravens; " + "wood material=" + (((val2 != null) ? ((Object)val2).name : null) ?? "embedded fallback") + ", stone material=" + (((val3 != null) ? ((Object)val3).name : null) ?? "embedded fallback") + ".")); } return true; } catch (Exception arg) { if ((Object)(object)val != (Object)null) { Object.DestroyImmediate((Object)(object)val); } foreach (var item in list) { if ((Object)(object)item.Item1 != (Object)null) { item.Item1.enabled = item.Item2; } } foreach (var item2 in list2) { if ((Object)(object)item2.Item1 != (Object)null) { ((Renderer)item2.Item1).enabled = item2.Item2; } } if (logger != null) { logger.LogWarning((object)$"Odin portal asset could not be applied; keeping cloned frame: {arg}"); } return false; } } private static Transform AddGroup(Transform parent, string name, Vector3 localPosition) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) Transform transform = new GameObject(name).transform; transform.SetParent(parent, false); transform.localPosition = localPosition; return transform; } private static bool TryAddNativeRaven(Transform parent, string prefabName, float yaw, Material fallbackWood, Texture? grain, ManualLogSource? logger) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_030e: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_0387: Unknown result type (might be due to invalid IL or missing references) //IL_038c: Unknown result type (might be due to invalid IL or missing references) //IL_038e: Unknown result type (might be due to invalid IL or missing references) //IL_0393: Unknown result type (might be due to invalid IL or missing references) //IL_03d3: Unknown result type (might be due to invalid IL or missing references) //IL_03dd: Unknown result type (might be due to invalid IL or missing references) //IL_03e2: Unknown result type (might be due to invalid IL or missing references) //IL_03e7: Unknown result type (might be due to invalid IL or missing references) //IL_03ec: Unknown result type (might be due to invalid IL or missing references) //IL_0418: Unknown result type (might be due to invalid IL or missing references) //IL_041d: Unknown result type (might be due to invalid IL or missing references) //IL_0422: Unknown result type (might be due to invalid IL or missing references) //IL_0424: Unknown result type (might be due to invalid IL or missing references) //IL_0438: Unknown result type (might be due to invalid IL or missing references) //IL_043d: Unknown result type (might be due to invalid IL or missing references) //IL_0442: Unknown result type (might be due to invalid IL or missing references) //IL_044a: Unknown result type (might be due to invalid IL or missing references) //IL_0457: Unknown result type (might be due to invalid IL or missing references) //IL_045e: Unknown result type (might be due to invalid IL or missing references) //IL_046e: Unknown result type (might be due to invalid IL or missing references) //IL_0470: Unknown result type (might be due to invalid IL or missing references) //IL_0474: Unknown result type (might be due to invalid IL or missing references) //IL_0479: Unknown result type (might be due to invalid IL or missing references) //IL_047e: 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) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) GameObject val = null; try { GameObject obj = PrefabManager.Instance.GetPrefab(prefabName) ?? Cache.GetPrefab<GameObject>(prefabName); Transform obj2 = ((obj != null) ? obj.transform.Find("model") : null); if ((Object)(object)obj2 == (Object)null) { throw new InvalidOperationException(prefabName + " model prefab is unavailable"); } val = new GameObject(prefabName + "_CarvedWood"); val.transform.SetParent(parent, false); val.SetActive(false); GameObject val2 = Object.Instantiate<GameObject>(((Component)obj2).gameObject, val.transform, false); ((Object)val2).name = prefabName + "_PerchedModel"; Component[] componentsInChildren = val2.GetComponentsInChildren<Component>(true); foreach (Component val3 in componentsInChildren) { if (!(val3 is Transform) && !(val3 is SkinnedMeshRenderer) && !(val3 is Animator)) { Object.DestroyImmediate((Object)(object)val3); } } Animator component = val2.GetComponent<Animator>(); AnimationClip val4 = null; if ((Object)(object)((component != null) ? component.runtimeAnimatorController : null) != (Object)null) { AnimationClip[] animationClips = component.runtimeAnimatorController.animationClips; foreach (AnimationClip val5 in animationClips) { if ((Object)(object)val5 != (Object)null && ((Object)val5).name == "HuginIdle") { val4 = val5; break; } } } if ((Object)(object)val4 == (Object)null) { throw new InvalidOperationException(prefabName + " idle clip is unavailable"); } val.SetActive(true); float num = PickFoldedIdleTime(val2, val.transform, val4); val4.SampleAnimation(val2, num); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } Vector3 val6 = default(Vector3); ((Vector3)(ref val6))..ctor(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); Vector3 val7 = default(Vector3); ((Vector3)(ref val7))..ctor(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); int num2 = 0; SkinnedMeshRenderer[] componentsInChildren2 = val2.GetComponentsInChildren<SkinnedMeshRenderer>(true); foreach (SkinnedMeshRenderer val8 in componentsInChildren2) { Material[] sharedMaterials = ((Renderer)val8).sharedMaterials; Material[] array = (Material[])(object)new Material[Math.Max(1, sharedMaterials.Length)]; for (int j = 0; j < array.Length; j++) { array[j] = GetCarvedRavenMaterial(prefabName, (j < sharedMaterials.Length) ? sharedMaterials[j] : null, grain, logger) ?? fallbackWood; } ((Renderer)val8).sharedMaterials = array; ((Renderer)val8).shadowCastingMode = (ShadowCastingMode)1; ((Renderer)val8).receiveShadows = true; val8.updateWhenOffscreen = true; Mesh sharedMesh = val8.sharedMesh; if ((Object)(object)sharedMesh == (Object)null) { continue; } num2 += sharedMesh.vertexCount; Bounds bounds = sharedMesh.bounds; Matrix4x4 val9 = val.transform.worldToLocalMatrix * ((Component)val8).transform.localToWorldMatrix; for (int k = -1; k <= 1; k += 2) { for (int l = -1; l <= 1; l += 2) { for (int m = -1; m <= 1; m += 2) { Vector3 val10 = ((Bounds)(ref bounds)).center + Vector3.Scale(((Bounds)(ref bounds)).extents, new Vector3((float)k, (float)l, (float)m)); Vector3 val11 = ((Matrix4x4)(ref val9)).MultiplyPoint3x4(val10); val6 = Vector3.Min(val6, val11); val7 = Vector3.Max(val7, val11); } } } } float num3 = val7.y - val6.y; if (num2 < 100 || num3 < 0.05f || num3 > 100f) { throw new InvalidOperationException(prefabName + " mesh could not be measured"); } float num4 = 0.55f / num3; if (num4 < 0.01f || num4 > 20f) { throw new InvalidOperationException($"{prefabName} mesh scale is out of range: {num4}"); } Quaternion val12 = Quaternion.Euler(0f, yaw, 0f); Vector3 val13 = Vector3.zero; int num5 = 0; Transform[] componentsInChildren3 = val2.GetComponentsInChildren<Transform>(true); foreach (Transform val14 in componentsInChildren3) { if (((Object)val14).name == "Mid3.l" || ((Object)val14).name == "Mid3.r") { val13 += val.transform.InverseTransformPoint(val14.position); num5++; } } if (num5 != 2) { throw new InvalidOperationException(prefabName + " toe bones are unavailable"); } val13 /= (float)num5; Vector3 val15 = val13 + new Vector3(0f, 0.015f / num4, 0f); val.transform.localRotation = val12; val.transform.localScale = Vector3.one * num4; val.transform.localPosition = -(val12 * (val15 * num4)); if (logger != null) { logger.LogInfo((object)("Mounted carved " + prefabName + " from the installed game mesh " + $"({num2} vertices, idle t={num:0.00}s, mesh height {num3:0.00} m, " + $"target height {0.55f:0.00} m, scale {num4:0.000}).")); } return true; } catch (Exception ex) { if ((Object)(object)val != (Object)null) { Object.DestroyImmediate((Object)(object)val); } if (logger != null) { logger.LogWarning((object)("Could not mount native " + prefabName + "; keeping authored crow: " + ex.Message)); } return false; } } private static float PickFoldedIdleTime(GameObject model, Transform mount, AnimationClip idle) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_0099: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) if (idle.length <= 0f) { return 0f; } SkinnedMeshRenderer[] componentsInChildren = model.GetComponentsInChildren<SkinnedMeshRenderer>(true); Mesh val = new Mesh(); float result = 0f; float num = float.PositiveInfinity; try { for (int i = 0; i < 24; i++) { float num2 = idle.length * (float)i / 24f; idle.SampleAnimation(model, num2); float num3 = float.PositiveInfinity; float num4 = float.NegativeInfinity; float num5 = float.PositiveInfinity; float num6 = float.NegativeInfinity; SkinnedMeshRenderer[] array = componentsInChildren; foreach (SkinnedMeshRenderer val2 in array) { if (!((Object)(object)val2.sharedMesh == (Object)null)) { val2.BakeMesh(val); Matrix4x4 val3 = mount.worldToLocalMatrix * ((Component)val2).transform.localToWorldMatrix; Vector3[] vertices = val.vertices; for (int k = 0; k < vertices.Length; k += 2) { Vector3 val4 = ((Matrix4x4)(ref val3)).MultiplyPoint3x4(vertices[k]); num3 = Math.Min(num3, val4.x); num4 = Math.Max(num4, val4.x); num5 = Math.Min(num5, val4.y); num6 = Math.Max(num6, val4.y); } } } float num7 = num6 - num5; if (!(num7 <= 0f)) { float num8 = (num4 - num3) / num7; if (!(num8 >= num)) { num = num8; result = num2; } } } return result; } finally { Object.DestroyImmediate((Object)(object)val); } } private static Material? GetCarvedRavenMaterial(string ravenName, Material? native, Texture? grain, ManualLogSource? logger) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)native == (Object)null) && native.HasProperty("_MainTex")) { Texture texture = native.GetTexture("_MainTex"); if (texture != null) { string key = ravenName + "/" + ((Object)native).name; if (CarvedRavenMaterials.TryGetValue(key, out Material value)) { return value; } try { Material val = new Material(native) { name = "Odin_" + ravenName + "_CarvedWood" }; val.SetTexture("_MainTex", (Texture)(object)BuildCarvedAlbedo(texture, grain, ravenName)); if (val.HasProperty("_Color")) { val.SetColor("_Color", Color.white); } if (val.HasProperty("_Metallic")) { val.SetFloat("_Metallic", 0f); } if (val.HasProperty("_Glossiness")) { val.SetFloat("_Glossiness", 0.14f); } if (val.HasProperty("_BumpScale")) { val.SetFloat("_BumpScale", 1.35f); } if (val.HasProperty("_EmissionColor")) { val.SetColor("_EmissionColor", Color.black); } val.DisableKeyword("_EMISSION"); CarvedRavenMaterials.Add(key, val); return val; } catch (Exception ex) { if (logger != null) { logger.LogWarning((object)("Could not carve " + ravenName + " material; using darkwood: " + ex.Message)); } return null; } } } return null; } private static Texture2D BuildCarvedAlbedo(Texture albedo, Texture? grain, string ravenName) { //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_02f8: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Expected O, but got Unknown //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) int width; int height; Color32[] array = ReadPixels(albedo, 1024, out width, out height); Color32[] array2 = null; int width2 = 0; int height2 = 0; float num = 96f; float num2 = 64f; float num3 = 40f; float num4 = 1f; Color32[] array3; if ((Object)(object)grain != (Object)null) { array2 = ReadPixels(grain, 512, out width2, out height2); double num5 = 0.0; double num6 = 0.0; double num7 = 0.0; array3 = array2; foreach (Color32 val in array3) { num5 += (double)(int)val.r; num6 += (double)(int)val.g; num7 += (double)(int)val.b; } num = (float)(num5 / (double)array2.Length); num2 = (float)(num6 / (double)array2.Length); num3 = (float)(num7 / (double)array2.Length); num4 = Math.Max(1f, 0.2126f * num + 0.7152f * num2 + 0.0722f * num3); } int[] array4 = new int[256]; array3 = array; foreach (Color32 p in array3) { array4[Luma(p)]++; } int num8 = Percentile(array4, array.Length, 0.04f); int num9 = Math.Max(num8 + 8, Percentile(array4, array.Length, 0.96f)); Color32[] array5 = (Color32[])(object)new Color32[array.Length]; for (int j = 0; j < height; j++) { for (int k = 0; k < width; k++) { int num10 = j * width + k; float num11 = Mathf.Clamp01((float)(Luma(array[num10]) - num8) / (float)(num9 - num8)); num11 = Mathf.Pow(num11, 0.85f); float num12 = Mathf.Lerp(0.46f, 1.42f, num11); if (array2 != null) { int num13 = (int)((long)k * 3L * width2 / width % width2); int num14 = (int)((long)j * 3L * height2 / height % height2); Color32 val2 = array2[num14 * width2 + num13]; num12 *= Mathf.Clamp((0.2126f * (float)(int)val2.r + 0.7152f * (float)(int)val2.g + 0.0722f * (float)(int)val2.b) / num4, 0.7f, 1.3f); } array5[num10] = new Color32((byte)Mathf.Clamp(num * num12, 0f, 255f), (byte)Mathf.Clamp(num2 * num12, 0f, 255f), (byte)Mathf.Clamp(num3 * num12, 0f, 255f), array[num10].a); } } Texture2D val3 = new Texture2D(width, height, (TextureFormat)4, true) { name = "Odin_" + ravenName + "_CarvedAlbedo", wrapMode = albedo.wrapMode, filterMode = (FilterMode)2, anisoLevel = 4 }; val3.SetPixels32(array5); val3.Apply(true, true); return val3; } private static int Luma(Color32 p) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) return 54 * p.r + 183 * p.g + 19 * p.b >> 8; } private static int Percentile(int[] histogram, int total, float fraction) { int num = (int)((float)total * fraction); int num2 = 0; for (int i = 0; i < histogram.Length; i++) { if ((num2 += histogram[i]) > num) { return i; } } return histogram.Length - 1; } private static Color32[] ReadPixels(Texture texture, int maxSize, out int width, out int height) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_005b: Unknown result type (might be due to invalid IL or missing references) width = Math.Min(texture.width, maxSize); height = Math.Min(texture.height, maxSize); RenderTexture temporary = RenderTexture.GetTemporary(width, height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2); RenderTexture active = RenderTexture.active; Texture2D val = null; try { Graphics.Blit(texture, temporary); RenderTexture.active = temporary; val = new Texture2D(width, height, (TextureFormat)4, false); val.ReadPixels(new Rect(0f, 0f, (float)width, (float)height), 0, 0, false); return val.GetPixels32(); } finally { RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } } } private static BoxCollider AddBox(Transform parent, string name, Vector3 center, Vector3 size, int layer, bool trigger) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name) { layer = layer }; val.transform.SetParent(parent, false); val.transform.localPosition = center; BoxCollider obj = val.AddComponent<BoxCollider>(); obj.size = size; ((Collider)obj).isTrigger = trigger; return obj; } private static void AddRamp(Transform parent, string name, float width, float height, float topDepth, float baseDepth, int layer) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name) { layer = layer }; val.transform.SetParent(parent, false); float num = width * 0.5f; float num2 = topDepth * 0.5f; float num3 = baseDepth * 0.5f; Mesh val2 = new Mesh(); ((Object)val2).name = name; val2.vertices = (Vector3[])(object)new Vector3[8] { new Vector3(0f - num, 0f, 0f - num3), new Vector3(num, 0f, 0f - num3), new Vector3(num, 0f, num3), new Vector3(0f - num, 0f, num3), new Vector3(0f - num, height, 0f - num2), new Vector3(num, height, 0f - num2), new Vector3(num, height, num2), new Vector3(0f - num, height, num2) }; val2.triangles = new int[36] { 0, 1, 2, 0, 2, 3, 4, 6, 5, 4, 7, 6, 0, 4, 5, 0, 5, 1, 2, 6, 7, 2, 7, 3, 3, 7, 4, 3, 4, 0, 1, 5, 6, 1, 6, 2 }; Mesh val3 = val2; val3.RecalculateBounds(); MeshCollider obj = val.AddComponent<MeshCollider>(); obj.convex = true; obj.sharedMesh = val3; } internal static Texture2D? GetRavenEyeMask(string ravenName) { if (RavenEyeMasks.TryGetValue(ravenName, out Texture2D value)) { return value; } try { Material ravenSourceMaterial = GetRavenSourceMaterial(ravenName); if ((Object)(object)ravenSourceMaterial == (Object)null || !ravenSourceMaterial.HasProperty("_EmissionMap")) { return null; } Texture texture = ravenSourceMaterial.GetTexture("_EmissionMap"); Texture2D val = (Texture2D)(object)((texture is Texture2D) ? texture : null); if (val == null) { return null; } Texture2D val2 = MakeGrayscaleMask(val, ravenName); RavenEyeMasks.Add(ravenName, val2); return val2; } catch (Exception ex) { Debug.LogWarning((object)("Could not prepare " + ravenName + " eye mask: " + ex.Message)); } return null; } internal static Material? GetRavenSourceMaterial(string ravenName) { GameObject obj = PrefabManager.Instance.GetPrefab(ravenName) ?? Cache.GetPrefab<GameObject>(ravenName); Transform val = ((obj != null) ? obj.transform.Find("model") : null); if ((Object)(object)val == (Object)null) { return null; } SkinnedMeshRenderer[] componentsInChildren = ((Component)val).GetComponentsInChildren<SkinnedMeshRenderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Material[] sharedMaterials = ((Renderer)componentsInChildren[i]).sharedMaterials; foreach (Material val2 in sharedMaterials) { if ((Object)(object)val2 != (Object)null && val2.HasProperty("_EmissionMap")) { return val2; } } } return null; } private static Texture2D MakeGrayscaleMask(Texture2D source, string ravenName) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) RenderTexture temporary = RenderTexture.GetTemporary(((Texture)source).width, ((Texture)source).height, 0, (RenderTextureFormat)0); RenderTexture active = RenderTexture.active; try { Graphics.Blit((Texture)(object)source, temporary); RenderTexture.active = temporary; Texture2D val = new Texture2D(((Texture)source).width, ((Texture)source).height, (TextureFormat)4, false) { name = "Odin_" + ravenName + "_EyeMask", wrapMode = ((Texture)source).wrapMode, filterMode = ((Texture)source).filterMode }; val.ReadPixels(new Rect(0f, 0f, (float)((Texture)source).width, (float)((Texture)source).height), 0, 0, false); val.Apply(false, false); Color32[] pixels = val.GetPixels32(); for (int i = 0; i < pixels.Length; i++) { byte b = Math.Max(pixels[i].r, Math.Max(pixels[i].g, pixels[i].b)); pixels[i] = new Color32(b, b, b, pixels[i].a); } val.SetPixels32(pixels); val.Apply(false, true); return val; } finally { RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); } } internal static bool IsActiveRunePart(string name) { if (!name.StartsWith("Rune_Wood_Active", StringComparison.Ordinal) && !name.StartsWith("Rune_Stone_Active", StringComparison.Ordinal) && !name.StartsWith("OdinEye_Carving", StringComparison.Ordinal)) { return name.StartsWith("OdinEye_Pupil", StringComparison.Ordinal); } return true; } private static Material FindFrameMaterial(GameObject prefab) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown MeshRenderer[] componentsInChildren = prefab.GetComponentsInChildren<MeshRenderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Material sharedMaterial = ((Renderer)componentsInChildren[i]).sharedMaterial; if ((Object)(object)sharedMaterial != (Object)null && sharedMaterial.renderQueue < 3000) { return sharedMaterial; } } Shader obj = Shader.Find("Standard"); if ((Object)(object)obj == (Object)null) { throw new InvalidOperationException("No usable frame shader found."); } return new Material(obj); } private static Material? FindNativeMaterial(string prefabName, string materialName) { GameObject prefab = PrefabManager.Instance.GetPrefab(prefabName); if ((Object)(object)prefab == (Object)null) { return null; } MeshRenderer[] componentsInChildren = prefab.GetComponentsInChildren<MeshRenderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Material[] sharedMaterials = ((Renderer)componentsInChildren[i]).sharedMaterials; foreach (Material val in sharedMaterials) { if ((Object)(object)val != (Object)null && ((Object)val).name == materialName) { return val; } } } return null; } private static Material GetMaterial(string name, Material donor, Material? nativeWood, Material? nativeStone, Dictionary<string, Material> cache) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_032d: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Unknown result type (might be due to invalid IL or missing references) if (cache.TryGetValue(name, out Material value)) { return value; } bool flag = name.StartsWith("MAT_Wood", StringComparison.Ordinal) || name.StartsWith("MAT_Raven_CarvedWood", StringComparison.Ordinal) || name == "MAT_Rope"; bool flag2 = name.StartsWith("MAT_Stone", StringComparison.Ordinal); object obj = (flag ? (nativeWood ?? donor) : (flag2 ? ((object)(nativeStone ?? donor)) : ((object)donor))); Material val = new Material((Material)obj) { name = "Odin_" + name }; Color value2; Color val2 = ((_colors != null && _colors.TryGetValue(name, out value2)) ? value2 : Color.white); Texture2D val3 = ((flag && (Object)(object)nativeWood == (Object)null) ? _wood : (flag2 ? _stone : null)); if ((Object)(object)val3 != (Object)null) { float num = name switch { "MAT_Rope" => 0.42f, "MAT_Raven_CarvedWood_Cut" => 0.91f, "MAT_Raven_CarvedWood" => 0.59f, "MAT_Stone_Light" => 0.72f, "MAT_Stone_Dark" => 0.46f, "MAT_Wood_Cut" => 1.42f, "MAT_Wood_Worn" => 1.13f, "MAT_Wood_Dark" => 0.55f, _ => flag2 ? 0.58f : 0.92f, }; ((Color)(ref val2))..ctor(num, num, num); } if (val.HasProperty("_MainTex") && ((Object)(object)val3 != (Object)null || (!flag && !flag2))) { val.SetTexture("_MainTex", (Texture)(object)val3); } if ((flag && (Object)(object)nativeWood != (Object)null) || (flag2 && (Object)(object)nativeStone != (Object)null)) { float num2 = name switch { "MAT_Stone_Light" => 0.72f, "MAT_Stone_Dark" => 0.46f, "MAT_Rope" => 0.42f, "MAT_Raven_CarvedWood_Cut" => 1.12f, "MAT_Raven_CarvedWood" => 0.76f, "MAT_Wood_Cut" => 1.32f, "MAT_Wood_Worn" => 1.13f, "MAT_Wood_Dark" => 0.56f, _ => 0.58f, }; ((Color)(ref val2))..ctor(num2, num2, num2); } if (flag2) { if (val.HasProperty("_BumpMap")) { val.SetTexture("_BumpMap", (Texture)null); } if (val.HasProperty("_BumpScale")) { val.SetFloat("_BumpScale", 0f); } if (val.HasProperty("_ValueNoise")) { val.SetFloat("_ValueNoise", 0f); } } if ((Object)obj == (Object)(object)donor) { if (val.HasProperty("_BumpMap")) { val.SetTexture("_BumpMap", (Texture)null); } if (val.HasProperty("_EmissionMap")) { val.SetTexture("_EmissionMap", (Texture)(object)Texture2D.whiteTexture); } } if (val.HasProperty("_Color")) { val.SetColor("_Color", val2); } if (val.HasProperty("_EmissionColor")) { val.SetColor("_EmissionColor", Color.black); } val.DisableKeyword("_EMISSION"); cache.Add(name, val); return val; } private static bool Load(ManualLogSource? logger) { if (_attempted) { return _parts != null; } _attempted = true; try { Assembly assembly = typeof(OdinPortalAsset).Assembly; string text = ReadText(assembly, "Ravengates.Assets.OdinPortal.obj"); string text2 = ReadText(assembly, "Ravengates.Assets.OdinPortal.mtl"); if (text == null || text2 == null) { throw new FileNotFoundException("Embedded Odin OBJ/MTL missing."); } _parts = OdinPortalObjMesh.Build(text); if (_parts.Count == 0) { throw new InvalidDataException("Odin OBJ has no triangles."); } _colors = ParseColors(text2); _wood = ReadTexture(assembly, "Ravengates.Assets.OdinWood.png"); _stone = ReadTexture(assembly, "Ravengates.Assets.OdinStone.png"); if ((Object)(object)_wood == (Object)null || (Object)(object)_stone == (Object)null) { throw new InvalidDataException("Odin textures are missing."); } return true; } catch (Exception arg) { _parts = null; if (logger != null) { logger.LogWarning((object)$"Could not load embedded Odin portal model: {arg}"); } return false; } } private static string? ReadText(Assembly assembly, string resource) { using Stream stream = assembly.GetManifestResourceStream(resource); if (stream == null) { return null; } using StreamReader streamReader = new StreamReader(stream); return streamReader.ReadToEnd(); } private static Texture2D? ReadTexture(Assembly assembly, string resource) { using Stream stream = assembly.GetManifestResourceStream(resource); if (stream == null) { return null; } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); Texture2D obj = AssetUtils.LoadImage(memoryStream.ToArray()); ((Object)obj).name = resource; ((Texture)obj).wrapMode = (TextureWrapMode)0; ((Texture)obj).anisoLevel = 2; return obj; } private static Dictionary<string, Color> ParseColors(string mtl) { //IL_00c2: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, Color> dictionary = new Dictionary<string, Color>(StringComparer.Ordinal); string text = null; string[] array = mtl.Split('\n'); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Trim().Split(new char[3] { ' ', '\t', '\r' }, StringSplitOptions.RemoveEmptyEntries); if (array2.Length >= 2 && array2[0] == "newmtl") { text = array2[1]; } if (text != null && array2.Length >= 4 && !(array2[0] != "Kd") && float.TryParse(array2[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(array2[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && float.TryParse(array2[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3)) { dictionary[text] = new Color(result, result2, result3); } } return dictionary; } } internal sealed class OdinPortalVisual : MonoBehaviour { private const float ActiveDistance = 40f; private static readonly Color HuginEye = new Color(5.2f, 0.06f, 0.02f); private static readonly Color MuninEye = new Color(0.05f, 4.6f, 5.2f); private const float EyeLightRange = 0.45f; private readonly List<(MeshRenderer Renderer, Material[] Dark, Material[] Lit)> _runes = new List<(MeshRenderer, Material[], Material[])>(); private readonly List<(Renderer Renderer, Material[] Dark, Material[] Lit)> _eyes = new List<(Renderer, Material[], Material[])>(); private readonly List<RavenSentinel> _ravens = new List<RavenSentinel>(); private RavenSentinel? _hugin; private RavenSentinel? _munin; private readonly List<Material> _owned = new List<Material>(); private bool _linked; private bool _initialized; private float _phase; private float _reactionEnd = -10f; private static Material? _sharedGlow; private void EnsureRunes() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: 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_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Expected O, but got Unknown //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) if (_initialized) { return; } _initialized = true; _runes.Clear(); _eyes.Clear(); _phase = Mathf.Abs(((Component)this).transform.position.x * 13.1f + ((Component)this).transform.position.z * 7.7f) % 100f; MeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<MeshRenderer>(true); foreach (MeshRenderer val in componentsInChildren) { if (!OdinPortalAsset.IsActiveRunePart(((Object)val).name)) { continue; } Material[] sharedMaterials = ((Renderer)val).sharedMaterials; if (sharedMaterials.Length == 0 || (Object)(object)sharedMaterials[0] == (Object)null) { continue; } if ((Object)(object)_sharedGlow == (Object)null) { _sharedGlow = new Material(sharedMaterials[0]) { name = "Odin_MAT_Rune_Emissive" }; if (_sharedGlow.HasProperty("_MainTex")) { _sharedGlow.SetTexture("_MainTex", (Texture)null); } if (_sharedGlow.HasProperty("_Color")) { _sharedGlow.SetColor("_Color", new Color(0.65f, 0.23f, 0.055f)); } if (_sharedGlow.HasProperty("_EmissionColor")) { _sharedGlow.SetColor("_EmissionColor", new Color(1.9f, 0.55f, 0.09f)); } _sharedGlow.EnableKeyword("_EMISSION"); } Material[] array = (Material[])(object)new Material[sharedMaterials.Length]; for (int j = 0; j < array.Length; j++) { array[j] = _sharedGlow; } _runes.Add((val, sharedMaterials, array)); RavengateRayTracingInterop.MarkNoLightProxy((Renderer)(object)val); } _hugin = AddRaven("Raven_Huginn", "Hugin", RavenRole.WatchesTraveller, HuginEye, 0f, 5f, OdinPortalAsset.HuginReach); _munin = AddRaven("Raven_Muninn", "Munin", RavenRole.WatchesGate, MuninEye, OdinPortalAsset.MuninYaw, 3f, OdinPortalAsset.MuninReach); } private RavenSentinel? AddRaven(string groupName, string ravenName, RavenRole role, Color eyeColor, float restYaw, float restLean, Vector2 reach) { //IL_0024: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) Transform val = ((Component)this).transform.Find(groupName); if ((Object)(object)val == (Object)null) { return null; } List<Material> list = new List<Material>(); RavenSentinel ravenSentinel = new RavenSentinel(val, role, restYaw, restLean, reach, (float)_ravens.Count * 1.37f + _phase) { EyeColor = eyeColor, Eyes = list }; Transform val2 = val.Find(ravenName + "_CarvedWood"); if ((Object)(object)val2 != (Object)null) { ravenSentinel.FindBones(val2); AddNativeEyes(val2, ravenName, eyeColor, list); } else { AddFallbackEyes(val, ravenName, eyeColor, list); } if (list.Count > 0) { ravenSentinel.EyeLight = (((Object)(object)ravenSentinel.Head != (Object)null) ? AddEyeLight(ravenSentinel.Head, Vector3.zero, ravenName, eyeColor) : AddEyeLight(val, Vector3.up * 0.42f, ravenName, eyeColor)); } _owned.AddRange(list); _ravens.Add(ravenSentinel); return ravenSentinel; } private void AddNativeEyes(Transform mount, string ravenName, Color glowColor, List<Material> glows) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) Texture2D ravenEyeMask = OdinPortalAsset.GetRavenEyeMask(ravenName); if ((Object)(object)ravenEyeMask == (Object)null) { return; } SkinnedMeshRenderer[] componentsInChildren = ((Component)mount).GetComponentsInChildren<SkinnedMeshRenderer>(true); foreach (SkinnedMeshRenderer val in componentsInChildren) { Material[] sharedMaterials = ((Renderer)val).sharedMaterials; if (sharedMaterials.Length == 0 || (Object)(object)sharedMaterials[0] == (Object)null) { continue; } Material val2 = sharedMaterials[0]; if (!val2.HasProperty("_EmissionMap")) { Material ravenSourceMaterial = OdinPortalAsset.GetRavenSourceMaterial(ravenName); if ((Object)(object)ravenSourceMaterial == (Object)null) { continue; } val2 = ravenSourceMaterial; } Material val3 = new Material(val2) { name = "Odin_" + ravenName + "_EyeGlow" }; if ((Object)(object)val2 != (Object)(object)sharedMaterials[0]) { if (val3.HasProperty("_MainTex") && sharedMaterials[0].HasProperty("_MainTex")) { val3.SetTexture("_MainTex", sharedMaterials[0].GetTexture("_MainTex")); } if (val3.HasProperty("_BumpMap") && sharedMaterials[0].HasProperty("_BumpMap")) { val3.SetTexture("_BumpMap", sharedMaterials[0].GetTexture("_BumpMap")); } if (val3.HasProperty("_Color") && sharedMaterials[0].HasProperty("_Color")) { val3.SetColor("_Color", sharedMaterials[0].GetColor("_Color")); } if (val3.HasProperty("_MetallicGlossMap")) { val3.SetTexture("_MetallicGlossMap", (Texture)null); } } val3.SetTexture("_EmissionMap", (Texture)(object)ravenEyeMask); val3.SetTextureScale("_EmissionMap", Vector2.one); val3.SetTextureOffset("_EmissionMap", Vector2.zero); if (val3.HasProperty("_EmissionColor")) { val3.SetColor("_EmissionColor", glowColor); } val3.EnableKeyword("_EMISSION"); Material[] array = (Material[])(object)new Material[sharedMaterials.Length]; for (int j = 0; j < array.Length; j++) { array[j] = val3; } _eyes.Add(((Renderer)(object)val, sharedMaterials, array)); glows.Add(val3); RavengateRayTracingInterop.MarkNoLightProxy((Renderer)(object)val); } } private Light AddEyeLight(Transform parent, Vector3 localOffset, string ravenName, Color eyeColor) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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_005c: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Odin_" + ravenName + "_EyeLight"); val.transform.SetParent(parent, false); val.transform.localPosition = localOffset; Light obj = val.AddComponent<Light>(); obj.type = (LightType)2; obj.color = eyeColor / Mathf.Max(eyeColor.r, Mathf.Max(eyeColor.g, eyeColor.b)); obj.range = 0.45f; obj.intensity = 0.55f; obj.shadows = (LightShadows)0; obj.renderMode = (LightRenderMode)1; ((Behaviour)obj).enabled = _linked; return obj; } private void AddFallbackEyes(Transform pivot, string ravenName, Color glowColor, List<Material> glows) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_0096: Unknown result type (might be due to invalid IL or missing references) Material val = null; MeshRenderer[] componentsInChildren = ((Component)pivot).GetComponentsInChildren<MeshRenderer>(true); foreach (MeshRenderer val2 in componentsInChildren) { Material[] sharedMaterials = ((Renderer)val2).sharedMaterials; Material[] array = (Material[])sharedMaterials.Clone(); bool flag = false; for (int j = 0; j < array.Length; j++) { if ((Object)(object)array[j] == (Object)null || !((Object)array[j]).name.Contains("Raven_Eye")) { continue; } if ((Object)(object)val == (Object)null) { val = new Material(array[j]) { name = "Odin_" + ravenName + "_FallbackEyeGlow" }; if (val.HasProperty("_EmissionColor")) { val.SetColor("_EmissionColor", glowColor); } val.EnableKeyword("_EMISSION"); glows.Add(val); } array[j] = val; flag = true; } if (flag) { _eyes.Add(((Renderer)(object)val2, sharedMaterials, array)); RavengateRayTracingInterop.MarkNoLightProxy((Renderer)(object)val2); } } } internal void SetLinked(bool linked) { EnsureRunes(); if (_linked == linked) { return; } _linked = linked; foreach (var rune in _runes) { if ((Object)(object)rune.Renderer != (Object)null) { ((Renderer)rune.Renderer).sharedMaterials = (linked ? rune.Lit : rune.Dark); } } foreach (var eye in _eyes) { if ((Object)(object)eye.Renderer != (Object)null) { eye.Renderer.sharedMaterials = (linked ? eye.Lit : eye.Dark); } } foreach (RavenSentinel raven in _ravens) { if ((Object)(object)raven.EyeLight != (Object)null) { ((Behaviour)raven.EyeLight).enabled = linked; } } } private void Update() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) if (!_initialized || _ravens.Count == 0) { return; } Camera mainCamera = Utils.GetMainCamera(); if ((Object)(object)mainCamera == (Object)null) { return; } Vector3 val = ((Component)mainCamera).transform.position - ((Component)this).transform.position; if (((Vector3)(ref val)).sqrMagnitude > 1600f) { return; } Player localPlayer = Player.m_localPlayer; Vector3? traveller = null; if ((Object)(object)localPlayer != (Object)null && !((Character)localPlayer).IsDead()) { traveller = ((Component)localPlayer).transform.position + Vector3.up * 1.55f; } float time = Time.time; RavenContext context = new RavenContext(((Component)this).transform, _linked, traveller, time < _reactionEnd + 1.8f, time, Time.deltaTime); _hugin?.Tick(in context); _munin?.Tick(in context); if (!_linked) { return; } foreach (RavenSentinel raven in _ravens) { raven.SetEyeGlow(raven.EyeLevel); } } internal void ReactToTeleport() { EnsureRunes(); _reactionEnd = Time.time + 0.42f; } private void OnDestroy() { foreach (Material item in _owned) { if ((Object)(object)item != (Object)null) { Object.Destroy((Object)(object)item); } } _owned.Clear(); } } internal static class PortalAim { private static BaseAI? _current; internal static void Begin(BaseAI ai) { _current = ai; } internal static void End() { _current = null; } internal static Vector3 ApparentPosition(Character target) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) return Apparent(_current, target, ((Component)target).transform.position); } internal static Vector3 ApparentTopPoint(Character target) { //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) return Apparent(_current, target, target.GetTopPoint()); } internal static Vector3 ApparentCenterPoint(Character target) { //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) return Apparent(_current, target, target.GetCenterPoint()); } internal static Vector3 ApparentVelocity(Character target) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) Vector3 velocity = target.GetVelocity(); if (!TryGetMap(_current, target, out var _, out var turn)) { return velocity; } return turn * velocity; } internal static Vector3 Apparent(BaseAI? ai, Character target, Vector3 world) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (!TryGetMap(ai, target, out var toApparent, out var _)) { return world; } return ((Matrix4x4)(ref toApparent)).MultiplyPoint3x4(world); } private static bool TryGetMap(BaseAI? ai, Character target, out Matrix4x4 toApparent, out Quaternion turn) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) toApparent = Matrix4x4.identity; turn = Quaternion.identity; if ((Object)(object)ai == (Object)null || (Object)(object)target == (Object)null || !PortalSense.Enabled || !PortalSense.TryGetView(((Component)ai).transform, target, out Portal portal)) { return false; } PortalTransform transformToPair = portal.GetTransformToPair(); Matrix4x4 val = ValheimPortalMath.ToMatrix(transformToPair); toApparent = ((Matrix4x4)(ref val)).inverse; turn = Quaternion.Inverse(ValheimPortalMath.ToUnity(((PortalTransform)(ref transformToPair)).Rotation)); return true; } } [HarmonyPatch(typeof(MonsterAI), "UpdateAI")] internal static class MonsterAIApparentTargetPatch { private static void Prefix(MonsterAI __instance) { PortalAim.Begin((BaseAI)(object)__instance); } private static void Finalizer() { PortalAim.End(); } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { FieldInfo fieldInfo = AccessTools.Field(typeof(MonsterAI), "m_targetCreature"); MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(Component), "transform"); MethodInfo methodInfo2 = AccessTools.PropertyGetter(typeof(Transform), "position"); Dictionary<MethodInfo, MethodInfo> dictionary = new Dictionary<MethodInfo, MethodInfo> { [AccessTools.Method(typeof(Character), "GetTopPoint", (Type[])null, (Type[])null)] = AccessTools.Method(typeof(PortalAim), "ApparentTopPoint", (Type[])null, (Type[])null), [AccessTools.Method(typeof(Character), "GetCenterPoint", (Type[])null, (Type[])null)] = AccessTools.Method(typeof(PortalAim), "ApparentCenterPoint", (Type[])null, (Type[])null), [AccessTools.Method(typeof(Character), "GetVelocity", (Type[])null, (Type[])null)] = AccessTools.Method(typeof(PortalAim), "ApparentVelocity", (Type[])null, (Type[])null) }; MethodInfo operand = AccessTools.Method(typeof(PortalAim), "ApparentPosition", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(typeof(EffectArea), "IsPointInsideNoMonsterArea", (Type[])null, (Type[])null); List<CodeInstruction> list = new List<CodeInstruction>(instructions); int num = 0; int num2 = 0; while (fieldInfo != null && num2 + 1 < list.Count) { if (!(list[num2].opcode != OpCodes.Ldfld) && object.Equals(list[num2].operand, fieldInfo) && list[num2 + 1].operand is MethodInfo methodInfo4) { MethodInfo value; if (methodInfo4 == methodInfo && num2 + 2 < list.Count && list[num2 + 2].operand is MethodInfo methodInfo5 && methodInfo5 == methodInfo2) { if (num2 + 3 >= list.Count || !(list[num2 + 3].operand is MethodInfo methodInfo6) || !(methodInfo6 == methodInfo3)) { list[num2 + 1].opcode = OpCodes.Call; list[num2 + 1].operand = operand; list[num2 + 2].opcode = OpCodes.Nop; list[num2 + 2].operand = null; num++; } } else if (dictionary.TryGetValue(methodInfo4, out value)) { list[num2 + 1].opcode = OpCodes.Call; list[num2 + 1].operand = value; num++; } } num2++; } if (num == 0) { RavengatesPlugin.LogWarning("MonsterAI.UpdateAI: target reads not found; creatures that sense a target through a Ravengate aim at its real position."); } return list; } } [HarmonyPatch(typeof(Attack), "GetProjectileSpawnPoint")] internal static class AttackProjectileAimPatch { private static void Postfix(ref Vector3 spawnPoint, ref Vector3 aimDir, BaseAI? ___m_baseAI, Humanoid? ___m_character, bool ___m_useCharacterFacing) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)___m_baseAI == (Object)null || (Object)(object)___m_character == (Object)null || ___m_useCharacterFacing) { return; } Character targetCreature = ___m_baseAI.GetTargetCreature(); if (!((Object)(object)targetCreature == (Object)null)) { Vector3 centerPoint = targetCreature.GetCenterPoint(); Vector3 val = PortalAim.Apparent(___m_baseAI, targetCreature, centerPoint); if (!(val == centerPoint)) { Vector3 val2 = val - spawnPoint; Vector3 normalized = ((Vector3)(ref val2)).normalized; aimDir = Vector3.RotateTowards(((Component)___m_character).transform.forward, normalized, MathF.PI / 2f, 1f); } } } } internal static class PortalExposureCatchUp { private const float CatchUpSpeed = 8f; private const float CatchUpSeconds = 1.5f; private static readonly Dictionary<PostProcessingProfile, (float Up, float Down)> Original = new Dictionary<PostProcessingProfile, (float, float)>(); private static float _until; internal static void Begin() { //IL_0045: 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_00a7: 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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) if (!PortalManagerConfig.ExposureCatchUp.Value) { return; } PostProcessingBehaviour[] array = Object.FindObjectsOfType<PostProcessingBehaviour>(); for (int i = 0; i < array.Length; i++) { PostProcessingProfile profile = array[i].profile; if ((Object)(object)profile == (Object)null || !((PostProcessingModel)profile.eyeAdaptation).enabled) { continue; } Settings settings = profile.eyeAdaptation.settings; if (!Original.ContainsKey(profile)) { if (settings.speedUp == 8f && settings.speedDown == 8f) { continue; } Original[profile] = (settings.speedUp, settings.speedDown); } settings.speedUp = Mathf.Max(settings.speedUp, 8f); settings.speedDown = Mathf.Max(settings.speedDown, 8f); profile.eyeAdaptation.settings = settings; } if (Original.Count > 0) { _until = Time.unscaledTime + 1.5f; } } internal static void Tick() { if (Original.Count > 0 && Time.unscaledTime >= _until) { Restore(); } } internal static void Restore() { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) if (Original.Count == 0) { return; } (float, float)? tuple = null; foreach (KeyValuePair<PostProcessingProfile, (float, float)> item in Original) { (float, float) valueOrDefault = tuple.GetValueOrDefault(); if (!tuple.HasValue) { valueOrDefault = item.Value; tuple = valueOrDefault; } if (!((Object)(object)item.Key == (Object)null)) { Settings settings = item.Key.eyeAdaptation.settings; settings.speedUp = item.Value.Item1; settings.speedDown = item.Value.Item2; item.Key.eyeAdaptation.settings = settings; } } PostProcessingBehaviour[] array = Object.FindObjectsOfType<PostProcessingBehaviour>(); for (int i = 0; i < array.Length; i++) { PostProcessingProfile profile = array[i].profile; if (!((Object)(object)profile == (Object)null) && !Original.ContainsKey(profile)) { Settings settings2 = profile.eyeAdaptation.settings; if (settings2.speedUp == 8f && settings2.speedDown == 8f) { settings2.speedUp = tuple.Value.Item1; settings2.speedDown = tuple.Value.Item2; profile.eyeAdaptation.settings = settings2; } } } Original.Clear(); } } internal static class PortalManagerConfig { internal static ConfigEntry<bool> EnableRavengates = null; internal static ConfigEntry<bool> EnablePortalRendering = null; internal static ConfigEntry<bool> EnablePlayerTraversal = null; internal static ConfigEntry<bool> EnableObjectTraversal = null; internal static ConfigEntry<bool> DefaultPortalTravel = null; internal static ConfigEntry<float> ReentryClearance = null; internal static ConfigEntry<KeyboardShortcut> ToggleKey = null; internal static ConfigEntry<float> MenuScale = null; internal static ConfigEntry<bool> AllowCreatureTraversal = null; internal static ConfigEntry<float> MaxCreatureHeight = null; internal static ConfigEntry<float> MaxCreatureWidth = null; internal static ConfigEntry<float> CreatureTraversalCooldown = null; internal static ConfigEntry<float> CreaturePortalSearchRadius = null; internal static ConfigEntry<float> PortalRouteAdvantage = null; internal static ConfigEntry<string> ExcludedCreatures = null; internal static ConfigEntry<bool> AllowVanillaLinks = null; internal static ConfigEntry<bool> ApplyVanillaItemRules = null; internal static ConfigEntry<bool> ReachThroughPortals = null; internal static ConfigEntry<bool> CreaturesSenseThroughPortals = null; internal static ConfigEntry<bool> PortalHearing = null; internal static ConfigEntry<float> PortalHearingMultiplier = null; internal static ConfigEntry<float> PortalHearingMaxRange = null; internal static ConfigEntry<float> PortalHearingDistanceFactor = null; internal static ConfigEntry<bool> AllowTiltedPlacement = null; internal static ConfigEntry<bool> UseVanillaRecipe = null; internal static ConfigEntry<bool> CloseWalledSides = null; internal static ConfigEntry<KeyboardShortcut> TiltKey = null; internal static ConfigEntry<bool> EnableTemporaryLinks = null; internal static ConfigEntry<float> TemporaryLinkSeconds = null; internal static ConfigEntry<RavengateTravellerKinds> OneWayAppliesTo = null; internal static ConfigEntry<float> PortalRenderScale = null; internal static ConfigEntry<int> MaxPortalViews = null; internal static ConfigEntry<float> MinPortalScreenPixels = null; internal static ConfigEntry<float> MaxPortalViewDistance = null; internal static ConfigEntry<bool> AdaptiveQuality = null; internal static ConfigEntry<RavengateCompositeStage> CompositeStage = null; internal static ConfigEntry<bool> WritePortalDepth = null; internal static ConfigEntry<float> CompositeExposure = null; internal static ConfigEntry<bool> ExposureCatchUp = null; internal static ConfigEntry<float> OpeningInset = null; internal static ConfigEntry<bool> EnableVisualStraddling = null; internal static ConfigEntry<bool> EnableAtmosphere = null; internal static ConfigEntry<float> AtmosphereDensity = null; internal static ConfigEntry<bool> EnableClimateSpread = null; internal static ConfigEntry<float> ImpressionGlowDay = null; internal static ConfigEntry<float> ImpressionGlowNight = null; internal static ConfigEntry<bool> EnableFrozenViews = null; internal static ConfigEntry<bool> EnableWeatherSounds = null; internal static ConfigEntry<bool> EnableTransitionEffects = null; internal static ConfigEntry<bool> EnableLightLeakage = null; internal static ConfigEntry<float> LightLeakageIntensity = null; internal static ConfigEntry<float> LightLeakageRange = null; internal static ConfigEntry<bool> EnablePortalTransition = null; internal static ConfigEntry<bool> TransitionRefraction = null; internal static ConfigEntry<bool> TransitionEnvironmentBlend = null; internal static ConfigEntry<bool> TransitionDepthStretch = null; internal static ConfigEntry<bool> TransitionPull = null; internal static ConfigEntry<float> PullDuration = null; internal static ConfigEntry<float> PullStrength = null; internal static ConfigEntry<float> RefractionDuration = null; internal static ConfigEntry<float> RefractionStrength = null; internal static ConfigEntry<float> EnvironmentBlendDuration = null; internal static ConfigEntry<float> DepthStretchDuration = null; internal static ConfigEntry<float> DepthStretchStrength = null; internal static ConfigEntry<bool> EnableGlassEdge = null; internal static ConfigEntry<float> GlassRefraction = null; internal static ConfigEntry<float> GlassHighlight = null; internal static ConfigEntry<bool> DisableForeignCameraComponents = null; internal static ConfigEntry<string> IsolationDisabledKeywords = null; internal static ConfigEntry<string> IsolationWhiteTextures = null; internal static ConfigEntry<string> IsolationBlackTextures = null; internal static ConfigEntry<int> RemoteZoneRadius = null; internal static ConfigEntry<int> MaxRemoteZones = null; internal static ConfigEntry<float> PortalInterestActivationDistance = null; internal static ConfigEntry<float> RemoteUnloadGraceSeconds = null; internal static ConfigEntry<float> DepartedAreaRetainSeconds = null; internal static ConfigEntry<bool> LogStreamingStats = null; private static bool _batching; private static string _excludedSource = string.Empty; private static readonly HashSet<string> ExcludedNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static readonly string[] PresetNames = new string[3] { "Conservative", "Balanced", "High Fidelity" }; private static readonly (float Scale, int Views, float MinPixels, float Distance, int Radius, int Zones, float Activation, float Grace)[] Presets = new(float, int, float, float, int, int, float, float)[3] { (0.5f, 2, 96f, 200f, 0, 49, 72f, 5f), (1f, 4, 64f, 400f, 1, 98, 128f, 10f), (1f, 8, 24f, 500f, 2, 196, 192f, 15f) }; internal static bool IsCreatureTraversalEnabled { get { if (IsEnabled && AllowCreatureTraversal != null) { return AllowCreatureTraversal.Value; } return false; } } internal static bool IsEnabled { get { if (EnableRavengates != null) { return EnableRavengates.Value; } return false; } } internal static bool IsRenderingEnabled { get { if (IsEnabled && EnablePortalRendering != null) { return EnablePortalRendering.Value; } return false; } } internal static bool CanEditServerSettings { get { if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer()) { return true; } try { return SynchronizationManager.Instance.PlayerIsAdmin; } catch { return true; } } } internal static event Action? Changed; internal static void Bind(ConfigFile config) { //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Expected O, but got Unknown EnableRavengates = BindEntry(config, "General", "EnableSeamlessPortals", defaultValue: true, "Master switch for Ravengate pieces (Ravengate_Wood). When off they stay as inert frames: no traversal, views, or remote streaming. Vanilla portals are never affected."); EnablePlayerTraversal = BindEntry(config, "General", "EnablePlayerTraversal", defaultValue: true, "Allow the local player and camera to cross linked Ravengates while the master switch is on."); EnableObjectTraversal = BindEntry(config, "General", "EnableObjectTraversal", defaultValue: true, "Allow dropped and thrown items, projectiles, and other rigidbodies owned by this peer to cross linked Ravengates."); DefaultPortalTravel = BindEntry(config, "General", "DefaultPortalTravel", defaultValue: false, "For this player, Ravengates that follow the default use Valheim's normal loading-screen teleport: no live view, remote streaming or seamless crossing. A gate set Live or classic in the Ravengates list keeps its own setting."); ReentryClearance = BindRange(config, "General", "ReentryClearance", 0.1f, 0.02f, 0.5f, "After emerging from a portal, a return crossing is deferred until the traveller is this far (metres) from the exit plane on either side."); ToggleKey = BindEntry<KeyboardShortcut>(config, "General", "ToggleKey", new KeyboardShortcut((KeyCode)287, Array.Empty<KeyCode>()), "Opens or closes the in-game portal manager while in a world."); TiltKey = BindEntry<KeyboardShortcut>(config, "General", "TiltKey", new KeyboardShortcut((KeyCode)116, Array.Empty<KeyCode>()), "While placing a Ravengate with AllowTiltedPlacement on, tilts it a quarter turn: upright, lying flat (for floors and ceilings), upside down, flat the other way round."); MenuScale = BindRange(config, "General", "MenuScale", 1.5f, 1f, 2f, "Size of the in-game portal manager. It is shrunk further only when it would not fit the screen."); AllowCreatureTraversal = BindEntry(config, "Gameplay", "AllowCreatureTraversal", defaultValue: true, "Allows small enemies and animals to physically pass through connected Ravengates. Off, creatures neither cross nor route toward gates; players, items and projectiles are unaffected.", adminOnly: true); MigrateRenamed<bool>(config, new ConfigDefinition("General", "EnableCreatureTraversal"), AllowCreatureTraversal); MaxCreatureHeight = BindRange(config, "Gameplay", "MaxCreatureHeight", 2.6f, 0.5f, 6f, "Tallest creature collider (metres) that may cross. A creature must also fit the gate's measured opening (about 2.05 x 2.22 m).", adminOnly: true); MaxCreatureWidth = BindRange(config, "Gameplay", "MaxCreatureWidth", 1.8f, 0.2f, 6f, "Widest creature collider (metres) that may cross. A creature must also fit the gate's measured opening.", adminOnly: true); CreatureTraversalCooldown = BindRange(config, "Gameplay", "CreatureTraversalCooldown", 0.75f, 0f, 10f, "After crossing, a creature cannot go back through the exit gate for this many secon