1414import java .io .OutputStream ;
1515import java .net .Socket ;
1616import java .nio .charset .StandardCharsets ;
17+ import java .util .HashSet ;
18+ import java .util .Objects ;
19+ import java .util .Set ;
1720import java .util .concurrent .Executor ;
21+ import java .util .function .Predicate ;
1822
1923/**
2024 * Processes incoming requests from a Crowd Control socket and executes them.
@@ -27,6 +31,8 @@ final class EffectExecutor {
2731 private final InputStream input ;
2832 private final RequestManager crowdControl ;
2933 private final @ Nullable String password ;
34+ private final @ NotNull Set <@ NotNull Id > notVisible = new HashSet <>();
35+ private final @ NotNull Set <@ NotNull Id > notSelectable = new HashSet <>();
3036 private boolean loggedIn = false ;
3137 private Request .@ Nullable Source player = null ;
3238
@@ -132,7 +138,79 @@ boolean isClosed() {
132138 return socket .isClosed () || !socket .isConnected () || socket .isOutputShutdown ();
133139 }
134140
141+ @ Nullable
142+ private Response update (@ NotNull Response response ) {
143+ // determine if this response should be sent
144+ if (response .getPacketType () == Response .PacketType .EFFECT_STATUS ) {
145+ // create variables
146+ Response .Builder builder = response .toBuilder ();
147+ // get variables
148+ IdType type = builder .idType ();
149+ // create filter to remove IDs whose state has not changed
150+ // (return true to remove, i.e. the ID is already in the set, and false to keep)
151+ // TODO: this is so verbose
152+ Predicate <Id > idFilter ;
153+ switch (Objects .requireNonNull (builder .type (), "Result type cannot be null" )) {
154+ case VISIBLE :
155+ idFilter = id -> {
156+ if (notVisible .contains (id )) {
157+ notVisible .remove (id );
158+ return false ;
159+ }
160+ return true ;
161+ };
162+ break ;
163+ case NOT_VISIBLE :
164+ idFilter = id -> {
165+ if (!notVisible .contains (id )) {
166+ notVisible .add (id );
167+ return false ;
168+ }
169+ return true ;
170+ };
171+ break ;
172+ case SELECTABLE :
173+ idFilter = id -> {
174+ if (notSelectable .contains (id )) {
175+ notSelectable .remove (id );
176+ return false ;
177+ }
178+ return true ;
179+ };
180+ break ;
181+ case NOT_SELECTABLE :
182+ idFilter = id -> {
183+ if (!notSelectable .contains (id )) {
184+ notSelectable .add (id );
185+ return false ;
186+ }
187+ return true ;
188+ };
189+ break ;
190+ default :
191+ idFilter = id -> false ;
192+ }
193+ // filter IDs
194+ builder .ids ().removeIf (id -> idFilter .test (new Id (id , type )));
195+ // rebuild
196+ try {
197+ return builder .build ();
198+ } catch (Exception e ) {
199+ // there were probably no IDs left, it's fine
200+ logger .debug ("Failed to rebuild response" , e );
201+ return null ;
202+ }
203+ }
204+ return response ;
205+ }
206+
135207 void write (@ NotNull Response response ) throws IOException {
208+ // update response
209+ response = update (response );
210+ if (response == null )
211+ return ;
212+
213+ // send response
136214 String json = response .toJSON ();
137215 logger .debug ("Sending response to client: " + json );
138216 synchronized (socket ) {
0 commit comments