diff --git a/src/main/java/ru/bclib/BCLib.java b/src/main/java/ru/bclib/BCLib.java index 7de687de..d284d125 100644 --- a/src/main/java/ru/bclib/BCLib.java +++ b/src/main/java/ru/bclib/BCLib.java @@ -7,8 +7,11 @@ import net.minecraft.resources.ResourceLocation; import ru.bclib.api.TagAPI; import ru.bclib.api.WorldDataAPI; import ru.bclib.api.dataexchange.DataExchangeAPI; +import ru.bclib.api.dataexchange.DataHandler; import ru.bclib.api.dataexchange.handler.HelloClient; import ru.bclib.api.dataexchange.handler.HelloServer; +import ru.bclib.api.dataexchange.handler.RequestFiles; +import ru.bclib.api.dataexchange.handler.SendFiles; import ru.bclib.config.Configs; import ru.bclib.recipes.CraftingRecipes; import ru.bclib.registry.BaseBlockEntities; @@ -16,6 +19,9 @@ import ru.bclib.registry.BaseRegistry; import ru.bclib.util.Logger; import ru.bclib.world.surface.BCLSurfaceBuilders; +import java.util.ArrayList; +import java.util.List; + public class BCLib implements ModInitializer { public static final String MOD_ID = "bclib"; public static final Logger LOGGER = new Logger(MOD_ID); @@ -30,8 +36,12 @@ public class BCLib implements ModInitializer { WorldDataAPI.registerModCache(MOD_ID); Configs.save(); - DataExchangeAPI.registerDescriptor(HelloClient.DESCRIPTOR); - DataExchangeAPI.registerDescriptor(HelloServer.DESCRIPTOR); + DataExchangeAPI.registerDescriptors(List.of( + HelloClient.DESCRIPTOR, + HelloServer.DESCRIPTOR, + RequestFiles.DESCRIPTOR, + SendFiles.DESCRIPTOR + )); } public static boolean isDevEnvironment() { diff --git a/src/main/java/ru/bclib/api/dataexchange/DataExchangeAPI.java b/src/main/java/ru/bclib/api/dataexchange/DataExchangeAPI.java index eccbfa26..e13faa0a 100644 --- a/src/main/java/ru/bclib/api/dataexchange/DataExchangeAPI.java +++ b/src/main/java/ru/bclib/api/dataexchange/DataExchangeAPI.java @@ -59,7 +59,7 @@ public class DataExchangeAPI extends DataExchange { } /** - * Add a new Descriptor for a DataHandler. + * Add a new Descriptor for a {@link DataHandler}. * @param desc The Descriptor you want to add. */ public static void registerDescriptor(DataHandlerDescriptor desc){ @@ -67,6 +67,15 @@ public class DataExchangeAPI extends DataExchange { api.getDescriptors().add(desc); } + /** + * Bulk-Add a Descriptors for your {@link DataHandler}-Objects. + * @param desc The Descriptors you want to add. + */ + public static void registerDescriptors(List desc){ + DataExchange api = DataExchange.getInstance(); + api.getDescriptors().addAll(desc); + } + /** * Sends the Handler. *

diff --git a/src/main/java/ru/bclib/api/dataexchange/DataHandlerDescriptor.java b/src/main/java/ru/bclib/api/dataexchange/DataHandlerDescriptor.java index 99017fe4..61860185 100644 --- a/src/main/java/ru/bclib/api/dataexchange/DataHandlerDescriptor.java +++ b/src/main/java/ru/bclib/api/dataexchange/DataHandlerDescriptor.java @@ -1,6 +1,10 @@ package ru.bclib.api.dataexchange; import net.minecraft.resources.ResourceLocation; +import ru.bclib.api.dataexchange.handler.HelloClient; +import ru.bclib.api.dataexchange.handler.HelloServer; +import ru.bclib.api.dataexchange.handler.RequestFiles; +import ru.bclib.api.dataexchange.handler.SendFiles; import java.util.function.Supplier; diff --git a/src/main/java/ru/bclib/api/dataexchange/handler/DataExchange.java b/src/main/java/ru/bclib/api/dataexchange/handler/DataExchange.java index 9dcf7a7d..9e4e66a9 100644 --- a/src/main/java/ru/bclib/api/dataexchange/handler/DataExchange.java +++ b/src/main/java/ru/bclib/api/dataexchange/handler/DataExchange.java @@ -97,10 +97,10 @@ abstract public class DataExchange { return new byte[0]; } - public void serializeContent(FriendlyByteBuf buf){ + public int serializeContent(FriendlyByteBuf buf){ DataHandler.writeString(buf, modID); DataHandler.writeString(buf, uniqueID); - serializeFileContent(buf); + return serializeFileContent(buf); } public static Pair deserializeContent(FriendlyByteBuf buf){ final String modID = DataHandler.readString(buf); @@ -138,10 +138,11 @@ abstract public class DataExchange { return new Pair(hash, data); } - private void serializeFileContent(FriendlyByteBuf buf) { + private int serializeFileContent(FriendlyByteBuf buf) { byte[] content = getContent(); buf.writeInt(content.length); buf.writeByteArray(content); + return content.length; } private static byte[] deserializeFileContent(FriendlyByteBuf buf) { diff --git a/src/main/java/ru/bclib/api/dataexchange/handler/HelloClient.java b/src/main/java/ru/bclib/api/dataexchange/handler/HelloClient.java index 05176c16..73e50045 100644 --- a/src/main/java/ru/bclib/api/dataexchange/handler/HelloClient.java +++ b/src/main/java/ru/bclib/api/dataexchange/handler/HelloClient.java @@ -16,6 +16,7 @@ import ru.bclib.api.dataexchange.DataHandler; import ru.bclib.api.dataexchange.DataHandlerDescriptor; import ru.bclib.api.dataexchange.handler.DataExchange.AutoSyncID; import ru.bclib.api.datafixer.DataFixerAPI; +import ru.bclib.gui.screens.SyncFilesScreen; import ru.bclib.gui.screens.WarnBCLibVersionMismatch; import java.util.ArrayList; @@ -134,8 +135,10 @@ public class HelloClient extends DataHandler { BCLib.LOGGER.info(" - " + e + ": " + (willRequest ? " (requesting)":"")); } + if (filesToRequest.size()>0) { showDonwloadConfigs(client, filesToRequest); + return; } } @@ -154,9 +157,13 @@ public class HelloClient extends DataHandler { @Environment(EnvType.CLIENT) protected void showDonwloadConfigs(Minecraft client, List files){ - requestFileDownloads((hadErrors)->{ - client.stop(); - }, files); + client.setScreen(new SyncFilesScreen((download) -> { + Minecraft.getInstance().setScreen((Screen)null); + if (download){ + requestFileDownloads(files); + } + })); + } private void requestBCLibDownload(Consumer whenFinished){ @@ -164,9 +171,8 @@ public class HelloClient extends DataHandler { whenFinished.accept(true); } - private void requestFileDownloads(Consumer whenFinished, List files){ + private void requestFileDownloads(List files){ BCLib.LOGGER.info("Starting download of Files:" + files.size()); DataExchangeAPI.send(new RequestFiles(files)); - whenFinished.accept(true); } } diff --git a/src/main/java/ru/bclib/api/dataexchange/handler/RequestFiles.java b/src/main/java/ru/bclib/api/dataexchange/handler/RequestFiles.java index 77832369..5c584780 100644 --- a/src/main/java/ru/bclib/api/dataexchange/handler/RequestFiles.java +++ b/src/main/java/ru/bclib/api/dataexchange/handler/RequestFiles.java @@ -12,10 +12,12 @@ import ru.bclib.api.dataexchange.handler.DataExchange.AutoSyncID; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import java.util.stream.Collectors; public class RequestFiles extends DataHandler { public static DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "request_files"), RequestFiles::new, false, false); + static String currentToken = ""; protected List files; private RequestFiles(){ @@ -29,6 +31,9 @@ public class RequestFiles extends DataHandler { @Override protected void serializeData(FriendlyByteBuf buf) { + newToken(); + writeString(buf, currentToken); + buf.writeInt(files.size()); for (AutoSyncID a : files){ @@ -36,9 +41,11 @@ public class RequestFiles extends DataHandler { writeString(buf, a.getUniqueID()); } } - + + String receivedToken = ""; @Override protected void deserializeFromIncomingData(FriendlyByteBuf buf, PacketSender responseSender, boolean fromClient) { + receivedToken = readString(buf); int size = buf.readInt(); files = new ArrayList<>(size); @@ -61,6 +68,16 @@ public class RequestFiles extends DataHandler { .filter(e -> e!=null) .collect(Collectors.toList()); - reply(new SendFiles(syncEntries), server); + reply(new SendFiles(syncEntries, receivedToken), server); + } + + + + public static void newToken(){ + currentToken = UUID.randomUUID().toString(); + } + + static { + newToken(); } } diff --git a/src/main/java/ru/bclib/api/dataexchange/handler/SendFiles.java b/src/main/java/ru/bclib/api/dataexchange/handler/SendFiles.java index 228a94a6..c7bb084c 100644 --- a/src/main/java/ru/bclib/api/dataexchange/handler/SendFiles.java +++ b/src/main/java/ru/bclib/api/dataexchange/handler/SendFiles.java @@ -1,44 +1,67 @@ package ru.bclib.api.dataexchange.handler; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import ru.bclib.BCLib; import ru.bclib.api.dataexchange.DataHandler; import ru.bclib.api.dataexchange.DataHandlerDescriptor; +import ru.bclib.gui.screens.ConfirmRestartScreen; +import ru.bclib.gui.screens.SyncFilesScreen; import ru.bclib.util.Pair; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import java.util.stream.Collectors; public class SendFiles extends DataHandler { public static DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "send_files"), SendFiles::new, false, false); protected List files; + private String token = ""; public SendFiles(){ - this(null); + this(null, ""); } - public SendFiles(List files) { + public SendFiles(List files, String token) { super(DESCRIPTOR.IDENTIFIER, true); this.files = files; + this.token = token; } @Override protected void serializeData(FriendlyByteBuf buf) { List existingFiles = files.stream().filter(e -> e.fileName.exists()).collect(Collectors.toList()); + writeString(buf, token); buf.writeInt(existingFiles.size()); + BCLib.LOGGER.info("Sending " + existingFiles.size() + " Files to Client:"); for (DataExchange.AutoFileSyncEntry entry : existingFiles) { - entry.serializeContent(buf); + int length = entry.serializeContent(buf); + BCLib.LOGGER.info(" - " + entry + " (" + length + " Bytes)"); } } private List> receivedFiles; @Override protected void deserializeFromIncomingData(FriendlyByteBuf buf, PacketSender responseSender, boolean fromClient) { + token = readString(buf); + if (!token.equals(RequestFiles.currentToken)) { + BCLib.LOGGER.error("Unrequested File Transfer!"); + receivedFiles = new ArrayList<>(0); + return; + } + int size = buf.readInt(); receivedFiles = new ArrayList<>(size); BCLib.LOGGER.info("Server sent " + size + " Files:"); @@ -55,6 +78,28 @@ public class SendFiles extends DataHandler { @Override protected void runOnGameThread(Minecraft client, MinecraftServer server, boolean isClient) { - + BCLib.LOGGER.info("Writing Files:"); + for (Pair entry : receivedFiles) { + final DataExchange.AutoFileSyncEntry e = entry.first; + final byte[] data = entry.second; + Path path = e.fileName.toPath(); + BCLib.LOGGER.info(" - Writing " + path + " (" + data.length + " Bytes)"); + try { + Files.write(path, data); + } catch (IOException ioException) { + BCLib.LOGGER.error(" --> Writing "+e.fileName+" failed: " + ioException); + } + } + + showConfirmRestart(client); + } + + @Environment(EnvType.CLIENT) + protected void showConfirmRestart(Minecraft client){ + client.setScreen(new ConfirmRestartScreen(() -> { + Minecraft.getInstance().setScreen((Screen)null); + client.stop(); + })); + } } diff --git a/src/main/java/ru/bclib/gui/screens/ConfirmRestartScreen.java b/src/main/java/ru/bclib/gui/screens/ConfirmRestartScreen.java new file mode 100644 index 00000000..09c12cbf --- /dev/null +++ b/src/main/java/ru/bclib/gui/screens/ConfirmRestartScreen.java @@ -0,0 +1,49 @@ +package ru.bclib.gui.screens; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; +import ru.bclib.gui.GridScreen; + + +@Environment(EnvType.CLIENT) +public class ConfirmRestartScreen extends GridScreen { + private final Component description; + private final ConfirmRestartScreen.Listener listener; + + public ConfirmRestartScreen(ConfirmRestartScreen.Listener listener) { + this(listener, null); + } + + public ConfirmRestartScreen(ConfirmRestartScreen.Listener listener, Component message) { + super(30, new TranslatableComponent("bclib.datafixer.confirmrestart.title")); + + this.description = message==null?new TranslatableComponent("bclib.datafixer.confirmrestart.message"):message; + this.listener = listener; + } + + protected void initLayout() { + final int BUTTON_HEIGHT = 20; + + grid.addMessageRow(this.description, 25); + + grid.startRow(); + grid.addButton( BUTTON_HEIGHT, CommonComponents.GUI_PROCEED, (button) -> { + listener.proceed(); + }); + + grid.endRow(); + grid.recenterVertically(); + } + + public boolean shouldCloseOnEsc() { + return false; + } + + @Environment(EnvType.CLIENT) + public interface Listener { + void proceed(); + } +} diff --git a/src/main/java/ru/bclib/gui/screens/SyncFilesScreen.java b/src/main/java/ru/bclib/gui/screens/SyncFilesScreen.java new file mode 100644 index 00000000..11505bf4 --- /dev/null +++ b/src/main/java/ru/bclib/gui/screens/SyncFilesScreen.java @@ -0,0 +1,46 @@ +package ru.bclib.gui.screens; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; +import ru.bclib.gui.GridScreen; + +@Environment(EnvType.CLIENT) +public class SyncFilesScreen extends GridScreen { + private final Component description; + private final SyncFilesScreen.Listener listener; + public SyncFilesScreen(SyncFilesScreen.Listener listener) { + super(30, new TranslatableComponent("bclib.datafixer.syncfiles.title")); + + this.description = new TranslatableComponent("bclib.datafixer.syncfiles.message"); + this.listener = listener; + } + + protected void initLayout() { + final int BUTTON_HEIGHT = 20; + + grid.addMessageRow(this.description, 25); + + grid.startRow(); + grid.addButton( BUTTON_HEIGHT, CommonComponents.GUI_NO, (button) -> { + listener.proceed(false); + }); + grid.addButton( BUTTON_HEIGHT, CommonComponents.GUI_YES, (button) -> { + listener.proceed(true); + }); + + grid.endRow(); + grid.recenterVertically(); + } + + public boolean shouldCloseOnEsc() { + return false; + } + + @Environment(EnvType.CLIENT) + public interface Listener { + void proceed(boolean download); + } +} diff --git a/src/main/resources/assets/bclib/lang/en_us.json b/src/main/resources/assets/bclib/lang/en_us.json index c4c8b0ec..09d1436f 100644 --- a/src/main/resources/assets/bclib/lang/en_us.json +++ b/src/main/resources/assets/bclib/lang/en_us.json @@ -6,5 +6,9 @@ "bclib.datafixer.backupWarning.nofixes": "Continue Without Fixes", "bclib.datafixer.backupWarning.continue": "Continue Without Backup", "bclib.datafixer.bclibmissmatch.title": "Version Mismatch", - "bclib.datafixer.bclibmissmatch.message": "The Version of BCLib on the server and this client do not match. This will cause problems when playing.\n\nDo you want to automatically download the BCLib-Version from the server. You will need to delete the old version from your Mods Directory and restart the game." + "bclib.datafixer.bclibmissmatch.message": "The Version of BCLib on the server and this client do not match. This will cause problems when playing.\n\nDo you want to automatically download the BCLib-Version from the server. You will need to delete the old version from your Mods Directory and restart the game.", + "bclib.datafixer.syncfiles.title": "Mismatching (Config-)Files", + "bclib.datafixer.syncfiles.message": "Some Files on the Server doe not match the versions on the client.\n\nDo you want to replace the local versions with the ones from the server?", + "bclib.datafixer.confirmrestart.title": "Restart Required", + "bclib.datafixer.confirmrestart.message": "The requested files were processed. You need o restart Minecraft now." } \ No newline at end of file