Use ProgressScreen for larger Data-Transfers

This commit is contained in:
Frank 2021-08-23 15:07:02 +02:00
parent 469e97b790
commit 3321d1c90e
5 changed files with 86 additions and 11 deletions

View file

@ -55,6 +55,7 @@ public abstract class BaseDataHandler {
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
abstract void sendToServer(Minecraft client); abstract void sendToServer(Minecraft client);
protected boolean isBlocking() { return false; }
@Override @Override
public String toString() { public String toString() {

View file

@ -56,7 +56,10 @@ public abstract class DataHandler extends BaseDataHandler {
@Override @Override
void receiveFromServer(Minecraft client, ClientPacketListener handler, FriendlyByteBuf buf, PacketSender responseSender) { void receiveFromServer(Minecraft client, ClientPacketListener handler, FriendlyByteBuf buf, PacketSender responseSender) {
deserializeIncomingData(buf, responseSender, true); deserializeIncomingData(buf, responseSender, true);
client.execute(() -> runOnGameThread(client, null, true)); final Runnable runner = () -> runOnGameThread(client, null, true);
if (isBlocking()) client.executeBlocking(runner);
else client.execute(runner);
} }
@Override @Override
@ -64,7 +67,10 @@ public abstract class DataHandler extends BaseDataHandler {
super.receiveFromClient(server, player, handler, buf, responseSender); super.receiveFromClient(server, player, handler, buf, responseSender);
deserializeIncomingData(buf, responseSender, false); deserializeIncomingData(buf, responseSender, false);
server.execute(() -> runOnGameThread(null, server, false)); final Runnable runner = () -> runOnGameThread(null, server, false);
if (isBlocking()) server.executeBlocking(runner);
else server.execute(runner);
} }
@Override @Override
@ -156,7 +162,10 @@ public abstract class DataHandler extends BaseDataHandler {
super.receiveFromClient(server, player, handler, buf, responseSender); super.receiveFromClient(server, player, handler, buf, responseSender);
deserializeIncomingDataOnServer(buf, responseSender); deserializeIncomingDataOnServer(buf, responseSender);
server.execute(() -> runOnServerGameThread(server)); final Runnable runner = () -> runOnServerGameThread(server);
if (isBlocking()) server.executeBlocking(runner);
else server.execute(runner);
} }
@Override @Override
@ -220,7 +229,10 @@ public abstract class DataHandler extends BaseDataHandler {
@Override @Override
final void receiveFromServer(Minecraft client, ClientPacketListener handler, FriendlyByteBuf buf, PacketSender responseSender) { final void receiveFromServer(Minecraft client, ClientPacketListener handler, FriendlyByteBuf buf, PacketSender responseSender) {
deserializeIncomingDataOnClient(buf, responseSender); deserializeIncomingDataOnClient(buf, responseSender);
client.execute(() -> runOnClientGameThread(client)); final Runnable runner = () -> runOnClientGameThread(client);
if (isBlocking()) client.executeBlocking(runner);
else client.execute(runner);
} }
@Override @Override

View file

@ -1,9 +1,13 @@
package ru.bclib.api.dataexchange.handler.autosync; package ru.bclib.api.dataexchange.handler.autosync;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.fabricmc.fabric.api.networking.v1.PacketSender;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.util.ProgressListener;
import ru.bclib.gui.screens.ProgressScreen;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
@ -23,8 +27,35 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
/**
* Used to seperate large data transfers into multiple smaller messages.
* <p>
* {@link DataHandler} will automatically convert larger messages into Chunks on the Server
* and assemble the original message from those chunks on the client.
*/
public class Chunker extends DataHandler.FromServer { public class Chunker extends DataHandler.FromServer {
public static class PacketChunkReceiver { private static ProgressScreen progressScreen;
@Environment(EnvType.CLIENT)
public static void setProgressScreen(ProgressScreen scr){
progressScreen = scr;
}
@Environment(EnvType.CLIENT)
public static ProgressScreen getProgressScreen(){
return progressScreen;
}
@Environment(EnvType.CLIENT)
public static ProgressListener getProgressListener(){
return progressScreen;
}
/**
* Responsible for assembling the original ByteBuffer created by {@link PacketChunkSender} on the
* receiving end. Automatically created from the header {@link Chunker}-Message (where the serialNo==-1)
*/
static class PacketChunkReceiver {
@NotNull @NotNull
public final UUID uuid; public final UUID uuid;
public final int chunkCount; public final int chunkCount;
@ -70,6 +101,10 @@ public class Chunker extends DataHandler.FromServer {
} }
public boolean testFinished(){ public boolean testFinished(){
ProgressListener listener = getProgressListener();
if (listener!=null){
listener.progressStagePercentage((100*receivedCount)/chunkCount);
}
if (incomingBuffer == null){ if (incomingBuffer == null){
return true; return true;
} if (lastReadSerial>=chunkCount-1){ } if (lastReadSerial>=chunkCount-1){
@ -79,7 +114,7 @@ public class Chunker extends DataHandler.FromServer {
return false; return false;
} }
protected void addBuffer(FriendlyByteBuf input){ private void addBuffer(FriendlyByteBuf input){
final int size = input.readableBytes(); final int size = input.readableBytes();
final int cap = networkedBuf.capacity()-networkedBuf.writerIndex(); final int cap = networkedBuf.capacity()-networkedBuf.writerIndex();
@ -102,7 +137,10 @@ public class Chunker extends DataHandler.FromServer {
Map<Integer, FriendlyByteBuf> incomingBuffer = new HashMap<>(); Map<Integer, FriendlyByteBuf> incomingBuffer = new HashMap<>();
int lastReadSerial = -1; int lastReadSerial = -1;
int receivedCount = 0;
public void processReceived(FriendlyByteBuf buf, int serialNo, int size){ public void processReceived(FriendlyByteBuf buf, int serialNo, int size){
receivedCount++;
if (lastReadSerial == serialNo-1){ if (lastReadSerial == serialNo-1){
addBuffer(buf); addBuffer(buf);
lastReadSerial = serialNo; lastReadSerial = serialNo;
@ -130,6 +168,10 @@ public class Chunker extends DataHandler.FromServer {
} }
} }
/**
* Responsible for splitting an outgoing ByteBuffer into several smaller Chunks and
* send them as seperate messages to the {@link Chunker}-Channel
*/
public static class PacketChunkSender { public static class PacketChunkSender {
private final FriendlyByteBuf networkedBuf; private final FriendlyByteBuf networkedBuf;
public final UUID uuid; public final UUID uuid;
@ -160,7 +202,9 @@ public class Chunker extends DataHandler.FromServer {
} }
} }
private static final int HEADER_SIZE = 1 + 16 + 4 + 4; //header = version + UUID + serialNo + size //header = version + UUID + serialNo + size, see serializeDataOnServer
private static final int HEADER_SIZE = 1 + 16 + 4 + 4;
public static final int MAX_PACKET_SIZE = 1024*1024; public static final int MAX_PACKET_SIZE = 1024*1024;
private static final int MAX_PAYLOAD_SIZE = MAX_PACKET_SIZE - HEADER_SIZE; private static final int MAX_PAYLOAD_SIZE = MAX_PACKET_SIZE - HEADER_SIZE;
@ -188,17 +232,20 @@ public class Chunker extends DataHandler.FromServer {
@Override @Override
protected void serializeDataOnServer(FriendlyByteBuf buf) { protected void serializeDataOnServer(FriendlyByteBuf buf) {
//Sending Header. Make sure to change HEADER_SIZE if you change this!
buf.writeByte(0); buf.writeByte(0);
buf.writeLong(uuid.getMostSignificantBits()); buf.writeLong(uuid.getMostSignificantBits());
buf.writeLong(uuid.getLeastSignificantBits()); buf.writeLong(uuid.getLeastSignificantBits());
buf.writeInt(serialNo); buf.writeInt(serialNo);
//sending Payload
if (serialNo == -1){ if (serialNo == -1){
//this is our header //this is our header-Chunk that transports status information
buf.writeInt(chunkCount); buf.writeInt(chunkCount);
writeString(buf, origin.getNamespace()); writeString(buf, origin.getNamespace());
writeString(buf, origin.getPath()); writeString(buf, origin.getPath());
} else { } else {
//this is an actual payload chunk
buf.capacity(MAX_PACKET_SIZE); buf.capacity(MAX_PACKET_SIZE);
final int size = Math.min(MAX_PAYLOAD_SIZE, networkedBuf.readableBytes()); final int size = Math.min(MAX_PAYLOAD_SIZE, networkedBuf.readableBytes());
buf.writeInt(size); buf.writeInt(size);

View file

@ -6,6 +6,7 @@ import net.fabricmc.fabric.api.networking.v1.PacketSender;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import ru.bclib.BCLib; import ru.bclib.BCLib;
import ru.bclib.api.dataexchange.DataExchangeAPI; import ru.bclib.api.dataexchange.DataExchangeAPI;
@ -14,6 +15,7 @@ import ru.bclib.api.dataexchange.DataHandlerDescriptor;
import ru.bclib.api.dataexchange.handler.autosync.AutoSyncID.WithContentOverride; import ru.bclib.api.dataexchange.handler.autosync.AutoSyncID.WithContentOverride;
import ru.bclib.api.dataexchange.handler.autosync.SyncFolderDescriptor.SubFile; import ru.bclib.api.dataexchange.handler.autosync.SyncFolderDescriptor.SubFile;
import ru.bclib.config.Configs; import ru.bclib.config.Configs;
import ru.bclib.gui.screens.ProgressScreen;
import ru.bclib.gui.screens.SyncFilesScreen; import ru.bclib.gui.screens.SyncFilesScreen;
import ru.bclib.gui.screens.WarnBCLibVersionMismatch; import ru.bclib.gui.screens.WarnBCLibVersionMismatch;
import ru.bclib.util.ModUtil; import ru.bclib.util.ModUtil;
@ -300,6 +302,10 @@ public class HelloClient extends DataHandler.FromServer {
} }
} }
@Override
protected boolean isBlocking() {
return true;
}
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
@Override @Override
@ -371,8 +377,6 @@ public class HelloClient extends DataHandler.FromServer {
} }
client.setScreen(new SyncFilesScreen(modFiles, configFiles, singleFiles, folderFiles, filesToRemove.size(), (downloadMods, downloadConfigs, downloadFiles, removeFiles) -> { client.setScreen(new SyncFilesScreen(modFiles, configFiles, singleFiles, folderFiles, filesToRemove.size(), (downloadMods, downloadConfigs, downloadFiles, removeFiles) -> {
Minecraft.getInstance()
.setScreen((Screen) null);
if (downloadMods || downloadConfigs || downloadFiles) { if (downloadMods || downloadConfigs || downloadFiles) {
BCLib.LOGGER.info("Updating local Files:"); BCLib.LOGGER.info("Updating local Files:");
List<AutoSyncID.WithContentOverride> localChanges = new ArrayList<>(files.toArray().length); List<AutoSyncID.WithContentOverride> localChanges = new ArrayList<>(files.toArray().length);
@ -398,6 +402,9 @@ public class HelloClient extends DataHandler.FromServer {
aid.relFile.delete(); aid.relFile.delete();
}); });
} }
Minecraft.getInstance()
.setScreen(Chunker.getProgressScreen());
})); }));
} }
@ -422,6 +429,11 @@ public class HelloClient extends DataHandler.FromServer {
private void requestFileDownloads(List<AutoSyncID> files) { private void requestFileDownloads(List<AutoSyncID> files) {
BCLib.LOGGER.info("Starting download of Files:" + files.size()); BCLib.LOGGER.info("Starting download of Files:" + files.size());
final ProgressScreen progress = new ProgressScreen(null, new TranslatableComponent("title.bclib.filesync.progress"), new TranslatableComponent("message.bclib.filesync.progress"));
progress.progressStart(new TranslatableComponent("message.bclib.filesync.progress.stage.empty"));
Chunker.setProgressScreen(progress);
DataExchangeAPI.send(new RequestFiles(files)); DataExchangeAPI.send(new RequestFiles(files));
} }
} }

View file

@ -179,7 +179,10 @@ public class SendFiles extends DataHandler.FromServer {
if (!parentFile.exists()) { if (!parentFile.exists()) {
parentFile.mkdirs(); parentFile.mkdirs();
} }
Files.write(path, data); //TODO: Disabled for testing. MUST BE ENABLED IN PRODUCTION!!!
if (!BCLib.isDevEnvironment()) {
Files.write(path, data);
}
if (removeAfter != null){ if (removeAfter != null){
final String bakFileName = removeAfter.toFile().getName(); final String bakFileName = removeAfter.toFile().getName();
String collisionFreeName = bakFileName; String collisionFreeName = bakFileName;