using System; using System.Collections.Generic; using UnityEngine; public class LightSource : MonoBehaviour { public static Dictionary NoShadows = new Dictionary(); public static Dictionary OneWayShadows = new Dictionary(); [HideInInspector] private GameObject child; [HideInInspector] private Vector2[] requiredDels; [HideInInspector] private Mesh myMesh; public int MinRays = 24; public float LightRadius = 3f; public Material Material; [HideInInspector] private List verts = new List(256); [HideInInspector] private int vertCount; private RaycastHit2D[] buffer = new RaycastHit2D[25]; private Collider2D[] hits = new Collider2D[40]; private ContactFilter2D filter; private Vector3[] vec; private Vector2[] uvs; private int[] triangles = new int[1200]; public float tol = 0.05f; private Vector2 del; private Vector2 tan; private Vector2 side; private List lightHits = new List(); private class VertInfo { public float Angle; public Vector3 Position; internal void Complete(float x, float y) { this.Position.x = x; this.Position.y = y; this.Angle = LightSource.pseudoAngle(y, x); } internal void Complete(Vector2 point) { this.Position.x = point.x; this.Position.y = point.y; this.Angle = LightSource.pseudoAngle(point.y, point.x); } } private class AngleComparer : IComparer { public static readonly LightSource.AngleComparer Instance = new LightSource.AngleComparer(); public int Compare(LightSource.VertInfo x, LightSource.VertInfo y) { if (x.Angle > y.Angle) { return 1; } if (x.Angle >= y.Angle) { return 0; } return -1; } } private class HitDepthComparer : IComparer { public static readonly LightSource.HitDepthComparer Instance = new LightSource.HitDepthComparer(); public int Compare(RaycastHit2D x, RaycastHit2D y) { if (x.fraction <= y.fraction) { return -1; } return 1; } } private void Start() { this.filter.useTriggers = true; this.filter.layerMask = Constants.ShadowMask; this.filter.useLayerMask = true; this.requiredDels = new Vector2[this.MinRays]; for (int i = 0; i < this.requiredDels.Length; i++) { this.requiredDels[i] = Vector2.left.Rotate((float)i / (float)this.requiredDels.Length * 360f); } this.myMesh = new Mesh(); this.myMesh.MarkDynamic(); this.myMesh.name = "ShadowMesh"; GameObject gameObject = new GameObject("LightChild"); gameObject.layer = 10; gameObject.AddComponent().mesh = this.myMesh; Renderer renderer = gameObject.AddComponent(); this.Material = new Material(this.Material); renderer.sharedMaterial = this.Material; this.child = gameObject; } private void Update() { this.vertCount = 0; Vector3 position = base.transform.position; position.z -= 7f; this.child.transform.position = position; Vector2 vector = position; this.Material.SetFloat("_LightRadius", this.LightRadius); int num = Physics2D.OverlapCircleNonAlloc(vector, this.LightRadius, this.hits, Constants.ShadowMask); for (int i = 0; i < num; i++) { Collider2D collider2D = this.hits[i]; if (!collider2D.isTrigger) { EdgeCollider2D edgeCollider2D = collider2D as EdgeCollider2D; if (edgeCollider2D) { Vector2[] points = edgeCollider2D.points; for (int j = 0; j < points.Length; j++) { Vector2 vector2 = edgeCollider2D.transform.TransformPoint(points[j]); this.del.x = vector2.x - vector.x; this.del.y = vector2.y - vector.y; this.TestBothSides(vector); } } else { PolygonCollider2D polygonCollider2D = collider2D as PolygonCollider2D; if (polygonCollider2D) { Vector2[] points2 = polygonCollider2D.points; for (int k = 0; k < points2.Length; k++) { Vector2 vector3 = polygonCollider2D.transform.TransformPoint(points2[k]); this.del.x = vector3.x - vector.x; this.del.y = vector3.y - vector.y; this.TestBothSides(vector); } } else { BoxCollider2D boxCollider2D = collider2D as BoxCollider2D; if (boxCollider2D) { Vector2 b = boxCollider2D.size / 2f; Vector2 vector4 = boxCollider2D.transform.TransformPoint(boxCollider2D.offset - b) - vector; Vector2 vector5 = boxCollider2D.transform.TransformPoint(boxCollider2D.offset + b) - vector; this.del.x = vector4.x; this.del.y = vector4.y; this.TestBothSides(vector); this.del.x = vector5.x; this.TestBothSides(vector); this.del.y = vector5.y; this.TestBothSides(vector); this.del.x = vector4.x; this.TestBothSides(vector); } } } } } float d = this.LightRadius * 1.05f; for (int l = 0; l < this.requiredDels.Length; l++) { Vector2 vector6 = d * this.requiredDels[l]; this.CreateVert(vector, ref vector6); } this.verts.Sort(0, this.vertCount, LightSource.AngleComparer.Instance); this.myMesh.Clear(); if (this.vec == null || this.vec.Length < this.vertCount + 1) { this.vec = new Vector3[this.vertCount + 1]; this.uvs = new Vector2[this.vec.Length]; } this.vec[0] = Vector3.zero; this.uvs[0] = new Vector2(this.vec[0].x, this.vec[0].y); for (int m = 0; m < this.vertCount; m++) { int num2 = m + 1; this.vec[num2] = this.verts[m].Position; this.uvs[num2] = new Vector2(this.vec[num2].x, this.vec[num2].y); } int num3 = this.vertCount * 3; if (num3 > this.triangles.Length) { this.triangles = new int[num3]; Debug.LogWarning("Resized triangles to: " + num3); } int num4 = 0; for (int n = 0; n < this.triangles.Length; n += 3) { if (n < num3) { this.triangles[n] = 0; this.triangles[n + 1] = num4 + 1; if (n == num3 - 3) { this.triangles[n + 2] = 1; } else { this.triangles[n + 2] = num4 + 2; } num4++; } else { this.triangles[n] = 0; this.triangles[n + 1] = 0; this.triangles[n + 2] = 0; } } this.myMesh.vertices = this.vec; this.myMesh.uv = this.uvs; this.myMesh.SetIndices(this.triangles, MeshTopology.Triangles, 0); } private void TestBothSides(Vector2 myPos) { float num = LightSource.length(this.del.x, this.del.x); this.tan.x = -this.del.y / num * this.tol; this.tan.y = this.del.x / num * this.tol; this.side.x = this.del.x + this.tan.x; this.side.y = this.del.y + this.tan.y; this.CreateVert(myPos, ref this.side); this.side.x = this.del.x - this.tan.x; this.side.y = this.del.y - this.tan.y; this.CreateVert(myPos, ref this.side); } private void CreateVert(Vector2 myPos, ref Vector2 del) { float num = this.LightRadius * 1.5f; int num2 = Physics2D.Raycast(myPos, del, this.filter, this.buffer, num); if (num2 > 0) { this.lightHits.Clear(); RaycastHit2D raycastHit2D = default(RaycastHit2D); Collider2D collider2D = null; for (int i = 0; i < num2; i++) { RaycastHit2D raycastHit2D2 = this.buffer[i]; Collider2D collider = raycastHit2D2.collider; OneWayShadows oneWayShadows; if (!LightSource.OneWayShadows.TryGetValue(collider.gameObject, out oneWayShadows) || !oneWayShadows.IsIgnored(this)) { this.lightHits.Add(raycastHit2D2); if (!collider.isTrigger) { raycastHit2D = raycastHit2D2; collider2D = collider; break; } } } for (int j = 0; j < this.lightHits.Count; j++) { NoShadowBehaviour noShadowBehaviour; if (LightSource.NoShadows.TryGetValue(this.lightHits[j].collider.gameObject, out noShadowBehaviour)) { noShadowBehaviour.didHit = true; } } if (collider2D && !collider2D.isTrigger) { Vector2 point = raycastHit2D.point; this.GetEmptyVert().Complete(point.x - myPos.x, point.y - myPos.y); return; } } Vector2 normalized = del.normalized; this.GetEmptyVert().Complete(normalized.x * num, normalized.y * num); } private LightSource.VertInfo GetEmptyVert() { if (this.vertCount < this.verts.Count) { List list = this.verts; int num = this.vertCount; this.vertCount = num + 1; return list[num]; } LightSource.VertInfo vertInfo = new LightSource.VertInfo(); this.verts.Add(vertInfo); this.vertCount = this.verts.Count; return vertInfo; } private static float length(float x, float y) { return Mathf.Sqrt(x * x + y * y); } public static float pseudoAngle(float dx, float dy) { if (dx < 0f) { float num = -dx; float num2 = (dy > 0f) ? dy : (-dy); return 2f - dy / (num + num2); } float num3 = (dy > 0f) ? dy : (-dy); return dy / (dx + num3); } }