1+ using Celeste . Mod . Helpers ;
12using Mono . Cecil . Cil ;
23using MonoMod . Cil ;
34using System . Collections ;
5+ using System . Collections . Generic ;
46using System . Linq ;
57using System . Reflection ;
68
@@ -9,14 +11,18 @@ namespace Celeste.Mod.CommunalHelper.Entities;
911[ CustomEntity ( "CommunalHelper/GlowController" ) ]
1012public class GlowController : Entity
1113{
14+ #region Hooks
15+
1216 public static void Load ( )
1317 {
1418 IL . Celeste . LightingRenderer . BeforeRender += IL_LightingRenderer_BeforeRender ;
19+ IL . Monocle . EntityList . UpdateLists += IL_EntityList_UpdateLists ;
1520 }
1621
1722 public static void Unload ( )
1823 {
1924 IL . Celeste . LightingRenderer . BeforeRender -= IL_LightingRenderer_BeforeRender ;
25+ IL . Monocle . EntityList . UpdateLists -= IL_EntityList_UpdateLists ;
2026 }
2127
2228 private static void IL_LightingRenderer_BeforeRender ( ILContext il )
@@ -39,6 +45,49 @@ private static void IL_LightingRenderer_BeforeRender(ILContext il)
3945 }
4046 } ) ;
4147 }
48+
49+ private static void IL_EntityList_UpdateLists ( ILContext il )
50+ {
51+ ILCursor cursor = new ( il ) ;
52+
53+ if ( ! cursor . TryGotoNextBestFit ( MoveType . Before ,
54+ instr => instr . MatchLdarg ( 0 ) ,
55+ instr => instr . MatchLdfld < EntityList > ( "toAwake" ) ,
56+ instr => instr . MatchCallvirt < List < Entity > > ( "GetEnumerator" ) ,
57+ instr => instr . MatchStloc ( 4 ) ) )
58+ return ;
59+
60+ VariableDefinition allGlowControllers = new ( il . Import ( typeof ( GlowController [ ] ) ) ) ;
61+ il . Body . Variables . Add ( allGlowControllers ) ;
62+
63+ cursor . Emit ( OpCodes . Ldarg_0 ) ;
64+ cursor . EmitDelegate < Func < EntityList , GlowController [ ] > > ( entityList =>
65+ {
66+ // not sure whether the tracker will work here so doing this just in case
67+ IEnumerable < Entity > allEntities = entityList . Concat ( entityList . ToAdd ) ;
68+ return allEntities . Where ( entity => entity is GlowController )
69+ . Cast < GlowController > ( )
70+ . ToArray ( ) ;
71+ } ) ;
72+ cursor . Emit ( OpCodes . Stloc , allGlowControllers ) ;
73+
74+ if ( ! cursor . TryGotoNextBestFit ( MoveType . After ,
75+ instr => instr . MatchLdloc ( 5 ) ,
76+ instr => instr . MatchLdarg ( 0 ) ,
77+ instr => instr . MatchCallvirt < EntityList > ( "get_Scene" ) ,
78+ instr => instr . MatchCallvirt < Entity > ( "Awake" ) ) )
79+ return ;
80+
81+ cursor . Emit ( OpCodes . Ldloc , 5 ) ;
82+ cursor . Emit ( OpCodes . Ldloc , allGlowControllers ) ;
83+ cursor . EmitDelegate < Action < Entity , GlowController [ ] > > ( ( entity , glowControllers ) =>
84+ {
85+ foreach ( GlowController controller in glowControllers )
86+ controller . Process ( entity ) ;
87+ } ) ;
88+ }
89+
90+ #endregion
4291
4392 private readonly string [ ] lightWhitelist ;
4493 private readonly string [ ] lightBlacklist ;
@@ -79,44 +128,39 @@ public GlowController(EntityData data, Vector2 offset)
79128 respawnAnimationIds = data . Attr ( "respawnAnimationIds" , "respawn" ) . Split ( ',' ) ;
80129 }
81130
82- public override void Awake ( Scene scene )
131+ private void Process ( Entity entity )
83132 {
84- base . Awake ( scene ) ;
85- var allEntities = scene . Entities . Concat ( scene . Entities . ToAdd ) ;
86- foreach ( var entity in allEntities )
87- {
88- var type = entity . GetType ( ) ;
89- var typeName = type . FullName ;
90- var requiresRemovalRoutine = false ;
133+ var type = entity . GetType ( ) ;
134+ var typeName = type . FullName ;
135+ var requiresRemovalRoutine = false ;
91136
92- if ( lightBlacklist . Contains ( typeName ) )
93- {
94- entity . Remove ( entity . Components . GetAll < VertexLight > ( ) . ToArray < Component > ( ) ) ;
95- }
96- if ( lightWhitelist . Contains ( typeName ) )
97- {
98- entity . Add ( new VertexLight ( lightOffset , lightColor , lightAlpha , lightStartFade , lightEndFade ) ) ;
99- requiresRemovalRoutine = true ;
100- }
137+ if ( lightBlacklist . Contains ( typeName ) )
138+ {
139+ entity . Remove ( entity . Components . GetAll < VertexLight > ( ) . ToArray < Component > ( ) ) ;
140+ }
141+ if ( lightWhitelist . Contains ( typeName ) )
142+ {
143+ entity . Add ( new VertexLight ( lightOffset , lightColor , lightAlpha , lightStartFade , lightEndFade ) ) ;
144+ requiresRemovalRoutine = true ;
145+ }
101146
102- if ( bloomBlacklist . Contains ( typeName ) )
103- {
104- entity . Remove ( entity . Components . GetAll < BloomPoint > ( ) . ToArray < Component > ( ) ) ;
105- entity . Remove ( entity . Components . GetAll < CustomBloom > ( ) . ToArray < Component > ( ) ) ;
106- }
107- if ( bloomWhitelist . Contains ( typeName ) )
108- {
109- entity . Add ( new BloomPoint ( bloomOffset , bloomAlpha , bloomRadius ) ) ;
110- requiresRemovalRoutine = true ;
111- }
147+ if ( bloomBlacklist . Contains ( typeName ) )
148+ {
149+ entity . Remove ( entity . Components . GetAll < BloomPoint > ( ) . ToArray < Component > ( ) ) ;
150+ entity . Remove ( entity . Components . GetAll < CustomBloom > ( ) . ToArray < Component > ( ) ) ;
151+ }
152+ if ( bloomWhitelist . Contains ( typeName ) )
153+ {
154+ entity . Add ( new BloomPoint ( bloomOffset , bloomAlpha , bloomRadius ) ) ;
155+ requiresRemovalRoutine = true ;
156+ }
112157
113- // some entities get a special coroutine that hides lights and blooms
114- // if it's a glider or otherwise has a sprite with an animation id contained in `deathAnimationIds`
115- if ( requiresRemovalRoutine &&
116- entity . Components . GetAll < Sprite > ( ) . FirstOrDefault ( s => deathAnimationIds . Any ( s . Has ) ) is { } sprite )
117- {
118- entity . Add ( new Coroutine ( DeathRemovalRoutine ( entity , sprite ) ) ) ;
119- }
158+ // some entities get a special coroutine that hides lights and blooms
159+ // if it's a glider or otherwise has a sprite with an animation id contained in `deathAnimationIds`
160+ if ( requiresRemovalRoutine &&
161+ entity . Components . GetAll < Sprite > ( ) . FirstOrDefault ( s => deathAnimationIds . Any ( s . Has ) ) is { } sprite )
162+ {
163+ entity . Add ( new Coroutine ( DeathRemovalRoutine ( entity , sprite ) ) ) ;
120164 }
121165 }
122166
0 commit comments