2121import com .minecrafttas .tasmod .networking .TASmodBufferBuilder ;
2222import com .minecrafttas .tasmod .registries .TASmodPackets ;
2323import com .minecrafttas .tasmod .savestates .exceptions .SavestateException ;
24- import com .minecrafttas .tasmod .util .Ducks .ResourcePackRepositoryDuck ;
2524import com .minecrafttas .tasmod .util .LoggerMarkers ;
2625
26+ import net .fabricmc .api .EnvType ;
27+ import net .fabricmc .api .Environment ;
2728import net .minecraft .client .Minecraft ;
2829import net .minecraft .entity .player .EntityPlayerMP ;
2930import net .minecraft .server .MinecraftServer ;
3031
32+ /**
33+ * Handles reloading server resourcepacks when loadstating.
34+ *
35+ * @author Scribble
36+ */
3137public class SavestateResourcePackHandler implements EventSavestate .EventServerLoadstate , ServerPacketHandler , ClientPacketHandler {
3238
33- private CompletableFuture <String > future ;
39+ /**
40+ * The server future for waiting until the client is done unloading the RP
41+ */
42+ private CompletableFuture <String > serverRPFuture ;
3443
44+ /**
45+ * The latch for waiting until the client RP is unloaded
46+ */
3547 public static CountDownLatch clientRPLatch ;
3648
3749 @ Override
@@ -46,17 +58,18 @@ public void onServerLoadstate(MinecraftServer server, int index, Path target, Pa
4658 } catch (Exception e ) {
4759 TASmod .LOGGER .catching (e );
4860 }
49- future = new CompletableFuture <>();
61+ serverRPFuture = new CompletableFuture <>();
5062
5163 String playername = null ;
5264 try {
53- playername = future .get (2L , TimeUnit .MINUTES );
65+ playername = serverRPFuture .get (2L , TimeUnit .MINUTES );
5466 } catch (TimeoutException e ) {
5567 throw new SavestateException (e , "Clearing resourcepacks %s timed out!" , serverOwnerName );
5668 } catch (ExecutionException | InterruptedException e ) {
5769 throw new SavestateException (e , "Clearing resourcepacks %s" , serverOwnerName );
5870 }
5971
72+ server .setResourcePack ("" , "" );
6073 TASmod .LOGGER .debug (LoggerMarkers .Savestate , "Cleared resourcepack for player {}" , playername );
6174 }
6275
@@ -65,30 +78,51 @@ public PacketID[] getAcceptedPacketIDs() {
6578 return new TASmodPackets [] { TASmodPackets .SAVESTATE_CLEAR_RESOURCEPACK };
6679 }
6780
81+ @ Environment (EnvType .CLIENT )
6882 @ Override
6983 public void onClientPacket (PacketID id , ByteBuffer buf , String username ) throws PacketNotImplementedException , WrongSideException , Exception {
7084 TASmodPackets packetId = (TASmodPackets ) id ;
7185
7286 Minecraft mc = Minecraft .getMinecraft ();
7387 switch (packetId ) {
7488 case SAVESTATE_CLEAR_RESOURCEPACK :
75- mc .addScheduledTask (() -> {
76- clientRPLatch = new CountDownLatch (1 );
77- ResourcePackRepositoryDuck duck = (ResourcePackRepositoryDuck ) mc .getResourcePackRepository ();
78- duck .clearServerResourcePackBlocking ();
79-
80- try {
81- clientRPLatch .await (30 , TimeUnit .SECONDS );
82- } catch (InterruptedException e ) {
83- e .printStackTrace ();
84- }
85-
86- try {
87- TASmodClient .client .send (new TASmodBufferBuilder (TASmodPackets .SAVESTATE_CLEAR_RESOURCEPACK ));
88- } catch (Exception e ) {
89- TASmod .LOGGER .catching (e );
90- }
91- });
89+
90+ TASmod .LOGGER .debug (LoggerMarkers .Savestate , "Clearing server resource pack" );
91+
92+ /**
93+ * Using a countdown latch here, which is counted down in
94+ * savestates.MixinMinecraft.
95+ *
96+ * Clearing the resourcepack is scheduled multiple times
97+ * so for simplicity, I use a latch here.
98+ */
99+ clientRPLatch = new CountDownLatch (1 );
100+ mc .getResourcePackRepository ().clearResourcePack ();
101+
102+ try {
103+ clientRPLatch .await (30 , TimeUnit .SECONDS );
104+ } catch (InterruptedException e ) {
105+ e .printStackTrace ();
106+ }
107+
108+ /**
109+ * At this point, "clearResourcePack" did remove the server RP
110+ * however, the file association with the "resources.zip" in the
111+ * save folder is still there, which causes loadstating to fail,
112+ * as the system still thinks that the RP is still "in use".
113+ *
114+ * We have to run the garbage collector to remove it.
115+ */
116+ System .gc ();
117+
118+ /**
119+ * Notify the server that savestates have been cleared and that savestating can continue
120+ */
121+ try {
122+ TASmodClient .client .send (new TASmodBufferBuilder (TASmodPackets .SAVESTATE_CLEAR_RESOURCEPACK ));
123+ } catch (Exception e ) {
124+ TASmod .LOGGER .catching (e );
125+ }
92126 break ;
93127
94128 default :
@@ -102,15 +136,21 @@ public void onServerPacket(PacketID id, ByteBuffer buf, String username) throws
102136
103137 switch (packetId ) {
104138 case SAVESTATE_CLEAR_RESOURCEPACK :
105- future .complete (username );
139+ serverRPFuture .complete (username );
106140 break ;
107141
108142 default :
109143 throw new WrongSideException (packetId , Side .SERVER );
110144 }
111145 }
112146
147+ /**
148+ * Notifies all clients that a new server resourcepack should be downloaded if available
149+ *
150+ * @param server The Minecraft server
151+ */
113152 public static void refreshServerResourcepack (MinecraftServer server ) {
153+ TASmod .LOGGER .debug (LoggerMarkers .Savestate , "Refreshing resourcepack" );
114154 List <EntityPlayerMP > players = server .getPlayerList ().getPlayers ();
115155 players .forEach ((player ) -> {
116156 player .loadResourcePack (server .getResourcePackUrl (), server .getResourcePackHash ());
0 commit comments