using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; namespace DigitalRuby.ThunderAndLightning { public class LightningBolt { public class LineRendererMesh { private const int defaultListCapacity = 2048; private static readonly Vector2 uv1 = new Vector2(0f, 0f); private static readonly Vector2 uv2 = new Vector2(1f, 0f); private static readonly Vector2 uv3 = new Vector2(0f, 1f); private static readonly Vector2 uv4 = new Vector2(1f, 1f); private readonly List indices = new List(2048); private readonly List vertices = new List(2048); private readonly List lineDirs = new List(2048); private readonly List colors = new List(2048); private readonly List ends = new List(2048); private readonly List texCoordsAndGlowModifiers = new List(2048); private readonly List fadeLifetimes = new List(2048); private const int boundsPadder = 1000000000; private int currentBoundsMinX = 1147483647; private int currentBoundsMinY = 1147483647; private int currentBoundsMinZ = 1147483647; private int currentBoundsMaxX = -1147483648; private int currentBoundsMaxY = -1147483648; private int currentBoundsMaxZ = -1147483648; private Mesh mesh; private MeshFilter meshFilterGlow; private MeshFilter meshFilterBolt; private MeshRenderer meshRendererGlow; private MeshRenderer meshRendererBolt; public GameObject GameObject { get; private set; } public Material MaterialGlow { get { return meshRendererGlow.sharedMaterial; } set { meshRendererGlow.sharedMaterial = value; } } public Material MaterialBolt { get { return meshRendererBolt.sharedMaterial; } set { meshRendererBolt.sharedMaterial = value; } } public MeshRenderer MeshRendererGlow => meshRendererGlow; public MeshRenderer MeshRendererBolt => meshRendererBolt; public int Tag { get; set; } public Action CustomTransform { get; set; } public Transform Transform { get; private set; } public bool Empty => vertices.Count == 0; public LineRendererMesh(LightningBoltDependencies dependencies) { dependencies.ThreadState.AddActionForMainThread(delegate { GameObject = new GameObject("LightningBoltMeshRenderer"); GameObject.SetActive(value: false); this.mesh = new Mesh { name = "ProceduralLightningMesh" }; this.mesh.MarkDynamic(); GameObject gameObject = new GameObject("LightningBoltMeshRendererGlow"); gameObject.transform.parent = GameObject.transform; GameObject gameObject2 = new GameObject("LightningBoltMeshRendererBolt"); gameObject2.transform.parent = GameObject.transform; meshFilterGlow = gameObject.AddComponent(); meshFilterBolt = gameObject2.AddComponent(); MeshFilter meshFilter = meshFilterGlow; Mesh sharedMesh = (meshFilterBolt.sharedMesh = this.mesh); meshFilter.sharedMesh = sharedMesh; meshRendererGlow = gameObject.AddComponent(); meshRendererBolt = gameObject2.AddComponent(); MeshRenderer meshRenderer = meshRendererGlow; ShadowCastingMode shadowCastingMode2 = (meshRendererBolt.shadowCastingMode = ShadowCastingMode.Off); meshRenderer.shadowCastingMode = shadowCastingMode2; MeshRenderer meshRenderer2 = meshRendererGlow; ReflectionProbeUsage reflectionProbeUsage2 = (meshRendererBolt.reflectionProbeUsage = ReflectionProbeUsage.Off); meshRenderer2.reflectionProbeUsage = reflectionProbeUsage2; MeshRenderer meshRenderer3 = meshRendererGlow; LightProbeUsage lightProbeUsage2 = (meshRendererBolt.lightProbeUsage = LightProbeUsage.Off); meshRenderer3.lightProbeUsage = lightProbeUsage2; MeshRenderer meshRenderer4 = meshRendererGlow; bool receiveShadows = (meshRendererBolt.receiveShadows = false); meshRenderer4.receiveShadows = receiveShadows; Transform = GameObject.GetComponent(); }, waitForAction: true); } public void PopulateMesh() { if (vertices.Count == 0) { mesh.Clear(); } else { PopulateMeshInternal(); } } public bool PrepareForLines(int lineCount) { int num = lineCount * 4; if (vertices.Count + num > 64999) { return false; } return true; } public void BeginLine(Vector3 start, Vector3 end, float radius, Color32 color, float colorIntensity, Vector4 fadeLifeTime, float glowWidthModifier, float glowIntensity) { Vector4 dir = end - start; dir.w = radius; AppendLineInternal(ref start, ref end, ref dir, ref dir, ref dir, color, colorIntensity, ref fadeLifeTime, glowWidthModifier, glowIntensity); } public void AppendLine(Vector3 start, Vector3 end, float radius, Color32 color, float colorIntensity, Vector4 fadeLifeTime, float glowWidthModifier, float glowIntensity) { Vector4 dir = end - start; dir.w = radius; Vector4 dirPrev = lineDirs[lineDirs.Count - 3]; Vector4 dirPrev2 = lineDirs[lineDirs.Count - 1]; AppendLineInternal(ref start, ref end, ref dir, ref dirPrev, ref dirPrev2, color, colorIntensity, ref fadeLifeTime, glowWidthModifier, glowIntensity); } public void Reset() { CustomTransform = null; Tag++; GameObject.SetActive(value: false); mesh.Clear(); indices.Clear(); vertices.Clear(); colors.Clear(); lineDirs.Clear(); ends.Clear(); texCoordsAndGlowModifiers.Clear(); fadeLifetimes.Clear(); currentBoundsMaxX = (currentBoundsMaxY = (currentBoundsMaxZ = -1147483648)); currentBoundsMinX = (currentBoundsMinY = (currentBoundsMinZ = 1147483647)); } private void PopulateMeshInternal() { GameObject.SetActive(value: true); mesh.SetVertices(vertices); mesh.SetTangents(lineDirs); mesh.SetColors(colors); mesh.SetUVs(0, texCoordsAndGlowModifiers); mesh.SetUVs(1, fadeLifetimes); mesh.SetNormals(ends); mesh.SetTriangles(indices, 0); Bounds bounds = default(Bounds); Vector3 vector = new Vector3(currentBoundsMinX - 2, currentBoundsMinY - 2, currentBoundsMinZ - 2); Vector3 vector2 = new Vector3(currentBoundsMaxX + 2, currentBoundsMaxY + 2, currentBoundsMaxZ + 2); bounds.center = (vector2 + vector) * 0.5f; bounds.size = (vector2 - vector) * 1.2f; mesh.bounds = bounds; } private void UpdateBounds(ref Vector3 point1, ref Vector3 point2) { int num = (int)point1.x - (int)point2.x; num &= num >> 31; int num2 = (int)point2.x + num; int num3 = (int)point1.x - num; num = currentBoundsMinX - num2; num &= num >> 31; currentBoundsMinX = num2 + num; num = currentBoundsMaxX - num3; num &= num >> 31; currentBoundsMaxX -= num; int num4 = (int)point1.y - (int)point2.y; num4 &= num4 >> 31; int num5 = (int)point2.y + num4; int num6 = (int)point1.y - num4; num4 = currentBoundsMinY - num5; num4 &= num4 >> 31; currentBoundsMinY = num5 + num4; num4 = currentBoundsMaxY - num6; num4 &= num4 >> 31; currentBoundsMaxY -= num4; int num7 = (int)point1.z - (int)point2.z; num7 &= num7 >> 31; int num8 = (int)point2.z + num7; int num9 = (int)point1.z - num7; num7 = currentBoundsMinZ - num8; num7 &= num7 >> 31; currentBoundsMinZ = num8 + num7; num7 = currentBoundsMaxZ - num9; num7 &= num7 >> 31; currentBoundsMaxZ -= num7; } private void AddIndices() { int count = vertices.Count; indices.Add(count++); indices.Add(count++); indices.Add(count); indices.Add(count--); indices.Add(count); indices.Add(count += 2); } private void AppendLineInternal(ref Vector3 start, ref Vector3 end, ref Vector4 dir, ref Vector4 dirPrev1, ref Vector4 dirPrev2, Color32 color, float colorIntensity, ref Vector4 fadeLifeTime, float glowWidthModifier, float glowIntensity) { AddIndices(); color.a = (byte)Mathf.Lerp(0f, 255f, colorIntensity * 0.1f); Vector4 item = new Vector4(uv1.x, uv1.y, glowWidthModifier, glowIntensity); vertices.Add(start); lineDirs.Add(dirPrev1); colors.Add(color); ends.Add(dir); vertices.Add(end); lineDirs.Add(dir); colors.Add(color); ends.Add(dir); dir.w = 0f - dir.w; vertices.Add(start); lineDirs.Add(dirPrev2); colors.Add(color); ends.Add(dir); vertices.Add(end); lineDirs.Add(dir); colors.Add(color); ends.Add(dir); texCoordsAndGlowModifiers.Add(item); item.x = uv2.x; item.y = uv2.y; texCoordsAndGlowModifiers.Add(item); item.x = uv3.x; item.y = uv3.y; texCoordsAndGlowModifiers.Add(item); item.x = uv4.x; item.y = uv4.y; texCoordsAndGlowModifiers.Add(item); fadeLifetimes.Add(fadeLifeTime); fadeLifetimes.Add(fadeLifeTime); fadeLifetimes.Add(fadeLifeTime); fadeLifetimes.Add(fadeLifeTime); UpdateBounds(ref start, ref end); } } public static int MaximumLightCount = 128; public static int MaximumLightsPerBatch = 8; private DateTime startTimeOffset; private LightningBoltDependencies dependencies; private float elapsedTime; private float lifeTime; private float maxLifeTime; private bool hasLight; private float timeSinceLevelLoad; private readonly List segmentGroups = new List(); private readonly List segmentGroupsWithLight = new List(); private readonly List activeLineRenderers = new List(); private static int lightCount; private static readonly List lineRendererCache = new List(); private static readonly List groupCache = new List(); private static readonly List lightCache = new List(); public float MinimumDelay { get; private set; } public bool HasGlow { get; private set; } public bool IsActive => elapsedTime < lifeTime; public CameraMode CameraMode { get; private set; } public void SetupLightningBolt(LightningBoltDependencies dependencies) { if (dependencies == null || dependencies.Parameters.Count == 0) { Debug.LogError("Lightning bolt dependencies must not be null"); return; } if (this.dependencies != null) { Debug.LogError("This lightning bolt is already in use!"); return; } this.dependencies = dependencies; CameraMode = dependencies.CameraMode; timeSinceLevelLoad = LightningBoltScript.TimeSinceStart; CheckForGlow(dependencies.Parameters); MinimumDelay = float.MaxValue; if (dependencies.ThreadState.multiThreaded) { startTimeOffset = DateTime.UtcNow; dependencies.ThreadState.AddActionForBackgroundThread(ProcessAllLightningParameters); } else { ProcessAllLightningParameters(); } } public bool Update() { elapsedTime += LightningBoltScript.DeltaTime; if (elapsedTime > maxLifeTime) { return false; } if (hasLight) { UpdateLights(); } return true; } public void Cleanup() { foreach (LightningBoltSegmentGroup item in segmentGroupsWithLight) { foreach (Light light in item.Lights) { CleanupLight(light); } item.Lights.Clear(); } lock (groupCache) { foreach (LightningBoltSegmentGroup segmentGroup in segmentGroups) { groupCache.Add(segmentGroup); } } hasLight = false; elapsedTime = 0f; lifeTime = 0f; maxLifeTime = 0f; if (dependencies != null) { dependencies.ReturnToCache(dependencies); dependencies = null; } foreach (LineRendererMesh activeLineRenderer in activeLineRenderers) { if (activeLineRenderer != null) { activeLineRenderer.Reset(); lineRendererCache.Add(activeLineRenderer); } } segmentGroups.Clear(); segmentGroupsWithLight.Clear(); activeLineRenderers.Clear(); } public LightningBoltSegmentGroup AddGroup() { LightningBoltSegmentGroup lightningBoltSegmentGroup; lock (groupCache) { if (groupCache.Count == 0) { lightningBoltSegmentGroup = new LightningBoltSegmentGroup(); } else { int index = groupCache.Count - 1; lightningBoltSegmentGroup = groupCache[index]; lightningBoltSegmentGroup.Reset(); groupCache.RemoveAt(index); } } segmentGroups.Add(lightningBoltSegmentGroup); return lightningBoltSegmentGroup; } public static void ClearCache() { foreach (LineRendererMesh item in lineRendererCache) { if (item != null) { UnityEngine.Object.Destroy(item.GameObject); } } foreach (Light item2 in lightCache) { if (item2 != null) { UnityEngine.Object.Destroy(item2.gameObject); } } lineRendererCache.Clear(); lightCache.Clear(); lock (groupCache) { groupCache.Clear(); } } private void CleanupLight(Light l) { if (l != null) { dependencies.LightRemoved(l); lightCache.Add(l); l.gameObject.SetActive(value: false); lightCount--; } } private void EnableLineRenderer(LineRendererMesh lineRenderer, int tag) { if (lineRenderer != null && lineRenderer.GameObject != null && lineRenderer.Tag == tag && IsActive) { lineRenderer.PopulateMesh(); } } private IEnumerator EnableLastRendererCoRoutine() { LineRendererMesh lineRenderer = activeLineRenderers[activeLineRenderers.Count - 1]; int tag = ++lineRenderer.Tag; yield return new WaitForSecondsLightning(MinimumDelay); EnableLineRenderer(lineRenderer, tag); } private LineRendererMesh GetOrCreateLineRenderer() { LineRendererMesh lineRenderer; do { if (lineRendererCache.Count == 0) { lineRenderer = new LineRendererMesh(dependencies); break; } int index = lineRendererCache.Count - 1; lineRenderer = lineRendererCache[index]; lineRendererCache.RemoveAt(index); } while (lineRenderer == null || lineRenderer.Transform == null); dependencies.ThreadState.AddActionForMainThread(delegate { lineRenderer.Transform.parent = null; lineRenderer.Transform.rotation = Quaternion.identity; lineRenderer.Transform.localScale = Vector3.one; lineRenderer.Transform.parent = dependencies.Parent.transform; GameObject gameObject = lineRenderer.GameObject; GameObject gameObject2 = lineRenderer.MeshRendererBolt.gameObject; int num = (lineRenderer.MeshRendererGlow.gameObject.layer = dependencies.Parent.layer); int layer2 = (gameObject2.layer = num); gameObject.layer = layer2; if (dependencies.UseWorldSpace) { lineRenderer.GameObject.transform.position = Vector3.zero; } else { lineRenderer.GameObject.transform.localPosition = Vector3.zero; } lineRenderer.MaterialGlow = dependencies.LightningMaterialMesh; lineRenderer.MaterialBolt = dependencies.LightningMaterialMeshNoGlow; if (!string.IsNullOrEmpty(dependencies.SortLayerName)) { MeshRenderer meshRendererGlow = lineRenderer.MeshRendererGlow; string sortingLayerName = (lineRenderer.MeshRendererBolt.sortingLayerName = dependencies.SortLayerName); meshRendererGlow.sortingLayerName = sortingLayerName; MeshRenderer meshRendererGlow2 = lineRenderer.MeshRendererGlow; layer2 = (lineRenderer.MeshRendererBolt.sortingOrder = dependencies.SortOrderInLayer); meshRendererGlow2.sortingOrder = layer2; } else { MeshRenderer meshRendererGlow3 = lineRenderer.MeshRendererGlow; string sortingLayerName = (lineRenderer.MeshRendererBolt.sortingLayerName = null); meshRendererGlow3.sortingLayerName = sortingLayerName; MeshRenderer meshRendererGlow4 = lineRenderer.MeshRendererGlow; layer2 = (lineRenderer.MeshRendererBolt.sortingOrder = 0); meshRendererGlow4.sortingOrder = layer2; } }, waitForAction: true); activeLineRenderers.Add(lineRenderer); return lineRenderer; } private void RenderGroup(LightningBoltSegmentGroup group, LightningBoltParameters p) { if (group.SegmentCount == 0) { return; } float num = ((!dependencies.ThreadState.multiThreaded) ? 0f : ((float)(DateTime.UtcNow - startTimeOffset).TotalSeconds)); float num2 = timeSinceLevelLoad + group.Delay + num; Vector4 fadeLifeTime = new Vector4(num2, num2 + group.PeakStart, num2 + group.PeakEnd, num2 + group.LifeTime); float num3 = group.LineWidth * 0.5f * LightningBoltParameters.Scale; int num4 = group.Segments.Count - group.StartIndex; float num5 = (num3 - num3 * group.EndWidthMultiplier) / (float)num4; float num6; if (p.GrowthMultiplier > 0f) { num6 = group.LifeTime / (float)num4 * p.GrowthMultiplier; num = 0f; } else { num6 = 0f; num = 0f; } LineRendererMesh currentLineRenderer = ((activeLineRenderers.Count == 0) ? GetOrCreateLineRenderer() : activeLineRenderers[activeLineRenderers.Count - 1]); if (!currentLineRenderer.PrepareForLines(num4)) { if (currentLineRenderer.CustomTransform != null) { return; } if (dependencies.ThreadState.multiThreaded) { dependencies.ThreadState.AddActionForMainThread(delegate(bool inDestroy) { if (!inDestroy) { EnableCurrentLineRenderer(); currentLineRenderer = GetOrCreateLineRenderer(); } }, waitForAction: true); } else { EnableCurrentLineRenderer(); currentLineRenderer = GetOrCreateLineRenderer(); } } currentLineRenderer.BeginLine(group.Segments[group.StartIndex].Start, group.Segments[group.StartIndex].End, num3, group.Color, p.Intensity, fadeLifeTime, p.GlowWidthMultiplier, p.GlowIntensity); for (int i = group.StartIndex + 1; i < group.Segments.Count; i++) { num3 -= num5; if (p.GrowthMultiplier < 1f) { num += num6; fadeLifeTime = new Vector4(num2 + num, num2 + group.PeakStart + num, num2 + group.PeakEnd, num2 + group.LifeTime); } currentLineRenderer.AppendLine(group.Segments[i].Start, group.Segments[i].End, num3, group.Color, p.Intensity, fadeLifeTime, p.GlowWidthMultiplier, p.GlowIntensity); } } private static IEnumerator NotifyBolt(LightningBoltDependencies dependencies, LightningBoltParameters p, Transform transform, Vector3 start, Vector3 end) { float delaySeconds = p.delaySeconds; float lifeTime = p.LifeTime; yield return new WaitForSecondsLightning(delaySeconds); if (dependencies.LightningBoltStarted != null) { dependencies.LightningBoltStarted(p, start, end); } LightningCustomTransformStateInfo state = ((p.CustomTransform == null) ? null : LightningCustomTransformStateInfo.GetOrCreateStateInfo()); if (state != null) { state.Parameters = p; state.BoltStartPosition = start; state.BoltEndPosition = end; state.State = LightningCustomTransformState.Started; state.Transform = transform; p.CustomTransform(state); state.State = LightningCustomTransformState.Executing; } if (p.CustomTransform == null) { yield return new WaitForSecondsLightning(lifeTime); } else { while (lifeTime > 0f) { p.CustomTransform(state); lifeTime -= LightningBoltScript.DeltaTime; yield return null; } } if (p.CustomTransform != null) { state.State = LightningCustomTransformState.Ended; p.CustomTransform(state); LightningCustomTransformStateInfo.ReturnStateInfoToCache(state); } if (dependencies.LightningBoltEnded != null) { dependencies.LightningBoltEnded(p, start, end); } LightningBoltParameters.ReturnParametersToCache(p); } private void ProcessParameters(LightningBoltParameters p, RangeOfFloats delay, LightningBoltDependencies depends) { MinimumDelay = Mathf.Min(delay.Minimum, MinimumDelay); p.delaySeconds = delay.Random(p.Random); if (depends.LevelOfDetailDistance > Mathf.Epsilon) { float num; if (p.Points.Count > 1) { num = Vector3.Distance(depends.CameraPos, p.Points[0]); num = Mathf.Min(Vector3.Distance(depends.CameraPos, p.Points[p.Points.Count - 1])); } else { num = Vector3.Distance(depends.CameraPos, p.Start); num = Mathf.Min(Vector3.Distance(depends.CameraPos, p.End)); } int num2 = Mathf.Min(8, (int)(num / depends.LevelOfDetailDistance)); p.Generations = Mathf.Max(1, p.Generations - num2); p.GenerationWhereForksStopSubtractor = Mathf.Clamp(p.GenerationWhereForksStopSubtractor - num2, 0, 8); } p.generationWhereForksStop = p.Generations - p.GenerationWhereForksStopSubtractor; lifeTime = Mathf.Max(p.LifeTime + p.delaySeconds, lifeTime); maxLifeTime = Mathf.Max(lifeTime, maxLifeTime); p.forkednessCalculated = (int)Mathf.Ceil(p.Forkedness * (float)p.Generations); if (p.Generations > 0) { p.Generator = p.Generator ?? LightningGenerator.GeneratorInstance; p.Generator.GenerateLightningBolt(this, p, out var start, out var end); p.Start = start; p.End = end; } } private void ProcessAllLightningParameters() { int maxLights = MaximumLightsPerBatch / dependencies.Parameters.Count; RangeOfFloats delay = default(RangeOfFloats); List list = new List(dependencies.Parameters.Count + 1); int num = 0; foreach (LightningBoltParameters parameter in dependencies.Parameters) { delay.Minimum = parameter.DelayRange.Minimum + parameter.Delay; delay.Maximum = parameter.DelayRange.Maximum + parameter.Delay; parameter.maxLights = maxLights; list.Add(segmentGroups.Count); ProcessParameters(parameter, delay, dependencies); } list.Add(segmentGroups.Count); LightningBoltDependencies dependenciesRef = dependencies; foreach (LightningBoltParameters parameters in dependenciesRef.Parameters) { Transform transform = RenderLightningBolt(parameters.quality, parameters.Generations, list[num], list[++num], parameters); if (dependenciesRef.ThreadState.multiThreaded) { dependenciesRef.ThreadState.AddActionForMainThread(delegate(bool inDestroy) { if (!inDestroy) { dependenciesRef.StartCoroutine(NotifyBolt(dependenciesRef, parameters, transform, parameters.Start, parameters.End)); } }); } else { dependenciesRef.StartCoroutine(NotifyBolt(dependenciesRef, parameters, transform, parameters.Start, parameters.End)); } } if (dependencies.ThreadState.multiThreaded) { dependencies.ThreadState.AddActionForMainThread(EnableCurrentLineRendererFromThread); return; } EnableCurrentLineRenderer(); dependencies.AddActiveBolt(this); } private void EnableCurrentLineRendererFromThread(bool inDestroy) { if (!inDestroy) { EnableCurrentLineRenderer(); dependencies.AddActiveBolt(this); } } private void EnableCurrentLineRenderer() { if (activeLineRenderers.Count != 0) { if (MinimumDelay <= 0f) { EnableLineRenderer(activeLineRenderers[activeLineRenderers.Count - 1], activeLineRenderers[activeLineRenderers.Count - 1].Tag); } else { dependencies.StartCoroutine(EnableLastRendererCoRoutine()); } } } private void RenderParticleSystems(Vector3 start, Vector3 end, float trunkWidth, float lifeTime, float delaySeconds) { if (trunkWidth > 0f) { if (dependencies.OriginParticleSystem != null) { dependencies.StartCoroutine(GenerateParticleCoRoutine(dependencies.OriginParticleSystem, start, delaySeconds)); } if (dependencies.DestParticleSystem != null) { dependencies.StartCoroutine(GenerateParticleCoRoutine(dependencies.DestParticleSystem, end, delaySeconds + lifeTime * 0.8f)); } } } private Transform RenderLightningBolt(LightningBoltQualitySetting quality, int generations, int startGroupIndex, int endGroupIndex, LightningBoltParameters parameters) { if (segmentGroups.Count == 0 || startGroupIndex >= segmentGroups.Count || endGroupIndex > segmentGroups.Count) { return null; } Transform result = null; LightningLightParameters lp = parameters.LightParameters; if (lp != null) { if (hasLight |= lp.HasLight) { lp.LightPercent = Mathf.Clamp(lp.LightPercent, Mathf.Epsilon, 1f); lp.LightShadowPercent = Mathf.Clamp(lp.LightShadowPercent, 0f, 1f); } else { lp = null; } } LightningBoltSegmentGroup lightningBoltSegmentGroup = segmentGroups[startGroupIndex]; Vector3 start = lightningBoltSegmentGroup.Segments[lightningBoltSegmentGroup.StartIndex].Start; Vector3 end = lightningBoltSegmentGroup.Segments[lightningBoltSegmentGroup.StartIndex + lightningBoltSegmentGroup.SegmentCount - 1].End; parameters.FadePercent = Mathf.Clamp(parameters.FadePercent, 0f, 0.5f); if (parameters.CustomTransform != null) { LineRendererMesh currentLineRenderer = ((activeLineRenderers.Count == 0 || !activeLineRenderers[activeLineRenderers.Count - 1].Empty) ? null : activeLineRenderers[activeLineRenderers.Count - 1]); if (currentLineRenderer == null) { if (dependencies.ThreadState.multiThreaded) { dependencies.ThreadState.AddActionForMainThread(delegate(bool inDestroy) { if (!inDestroy) { EnableCurrentLineRenderer(); currentLineRenderer = GetOrCreateLineRenderer(); } }, waitForAction: true); } else { EnableCurrentLineRenderer(); currentLineRenderer = GetOrCreateLineRenderer(); } } if (currentLineRenderer == null) { return null; } currentLineRenderer.CustomTransform = parameters.CustomTransform; result = currentLineRenderer.Transform; } for (int i = startGroupIndex; i < endGroupIndex; i++) { LightningBoltSegmentGroup lightningBoltSegmentGroup2 = segmentGroups[i]; lightningBoltSegmentGroup2.Delay = parameters.delaySeconds; lightningBoltSegmentGroup2.LifeTime = parameters.LifeTime; lightningBoltSegmentGroup2.PeakStart = lightningBoltSegmentGroup2.LifeTime * parameters.FadePercent; lightningBoltSegmentGroup2.PeakEnd = lightningBoltSegmentGroup2.LifeTime - lightningBoltSegmentGroup2.PeakStart; float num = lightningBoltSegmentGroup2.PeakEnd - lightningBoltSegmentGroup2.PeakStart; float num2 = lightningBoltSegmentGroup2.LifeTime - lightningBoltSegmentGroup2.PeakEnd; lightningBoltSegmentGroup2.PeakStart *= parameters.FadeInMultiplier; lightningBoltSegmentGroup2.PeakEnd = lightningBoltSegmentGroup2.PeakStart + num * parameters.FadeFullyLitMultiplier; lightningBoltSegmentGroup2.LifeTime = lightningBoltSegmentGroup2.PeakEnd + num2 * parameters.FadeOutMultiplier; lightningBoltSegmentGroup2.LightParameters = lp; RenderGroup(lightningBoltSegmentGroup2, parameters); } if (dependencies.ThreadState.multiThreaded) { dependencies.ThreadState.AddActionForMainThread(delegate(bool inDestroy) { if (!inDestroy) { RenderParticleSystems(start, end, parameters.TrunkWidth, parameters.LifeTime, parameters.delaySeconds); if (lp != null) { CreateLightsForGroup(segmentGroups[startGroupIndex], lp, quality, parameters.maxLights); } } }); } else { RenderParticleSystems(start, end, parameters.TrunkWidth, parameters.LifeTime, parameters.delaySeconds); if (lp != null) { CreateLightsForGroup(segmentGroups[startGroupIndex], lp, quality, parameters.maxLights); } } return result; } private void CreateLightsForGroup(LightningBoltSegmentGroup group, LightningLightParameters lp, LightningBoltQualitySetting quality, int maxLights) { if (lightCount == MaximumLightCount || maxLights <= 0) { return; } float num = (lifeTime - group.PeakEnd) * lp.FadeOutMultiplier; float num2 = (group.PeakEnd - group.PeakStart) * lp.FadeFullyLitMultiplier; float num3 = group.PeakStart * lp.FadeInMultiplier + num2 + num; maxLifeTime = Mathf.Max(maxLifeTime, group.Delay + num3); segmentGroupsWithLight.Add(group); int segmentCount = group.SegmentCount; float num4; float num5; if (quality == LightningBoltQualitySetting.LimitToQualitySetting) { int qualityLevel = QualitySettings.GetQualityLevel(); if (LightningBoltParameters.QualityMaximums.TryGetValue(qualityLevel, out var value)) { num4 = Mathf.Min(lp.LightPercent, value.MaximumLightPercent); num5 = Mathf.Min(lp.LightShadowPercent, value.MaximumShadowPercent); } else { Debug.LogError("Unable to read lightning quality for level " + qualityLevel); num4 = lp.LightPercent; num5 = lp.LightShadowPercent; } } else { num4 = lp.LightPercent; num5 = lp.LightShadowPercent; } maxLights = Mathf.Max(1, Mathf.Min(maxLights, (int)((float)segmentCount * num4))); int num6 = Mathf.Max(1, segmentCount / maxLights); int num7 = maxLights - (int)((float)maxLights * num5); int nthShadowCounter = num7; for (int i = group.StartIndex + (int)((float)num6 * 0.5f); i < group.Segments.Count && !AddLightToGroup(group, lp, i, num6, num7, ref maxLights, ref nthShadowCounter); i += num6) { } } private bool AddLightToGroup(LightningBoltSegmentGroup group, LightningLightParameters lp, int segmentIndex, int nthLight, int nthShadows, ref int maxLights, ref int nthShadowCounter) { Light orCreateLight = GetOrCreateLight(lp); group.Lights.Add(orCreateLight); Vector3 vector = (group.Segments[segmentIndex].Start + group.Segments[segmentIndex].End) * 0.5f; if (dependencies.CameraIsOrthographic) { if (dependencies.CameraMode == CameraMode.OrthographicXZ) { vector.y = dependencies.CameraPos.y + lp.OrthographicOffset; } else { vector.z = dependencies.CameraPos.z + lp.OrthographicOffset; } } if (dependencies.UseWorldSpace) { orCreateLight.gameObject.transform.position = vector; } else { orCreateLight.gameObject.transform.localPosition = vector; } if (lp.LightShadowPercent == 0f || ++nthShadowCounter < nthShadows) { orCreateLight.shadows = LightShadows.None; } else { orCreateLight.shadows = LightShadows.Soft; nthShadowCounter = 0; } if (++lightCount != MaximumLightCount) { return --maxLights == 0; } return true; } private Light GetOrCreateLight(LightningLightParameters lp) { Light light; do { if (lightCache.Count == 0) { light = new GameObject("LightningBoltLight").AddComponent(); light.type = LightType.Point; break; } light = lightCache[lightCache.Count - 1]; lightCache.RemoveAt(lightCache.Count - 1); } while (light == null); light.bounceIntensity = lp.BounceIntensity; light.shadowNormalBias = lp.ShadowNormalBias; light.color = lp.LightColor; light.renderMode = lp.RenderMode; light.range = lp.LightRange; light.shadowStrength = lp.ShadowStrength; light.shadowBias = lp.ShadowBias; light.intensity = 0f; light.gameObject.transform.parent = dependencies.Parent.transform; light.gameObject.SetActive(value: true); dependencies.LightAdded(light); return light; } private void UpdateLight(LightningLightParameters lp, IEnumerable lights, float delay, float peakStart, float peakEnd, float lifeTime) { if (elapsedTime < delay) { return; } float num = (lifeTime - peakEnd) * lp.FadeOutMultiplier; float num2 = (peakEnd - peakStart) * lp.FadeFullyLitMultiplier; peakStart *= lp.FadeInMultiplier; peakEnd = peakStart + num2; lifeTime = peakEnd + num; float num3 = elapsedTime - delay; if (num3 >= peakStart) { if (num3 <= peakEnd) { foreach (Light light in lights) { light.intensity = lp.LightIntensity * lp.LightMultiplier; } return; } float t = (num3 - peakEnd) / (lifeTime - peakEnd); { foreach (Light light2 in lights) { light2.intensity = Mathf.Lerp(lp.LightIntensity * lp.LightMultiplier, 0f, t); } return; } } float t2 = num3 / peakStart; foreach (Light light3 in lights) { light3.intensity = Mathf.Lerp(0f, lp.LightIntensity * lp.LightMultiplier, t2); } } private void UpdateLights() { foreach (LightningBoltSegmentGroup item in segmentGroupsWithLight) { UpdateLight(item.LightParameters, item.Lights, item.Delay, item.PeakStart, item.PeakEnd, item.LifeTime); } } private IEnumerator GenerateParticleCoRoutine(ParticleSystem p, Vector3 pos, float delay) { yield return new WaitForSecondsLightning(delay); p.transform.position = pos; if (p.emission.burstCount > 0) { ParticleSystem.Burst[] array = new ParticleSystem.Burst[p.emission.burstCount]; p.emission.GetBursts(array); int count = UnityEngine.Random.Range(array[0].minCount, array[0].maxCount + 1); p.Emit(count); } else { ParticleSystem.MinMaxCurve rateOverTime = p.emission.rateOverTime; int count = (int)((rateOverTime.constantMax - rateOverTime.constantMin) * 0.5f); count = UnityEngine.Random.Range(count, count * 2); p.Emit(count); } } private void CheckForGlow(IEnumerable parameters) { foreach (LightningBoltParameters parameter in parameters) { HasGlow = parameter.GlowIntensity >= Mathf.Epsilon && parameter.GlowWidthMultiplier >= Mathf.Epsilon; if (HasGlow) { break; } } } } }