Use ProgressScreen for larger Data-Transfers
This commit is contained in:
parent
469e97b790
commit
3321d1c90e
5 changed files with 86 additions and 11 deletions
|
@ -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() {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue