diff --git a/src/main/java/com/minecrafttas/tasmod/TASmod.java b/src/main/java/com/minecrafttas/tasmod/TASmod.java index 69fb8eb3..6cb78d10 100644 --- a/src/main/java/com/minecrafttas/tasmod/TASmod.java +++ b/src/main/java/com/minecrafttas/tasmod/TASmod.java @@ -29,6 +29,7 @@ import com.minecrafttas.tasmod.playback.metadata.builtin.StartpositionMetadataExtension; import com.minecrafttas.tasmod.registries.TASmodPackets; import com.minecrafttas.tasmod.savestates.SavestateHandlerServer; +import com.minecrafttas.tasmod.savestates.handlers.SavestateResourcePackHandler; import com.minecrafttas.tasmod.savestates.storage.builtin.SavestateMotionStorage; import com.minecrafttas.tasmod.tickratechanger.TickrateChangerServer; import com.minecrafttas.tasmod.ticksync.TickSyncServer; @@ -119,6 +120,9 @@ public void onInitialize() { SavestateMotionStorage motionStorage = new SavestateMotionStorage(); PacketHandlerRegistry.register(motionStorage); EventListenerRegistry.register(motionStorage); + SavestateResourcePackHandler resourcepackHandler = new SavestateResourcePackHandler(); + PacketHandlerRegistry.register(resourcepackHandler); + EventListenerRegistry.register(resourcepackHandler); PacketHandlerRegistry.register(playUntil); EventListenerRegistry.register(playUntil); } diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinResourcePackRepository.java b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinResourcePackRepository.java new file mode 100644 index 00000000..cacec9f5 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinResourcePackRepository.java @@ -0,0 +1,46 @@ +package com.minecrafttas.tasmod.mixin.savestates; + +import java.util.concurrent.locks.ReentrantLock; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import com.google.common.util.concurrent.ListenableFuture; +import com.minecrafttas.tasmod.util.Ducks.ResourcePackRepositoryDuck; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.IResourcePack; +import net.minecraft.client.resources.ResourcePackRepository; + +@Mixin(ResourcePackRepository.class) +public class MixinResourcePackRepository implements ResourcePackRepositoryDuck { + + @Shadow + @Final + private ReentrantLock lock; + @Shadow + private ListenableFuture downloadingPacks; + @Shadow + private IResourcePack serverResourcePack; + + @Override + public void clearServerResourcePackBlocking() { + this.lock.lock(); + + try { + if (this.downloadingPacks != null) { + this.downloadingPacks.cancel(true); + } + + this.downloadingPacks = null; + if (this.serverResourcePack != null) { + this.serverResourcePack = null; + Minecraft.getMinecraft().refreshResources(); + } + } finally { + this.lock.unlock(); + } + } + +} diff --git a/src/main/java/com/minecrafttas/tasmod/registries/TASmodPackets.java b/src/main/java/com/minecrafttas/tasmod/registries/TASmodPackets.java index 7c8b2094..42f4e093 100644 --- a/src/main/java/com/minecrafttas/tasmod/registries/TASmodPackets.java +++ b/src/main/java/com/minecrafttas/tasmod/registries/TASmodPackets.java @@ -104,6 +104,12 @@ public enum TASmodPackets implements PacketID { Minecraft mc = Minecraft.getMinecraft(); ((ScoreboardDuck) mc.world.getScoreboard()).clearScoreboard(); }), + /** + *

Clears the resourcepack on the client side + *

SIDE: Client
+ * ARGS: none + */ + SAVESTATE_CLEAR_RESOURCEPACK, /** *

Notifies the client to clear all inputs from the input buffer in {@link PlaybackControllerClient} *

SIDE: Both
diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerClient.java b/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerClient.java index 15abee1e..0b3fa37d 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerClient.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerClient.java @@ -28,6 +28,7 @@ import com.minecrafttas.tasmod.savestates.exceptions.SavestateException; import com.minecrafttas.tasmod.savestates.gui.GuiSavestateSavingScreen; import com.minecrafttas.tasmod.util.Ducks.ChunkProviderDuck; +import com.minecrafttas.tasmod.util.Ducks.ResourcePackRepositoryDuck; import com.minecrafttas.tasmod.util.Ducks.SubtickDuck; import com.minecrafttas.tasmod.util.Ducks.WorldClientDuck; import com.minecrafttas.tasmod.util.LoggerMarkers; @@ -151,6 +152,8 @@ public static void loadstate(String nameOfSavestate) throws Exception { return; } + ((ResourcePackRepositoryDuck) Minecraft.getMinecraft().getResourcePackRepository()).clearServerResourcePackBlocking(); + PlaybackControllerClient controller = TASmodClient.controller; TASstate state = controller.getState(); diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java b/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java index 387078c5..884e9e0b 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java @@ -40,6 +40,7 @@ import com.minecrafttas.tasmod.savestates.files.SavestateDataFile.DataValues; import com.minecrafttas.tasmod.savestates.files.SavestateTrackerFile; import com.minecrafttas.tasmod.savestates.handlers.SavestatePlayerHandler; +import com.minecrafttas.tasmod.savestates.handlers.SavestateResourcePackHandler; import com.minecrafttas.tasmod.savestates.handlers.SavestateWorldHandler; import com.minecrafttas.tasmod.util.LoggerMarkers; import com.minecrafttas.tasmod.util.Scheduler.Task; @@ -386,6 +387,9 @@ public void loadState(int savestateIndex, boolean tickrate0, boolean changeIndex // Reenable level saving worldHandler.enableLevelSaving(); + // Refresh server resourcepacks on the client + SavestateResourcePackHandler.refreshServerResourcepack(server); + // Incrementing info file SavestateTrackerFile tracker = new SavestateTrackerFile(savestateDirectory.resolve(worldname + "-info.txt")); tracker.increaseLoadstateCount(); @@ -398,6 +402,8 @@ public void loadState(int savestateIndex, boolean tickrate0, boolean changeIndex worldHandler.sendChunksToClient(); + playerHandler.updateServerResourcePack(); + try { TASmod.server.sendToAll(new TASmodBufferBuilder(CLEAR_SCREEN)); } catch (Exception e) { @@ -753,9 +759,9 @@ private int legacyIndexFile(Path savestateDat) { public PacketID[] getAcceptedPacketIDs() { return new TASmodPackets[] { //@formatter:off - TASmodPackets.SAVESTATE_SAVE, - TASmodPackets.SAVESTATE_LOAD, - TASmodPackets.SAVESTATE_SCREEN, + TASmodPackets.SAVESTATE_SAVE, + TASmodPackets.SAVESTATE_LOAD, + TASmodPackets.SAVESTATE_SCREEN, TASmodPackets.SAVESTATE_UNLOAD_CHUNKS //@formatter:on }; @@ -770,7 +776,7 @@ public void onServerPacket(PacketID id, ByteBuffer buf, String username) throws switch (packet) { case SAVESTATE_SAVE: - Integer index = TASmodBufferBuilder.readInt(buf); + int index = TASmodBufferBuilder.readInt(buf); Task savestateTask = () -> { try { diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestatePlayerHandler.java b/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestatePlayerHandler.java index 1a1706a2..5248288b 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestatePlayerHandler.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestatePlayerHandler.java @@ -225,4 +225,13 @@ public void onClientPacket(PacketID id, ByteBuffer buf, String username) throws break; } } + + public void updateServerResourcePack() { + if (!this.server.getResourcePackUrl().isEmpty()) { + List players = server.getPlayerList().getPlayers(); + for (EntityPlayerMP player : players) { + player.loadResourcePack(this.server.getResourcePackUrl(), this.server.getResourcePackHash()); + } + } + } } diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestateResourcePackHandler.java b/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestateResourcePackHandler.java new file mode 100644 index 00000000..d8f203c0 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestateResourcePackHandler.java @@ -0,0 +1,108 @@ +package com.minecrafttas.tasmod.savestates.handlers; + +import java.nio.ByteBuffer; +import java.nio.file.Path; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import com.minecrafttas.mctcommon.networking.Client.Side; +import com.minecrafttas.mctcommon.networking.exception.PacketNotImplementedException; +import com.minecrafttas.mctcommon.networking.exception.WrongSideException; +import com.minecrafttas.mctcommon.networking.interfaces.ClientPacketHandler; +import com.minecrafttas.mctcommon.networking.interfaces.PacketID; +import com.minecrafttas.mctcommon.networking.interfaces.ServerPacketHandler; +import com.minecrafttas.tasmod.TASmod; +import com.minecrafttas.tasmod.TASmodClient; +import com.minecrafttas.tasmod.events.EventSavestate; +import com.minecrafttas.tasmod.networking.TASmodBufferBuilder; +import com.minecrafttas.tasmod.registries.TASmodPackets; +import com.minecrafttas.tasmod.savestates.exceptions.SavestateException; +import com.minecrafttas.tasmod.util.Ducks.ResourcePackRepositoryDuck; +import com.minecrafttas.tasmod.util.LoggerMarkers; + +import net.minecraft.client.Minecraft; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.server.MinecraftServer; + +public class SavestateResourcePackHandler implements EventSavestate.EventServerLoadstate, ServerPacketHandler, ClientPacketHandler { + + private CompletableFuture future; + + @Override + public void onServerLoadstate(MinecraftServer server, int index, Path target, Path current) { + if (server.getResourcePackUrl().isEmpty() || server.isDedicatedServer()) + return; + + String serverOwnerName = server.getServerOwner(); + + try { + TASmod.server.sendTo(serverOwnerName, new TASmodBufferBuilder(TASmodPackets.SAVESTATE_CLEAR_RESOURCEPACK)); + } catch (Exception e) { + TASmod.LOGGER.catching(e); + } + future = new CompletableFuture<>(); + + String playername = null; + try { + playername = future.get(2L, TimeUnit.MINUTES); + } catch (TimeoutException e) { + throw new SavestateException(e, "Clearing resourcepacks %s timed out!", serverOwnerName); + } catch (ExecutionException | InterruptedException e) { + throw new SavestateException(e, "Clearing resourcepacks %s", serverOwnerName); + } + + TASmod.LOGGER.debug(LoggerMarkers.Savestate, "Cleared resourcepack for player {}", playername); + } + + @Override + public PacketID[] getAcceptedPacketIDs() { + return new TASmodPackets[] { TASmodPackets.SAVESTATE_CLEAR_RESOURCEPACK }; + } + + @Override + public void onClientPacket(PacketID id, ByteBuffer buf, String username) throws PacketNotImplementedException, WrongSideException, Exception { + TASmodPackets packetId = (TASmodPackets) id; + + Minecraft mc = Minecraft.getMinecraft(); + switch (packetId) { + case SAVESTATE_CLEAR_RESOURCEPACK: + mc.addScheduledTask(() -> { + ResourcePackRepositoryDuck duck = (ResourcePackRepositoryDuck) mc.getResourcePackRepository(); + duck.clearServerResourcePackBlocking(); + try { + TASmodClient.client.send(new TASmodBufferBuilder(TASmodPackets.SAVESTATE_CLEAR_RESOURCEPACK)); + } catch (Exception e) { + TASmod.LOGGER.catching(e); + } + }); + break; + + default: + throw new WrongSideException(packetId, Side.CLIENT); + } + } + + @Override + public void onServerPacket(PacketID id, ByteBuffer buf, String username) throws PacketNotImplementedException, WrongSideException, Exception { + TASmodPackets packetId = (TASmodPackets) id; + + switch (packetId) { + case SAVESTATE_CLEAR_RESOURCEPACK: + future.complete(username); + break; + + default: + throw new WrongSideException(packetId, Side.SERVER); + } + } + + public static void refreshServerResourcepack(MinecraftServer server) { + List players = server.getPlayerList().getPlayers(); + players.forEach((player) -> { + player.loadResourcePack(server.getResourcePackUrl(), server.getResourcePackHash()); + }); + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/util/Ducks.java b/src/main/java/com/minecrafttas/tasmod/util/Ducks.java index bd13bd34..ad8cb4ff 100644 --- a/src/main/java/com/minecrafttas/tasmod/util/Ducks.java +++ b/src/main/java/com/minecrafttas/tasmod/util/Ducks.java @@ -142,4 +142,8 @@ public static interface PlayerChunkMapDuck { */ public void forceTick(); } + + public static interface ResourcePackRepositoryDuck { + public void clearServerResourcePackBlocking(); + } } diff --git a/src/main/resources/tasmod.mixin.json b/src/main/resources/tasmod.mixin.json index 6f004f1d..52028c0a 100644 --- a/src/main/resources/tasmod.mixin.json +++ b/src/main/resources/tasmod.mixin.json @@ -32,6 +32,7 @@ // Savestates "savestates.MixinChunkProviderClient", "savestates.MixinWorldClient", + "savestates.MixinResourcePackRepository", // Interpolation "MixinFrustum",