Compare files on client/server
This commit is contained in:
parent
8397ef7cca
commit
119e94520c
9 changed files with 371 additions and 53 deletions
|
@ -7,9 +7,14 @@ import net.fabricmc.fabric.api.client.networking.v1.ClientLoginConnectionEvents;
|
|||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import ru.bclib.BCLib;
|
||||
import ru.bclib.api.dataexchange.handler.DataExchange;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -20,7 +25,10 @@ import java.util.function.Predicate;
|
|||
public class DataExchangeAPI extends DataExchange {
|
||||
private final static List<String> MODS = Lists.newArrayList();
|
||||
|
||||
protected DataExchangeAPI() {
|
||||
/**
|
||||
* You should never need to create a custom instance of this Object.
|
||||
*/
|
||||
public DataExchangeAPI() {
|
||||
super((api) -> new ConnectorClientside(api), (api) -> new ConnectorServerside(api));
|
||||
}
|
||||
|
||||
|
@ -47,8 +55,8 @@ public class DataExchangeAPI extends DataExchange {
|
|||
* @param desc The Descriptor you want to add.
|
||||
*/
|
||||
public static void registerDescriptor(DataHandlerDescriptor desc){
|
||||
DataExchangeAPI api = DataExchange.getInstance();
|
||||
api.descriptors.add(desc);
|
||||
DataExchange api = DataExchange.getInstance();
|
||||
api.getDescriptors().add(desc);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,10 +80,58 @@ public class DataExchangeAPI extends DataExchange {
|
|||
/**
|
||||
* Registers a File for automatic client syncing.
|
||||
*
|
||||
* @param needTransfer If the predicate returns true, the file needs to get copied to the server.
|
||||
* @param modID The ID of the calling Mod
|
||||
* @param fileName The name of the File
|
||||
*/
|
||||
public static void addAutoSyncFile(Predicate<Object> needTransfer, File fileName){
|
||||
DataExchangeAPI.getInstance().addAutoSyncFileData(needTransfer, fileName);
|
||||
public static void addAutoSyncFile(String modID, File fileName){
|
||||
getInstance().addAutoSyncFileData(modID, fileName, false, FileHash.NEED_TRANSFER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a File for automatic client syncing.
|
||||
*
|
||||
* @param modID The ID of the calling Mod
|
||||
* @param uniqueID A unique Identifier for the File. (see {@link ru.bclib.api.dataexchange.FileHash#uniqueID} for
|
||||
* Details
|
||||
* @param fileName The name of the File
|
||||
*/
|
||||
public static void addAutoSyncFile(String modID, String uniqueID, File fileName){
|
||||
getInstance().addAutoSyncFileData(modID, uniqueID, fileName, false, FileHash.NEED_TRANSFER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a File for automatic client syncing.
|
||||
*
|
||||
* @param modID The ID of the calling Mod
|
||||
* @param fileName The name of the File
|
||||
* @param requestContent When {@code true} the content of the file is requested for comparison. This will copy the
|
||||
* entire file from the client to the server.
|
||||
* <p>
|
||||
* You should only use this option, if you need to compare parts of the file in order to decide
|
||||
* If the File needs to be copied. Normally using the {@link ru.bclib.api.dataexchange.FileHash}
|
||||
* for comparison is sufficient.
|
||||
* @param needTransfer If the predicate returns true, the file needs to get copied to the server.
|
||||
*/
|
||||
public static void addAutoSyncFile(String modID, File fileName, boolean requestContent, NeedTransferPredicate needTransfer){
|
||||
getInstance().addAutoSyncFileData(modID, fileName, requestContent, needTransfer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a File for automatic client syncing.
|
||||
*
|
||||
* @param modID The ID of the calling Mod
|
||||
* @param uniqueID A unique Identifier for the File. (see {@link ru.bclib.api.dataexchange.FileHash#uniqueID} for
|
||||
* Details
|
||||
* @param fileName The name of the File
|
||||
* @param requestContent When {@code true} the content of the file is requested for comparison. This will copy the
|
||||
* entire file from the client to the server.
|
||||
* <p>
|
||||
* You should only use this option, if you need to compare parts of the file in order to decide
|
||||
* If the File needs to be copied. Normally using the {@link ru.bclib.api.dataexchange.FileHash}
|
||||
* for comparison is sufficient.
|
||||
* @param needTransfer If the predicate returns true, the file needs to get copied to the server.
|
||||
*/
|
||||
public static void addAutoSyncFile(String modID, String uniqueID, File fileName, boolean requestContent, NeedTransferPredicate needTransfer){
|
||||
getInstance().addAutoSyncFileData(modID, uniqueID, fileName, requestContent, needTransfer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,15 +49,15 @@ public abstract class DataHandler {
|
|||
server.execute(() -> runOnGameThread(null, server, false));
|
||||
}
|
||||
|
||||
protected void serializeData(FriendlyByteBuf buf) {
|
||||
}
|
||||
|
||||
protected void deserializeFromIncomingData(FriendlyByteBuf buf, PacketSender responseSender, boolean isClient){
|
||||
}
|
||||
|
||||
protected void runOnGameThread(Minecraft client, MinecraftServer server, boolean isClient){
|
||||
}
|
||||
|
||||
protected void serializeData(FriendlyByteBuf buf) {
|
||||
}
|
||||
|
||||
final protected boolean reply(DataHandler message, MinecraftServer server){
|
||||
if (lastMessageSender==null) return false;
|
||||
message.sendToClient(server, lastMessageSender);
|
||||
|
|
|
@ -3,6 +3,7 @@ package ru.bclib.api.dataexchange;
|
|||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import ru.bclib.BCLib;
|
||||
import ru.bclib.api.dataexchange.handler.DataExchange;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -12,6 +13,7 @@ import java.security.MessageDigest;
|
|||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Calculates a hash based on the contents of a File.
|
||||
|
@ -38,11 +40,47 @@ public class FileHash {
|
|||
*/
|
||||
public final int value;
|
||||
|
||||
FileHash(byte[] md5, int size, int value) {
|
||||
/**
|
||||
* A Unique ID for the referenced File.
|
||||
* <p>
|
||||
* Files with the same {@link #modID} need to have a unique IDs. Normally the filename from {@link #FileHash(String, File, byte[], int, int)}
|
||||
* is used to generated that ID, but you can directly specify one using {@link #FileHash(String, String, byte[], int, int)}.
|
||||
*/
|
||||
@NotNull
|
||||
public final String uniqueID;
|
||||
|
||||
/**
|
||||
* The ID of the Mod that is registering the File
|
||||
*/
|
||||
@NotNull
|
||||
public final String modID;
|
||||
|
||||
FileHash(String modID, File file, byte[] md5, int size, int value) {
|
||||
this(modID, file.getName(), md5, size, value);
|
||||
}
|
||||
|
||||
FileHash(String modID, String uniqueID, byte[] md5, int size, int value) {
|
||||
Objects.nonNull(modID);
|
||||
Objects.nonNull(uniqueID);
|
||||
Objects.nonNull(md5);
|
||||
|
||||
this.md5 = md5;
|
||||
this.size = size;
|
||||
this.value = value;
|
||||
this.modID = modID;
|
||||
this.uniqueID = uniqueID;
|
||||
}
|
||||
|
||||
private static int ERR_DOES_NOT_EXIST = -10;
|
||||
private static int ERR_IO_ERROR = -20;
|
||||
static FileHash createForEmpty(String modID, String uniqueID, int errCode){
|
||||
return new FileHash(modID, uniqueID, new byte[0], 0, errCode);
|
||||
}
|
||||
|
||||
final static DataExchange.NeedTransferPredicate NEED_TRANSFER = (clientHash, serverHash, content)-> !clientHash.equals(serverHash);
|
||||
|
||||
public boolean noFile() {
|
||||
return md5.length == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -58,13 +96,13 @@ public class FileHash {
|
|||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
FileHash that = (FileHash) o;
|
||||
return size == that.size && value == that.value && Arrays.equals(md5, that.md5);
|
||||
FileHash fileHash = (FileHash) o;
|
||||
return size == fileHash.size && value == fileHash.value && Arrays.equals(md5, fileHash.md5) && uniqueID.equals(fileHash.uniqueID) && modID.equals(fileHash.modID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = Objects.hash(size, value);
|
||||
int result = Objects.hash(size, value, uniqueID, modID);
|
||||
result = 31 * result + Arrays.hashCode(md5);
|
||||
return result;
|
||||
}
|
||||
|
@ -76,14 +114,17 @@ public class FileHash {
|
|||
public String getMd5String(){
|
||||
return toHexString(md5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the Object to a buffer
|
||||
* @param buf The buffer to write to
|
||||
*/
|
||||
public void writeString(FriendlyByteBuf buf) {
|
||||
public void serialize(FriendlyByteBuf buf) {
|
||||
buf.writeInt(size);
|
||||
buf.writeInt(value);
|
||||
buf.writeByteArray(md5);
|
||||
DataHandler.writeString(buf, modID);
|
||||
DataHandler.writeString(buf, uniqueID);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,12 +132,14 @@ public class FileHash {
|
|||
* @param buf Thea buffer to read from
|
||||
* @return The received String
|
||||
*/
|
||||
public static FileHash readString(FriendlyByteBuf buf){
|
||||
public static FileHash deserialize(FriendlyByteBuf buf){
|
||||
final int size = buf.readInt();
|
||||
final int value = buf.readInt();
|
||||
final byte[] md5 = buf.readByteArray();
|
||||
final String modID = DataHandler.readString(buf);
|
||||
final String uniqueID = DataHandler.readString(buf);
|
||||
|
||||
return new FileHash(md5, size, value);
|
||||
return new FileHash(modID, uniqueID, md5, size, value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -116,12 +159,28 @@ public class FileHash {
|
|||
|
||||
/**
|
||||
* Create a new {@link FileHash}.
|
||||
* <p>
|
||||
* Will call {@link #create(String, File, String)} using the name of the File as {@code uniqueID}.
|
||||
* @param modID ID of the calling Mod
|
||||
* @param file The input file
|
||||
*
|
||||
* @return A new Instance. You can compare instances using {@link #equals(Object)} to determine if two files are
|
||||
* identical.
|
||||
* identical. Will return {@code null} when an error occurs or the File does not exist
|
||||
*/
|
||||
public static FileHash createFromBinary(File file){
|
||||
if (!file.exists()) return null;
|
||||
public static FileHash create(String modID, File file){
|
||||
return create(modID, file, file.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link FileHash}.
|
||||
* @param modID ID of the calling Mod
|
||||
* @param file The input file
|
||||
* @param uniqueID The unique ID that is used for this File (see {@link FileHash#uniqueID} for Details.
|
||||
* @return A new Instance. You can compare instances using {@link #equals(Object)} to determine if two files are
|
||||
* identical. Will return {@code null} when an error occurs or the File does not exist
|
||||
*/
|
||||
public static FileHash create(String modID, File file, String uniqueID){
|
||||
if (!file.exists()) return createForEmpty(modID, uniqueID, ERR_DOES_NOT_EXIST);
|
||||
final Path path = file.toPath();
|
||||
|
||||
int size = 0;
|
||||
|
@ -140,12 +199,14 @@ public class FileHash {
|
|||
md.update(data);
|
||||
md5 = md.digest();
|
||||
|
||||
return new FileHash(md5, size, value);
|
||||
return new FileHash(modID, uniqueID, md5, size, value);
|
||||
} catch (IOException e) {
|
||||
BCLib.LOGGER.error("Failed to read file: " + file);
|
||||
return null;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
BCLib.LOGGER.error("Unable to build hash for file: " + file);
|
||||
}
|
||||
|
||||
return createForEmpty(modID, uniqueID, ERR_IO_ERROR);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,29 +5,117 @@ import net.fabricmc.api.Environment;
|
|||
import net.fabricmc.fabric.api.client.networking.v1.ClientLoginConnectionEvents;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import ru.bclib.api.dataexchange.ConnectorClientside;
|
||||
import ru.bclib.api.dataexchange.ConnectorServerside;
|
||||
import ru.bclib.api.dataexchange.DataExchangeAPI;
|
||||
import ru.bclib.api.dataexchange.DataHandler;
|
||||
import ru.bclib.api.dataexchange.DataHandlerDescriptor;
|
||||
import ru.bclib.api.dataexchange.FileHash;
|
||||
import ru.bclib.util.Pair;
|
||||
import ru.bclib.util.Triple;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
abstract public class DataExchange {
|
||||
private static class AutoFileSyncEntry {
|
||||
public final Predicate<Object> needTransfer;
|
||||
public final File fileName;
|
||||
@FunctionalInterface
|
||||
public interface NeedTransferPredicate {
|
||||
public boolean test(FileHash clientHash, FileHash serverHash, byte[] content);
|
||||
}
|
||||
|
||||
private AutoFileSyncEntry(Predicate<Object> needTransfer, File fileName) {
|
||||
final static class AutoSyncTriple extends Triple<FileHash, byte[], DataExchange.AutoFileSyncEntry>{
|
||||
public AutoSyncTriple(FileHash first, byte[] second, AutoFileSyncEntry third) {
|
||||
super(first, second, third);
|
||||
}
|
||||
}
|
||||
static class AutoFileSyncEntry {
|
||||
public final NeedTransferPredicate needTransfer;
|
||||
public final File fileName;
|
||||
public final String modID;
|
||||
public final String uniqueID;
|
||||
public final boolean requestContent;
|
||||
private FileHash hash;
|
||||
|
||||
AutoFileSyncEntry(String modID, File fileName, boolean requestContent, NeedTransferPredicate needTransfer) {
|
||||
this(modID, fileName.getName(), fileName, requestContent, needTransfer);
|
||||
}
|
||||
|
||||
AutoFileSyncEntry(String modID, String uniqueID, File fileName, boolean requestContent, NeedTransferPredicate needTransfer) {
|
||||
this.needTransfer = needTransfer;
|
||||
this.fileName = fileName;
|
||||
this.modID = modID;
|
||||
this.uniqueID = uniqueID;
|
||||
this.requestContent = requestContent;
|
||||
}
|
||||
|
||||
public FileHash getFileHash(){
|
||||
if (hash == null) {
|
||||
hash = FileHash.create(modID, fileName, uniqueID);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
public byte[] getContent(){
|
||||
if (!fileName.exists()) return new byte[0];
|
||||
final Path path = fileName.toPath();
|
||||
|
||||
try {
|
||||
return Files.readAllBytes(path);
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
|
||||
public void serialize(FriendlyByteBuf buf){
|
||||
getFileHash().serialize(buf);
|
||||
buf.writeBoolean(requestContent);
|
||||
|
||||
if (requestContent) {
|
||||
byte[] content = getContent();
|
||||
buf.writeInt(content.length);
|
||||
buf.writeByteArray(content);
|
||||
}
|
||||
}
|
||||
|
||||
public static AutoSyncTriple deserializeAndMatch(FriendlyByteBuf buf){
|
||||
Pair<FileHash, byte[]> e = deserialize(buf);
|
||||
AutoFileSyncEntry match = findMatching(e.first);
|
||||
return new AutoSyncTriple(e.first, e.second, match);
|
||||
}
|
||||
|
||||
public static Pair<FileHash, byte[]> deserialize(FriendlyByteBuf buf){
|
||||
FileHash hash = FileHash.deserialize(buf);
|
||||
boolean withContent = buf.readBoolean();
|
||||
byte[] data = null;
|
||||
if (withContent) {
|
||||
int size = buf.readInt();
|
||||
data = buf.readByteArray(size);
|
||||
}
|
||||
|
||||
return new Pair(hash, data);
|
||||
}
|
||||
|
||||
public static AutoFileSyncEntry findMatching(FileHash hash){
|
||||
return DataExchange
|
||||
.getInstance()
|
||||
.autoSyncFiles
|
||||
.stream()
|
||||
.filter(asf -> asf.modID.equals(hash.modID) && asf.uniqueID.equals(hash.uniqueID))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,8 +173,8 @@ abstract public class DataExchange {
|
|||
* This is automatically called by BCLib. You can register {@link DataHandler}-Objects before this Method is called
|
||||
*/
|
||||
@Environment(EnvType.CLIENT)
|
||||
public void prepareClientside(){
|
||||
DataExchangeAPI api = DataExchangeAPI.getInstance();
|
||||
public static void prepareClientside(){
|
||||
DataExchange api = DataExchange.getInstance();
|
||||
api.initClientside();
|
||||
|
||||
}
|
||||
|
@ -97,7 +185,7 @@ abstract public class DataExchange {
|
|||
* This is automatically called by BCLib. You can register {@link DataHandler}-Objects before this Method is called
|
||||
*/
|
||||
public static void prepareServerside(){
|
||||
DataExchange api = DataExchangeAPI.getInstance();
|
||||
DataExchange api = DataExchange.getInstance();
|
||||
api.initServerSide();
|
||||
}
|
||||
|
||||
|
@ -124,10 +212,36 @@ abstract public class DataExchange {
|
|||
/**
|
||||
* Registers a File for automatic client syncing.
|
||||
*
|
||||
* @param modID The ID of the calling Mod
|
||||
* @param needTransfer If the predicate returns true, the file needs to get copied to the server.
|
||||
* @param fileName The name of the File
|
||||
* @param requestContent When {@code true} the content of the file is requested for comparison. This will copy the
|
||||
* entire file from the client to the server.
|
||||
* <p>
|
||||
* You should only use this option, if you need to compare parts of the file in order to decide
|
||||
* If the File needs to be copied. Normally using the {@link ru.bclib.api.dataexchange.FileHash}
|
||||
* for comparison is sufficient.
|
||||
*/
|
||||
protected void addAutoSyncFileData(Predicate<Object> needTransfer, File fileName){
|
||||
autoSyncFiles.add(new AutoFileSyncEntry(needTransfer, fileName));
|
||||
protected void addAutoSyncFileData(String modID, File fileName, boolean requestContent, NeedTransferPredicate needTransfer){
|
||||
autoSyncFiles.add(new AutoFileSyncEntry(modID, fileName, requestContent, needTransfer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a File for automatic client syncing.
|
||||
*
|
||||
* @param modID The ID of the calling Mod
|
||||
* @param uniqueID A unique Identifier for the File. (see {@link ru.bclib.api.dataexchange.FileHash#uniqueID} for
|
||||
* Details
|
||||
* @param needTransfer If the predicate returns true, the file needs to get copied to the server.
|
||||
* @param fileName The name of the File
|
||||
* @param requestContent When {@code true} the content of the file is requested for comparison. This will copy the
|
||||
* entire file from the client to the server.
|
||||
* <p>
|
||||
* You should only use this option, if you need to compare parts of the file in order to decide
|
||||
* If the File needs to be copied. Normally using the {@link ru.bclib.api.dataexchange.FileHash}
|
||||
* for comparison is sufficient.
|
||||
*/
|
||||
protected void addAutoSyncFileData(String modID, String uniqueID, File fileName, boolean requestContent, NeedTransferPredicate needTransfer){
|
||||
autoSyncFiles.add(new AutoFileSyncEntry(modID, uniqueID, fileName, requestContent, needTransfer));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import net.fabricmc.loader.api.FabricLoader;
|
|||
import net.fabricmc.loader.api.ModContainer;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.client.gui.screens.worldselection.EditWorldScreen;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
@ -15,10 +14,12 @@ import ru.bclib.BCLib;
|
|||
import ru.bclib.api.dataexchange.DataExchangeAPI;
|
||||
import ru.bclib.api.dataexchange.DataHandler;
|
||||
import ru.bclib.api.dataexchange.DataHandlerDescriptor;
|
||||
import ru.bclib.api.dataexchange.FileHash;
|
||||
import ru.bclib.api.datafixer.DataFixerAPI;
|
||||
import ru.bclib.gui.screens.ConfirmFixScreen;
|
||||
import ru.bclib.gui.screens.WarnBCLibVersionMismatch;
|
||||
import ru.bclib.util.Triple;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -26,6 +27,11 @@ import java.util.Map.Entry;
|
|||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Sent from the Server to the Client.
|
||||
* <p>
|
||||
* For Details refer to {@link HelloServer}
|
||||
*/
|
||||
public class HelloClient extends DataHandler {
|
||||
public static DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "hello_client"), HelloClient::new, false, false);
|
||||
|
||||
|
@ -46,19 +52,55 @@ public class HelloClient extends DataHandler {
|
|||
return getModVersion(BCLib.MOD_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void serializeData(FriendlyByteBuf buf) {
|
||||
final List<String> mods = DataExchangeAPI.registeredMods();
|
||||
|
||||
//write BCLibVersion (=protocol version)
|
||||
buf.writeInt(DataFixerAPI.getModVersion(getBCLibVersion()));
|
||||
|
||||
//write Plugin Versions
|
||||
buf.writeInt(mods.size());
|
||||
for (String modID : mods) {
|
||||
writeString(buf, modID);
|
||||
buf.writeInt(DataFixerAPI.getModVersion(getModVersion(modID)));
|
||||
}
|
||||
|
||||
//send config Data
|
||||
final List<DataExchange.AutoFileSyncEntry> autoSyncFiles = DataExchange.getInstance().autoSyncFiles;
|
||||
buf.writeInt(autoSyncFiles.size());
|
||||
for (DataExchange.AutoFileSyncEntry entry : autoSyncFiles) {
|
||||
System.out.println("Serializing " + entry.getFileHash());
|
||||
entry.serialize(buf);
|
||||
}
|
||||
}
|
||||
|
||||
String bclibVersion ="0.0.0";
|
||||
Map<String, String> modVersion = new HashMap<>();
|
||||
List<DataExchange.AutoSyncTriple> autoSyncedFiles = null;
|
||||
@Override
|
||||
protected void deserializeFromIncomingData(FriendlyByteBuf buf, PacketSender responseSender, boolean fromClient) {
|
||||
//read BCLibVersion (=protocol version)
|
||||
bclibVersion = DataFixerAPI.getModVersion(buf.readInt());
|
||||
modVersion = new HashMap<>();
|
||||
|
||||
//read Plugin Versions
|
||||
modVersion = new HashMap<>();
|
||||
int count = buf.readInt();
|
||||
for (int i=0; i< count; i++) {
|
||||
String id = readString(buf);
|
||||
String version = DataFixerAPI.getModVersion(buf.readInt());
|
||||
modVersion.put(id, version);
|
||||
}
|
||||
|
||||
//read config Data
|
||||
count = buf.readInt();
|
||||
autoSyncedFiles = new ArrayList<>(count);
|
||||
for (int i=0; i< count; i++) {
|
||||
System.out.println("Deserializing ");
|
||||
DataExchange.AutoSyncTriple t = DataExchange.AutoFileSyncEntry.deserializeAndMatch(buf);
|
||||
autoSyncedFiles.add(t);
|
||||
System.out.println(t.first);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -75,17 +117,13 @@ public class HelloClient extends DataHandler {
|
|||
String ver = getModVersion(e.getKey());
|
||||
BCLib.LOGGER.info(" - " + e.getKey() + " (client="+ver+", server="+ver+")");
|
||||
}
|
||||
|
||||
for (DataExchange.AutoSyncTriple e : autoSyncedFiles) {
|
||||
if (e.third == null) {
|
||||
BCLib.LOGGER.info(" - File " + e.first.modID + "." + e.first.uniqueID + ": Does not exist on client.");
|
||||
} else if (e.third.needTransfer.test(e.third.getFileHash(), e.first, e.second)) {
|
||||
BCLib.LOGGER.info(" - File " + e.first.modID + "." + e.first.uniqueID + ": Needs Transfer");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void serializeData(FriendlyByteBuf buf) {
|
||||
final List<String> mods = DataExchangeAPI.registeredMods();
|
||||
buf.writeInt(DataFixerAPI.getModVersion(getBCLibVersion()));
|
||||
|
||||
buf.writeInt(mods.size());
|
||||
for (String modID : mods) {
|
||||
writeString(buf, modID);
|
||||
buf.writeInt(DataFixerAPI.getModVersion(getModVersion(modID)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,34 @@ import ru.bclib.api.dataexchange.DataHandler;
|
|||
import ru.bclib.api.dataexchange.DataHandlerDescriptor;
|
||||
import ru.bclib.api.datafixer.DataFixerAPI;
|
||||
|
||||
/**
|
||||
* This message is sent once a player enters the world. It initiates a sequence of Messages that will sync files between both
|
||||
* client and server.
|
||||
* <p>
|
||||
* <tab<le>
|
||||
* <tr>
|
||||
* <th>Server</th>
|
||||
* <th></th>
|
||||
* <th>Client</th>
|
||||
* <th></th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td colspan="4">Player enters World</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td></td>
|
||||
* <td><--</td>
|
||||
* <td>{@link HelloServer}</td>
|
||||
* <td>Sends the current BLib-Version installed on the Client</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link HelloClient}</td>
|
||||
* <td>--></td>
|
||||
* <td></td>
|
||||
* <td>Sends the current BClIb-Version and the Version of all Plugins on the Server</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public class HelloServer extends DataHandler {
|
||||
public static DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "hello_server"), HelloServer::new, false, true);
|
||||
|
||||
|
@ -18,6 +46,11 @@ public class HelloServer extends DataHandler {
|
|||
super(DESCRIPTOR.IDENTIFIER, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void serializeData(FriendlyByteBuf buf) {
|
||||
buf.writeInt(DataFixerAPI.getModVersion(HelloClient.getBCLibVersion()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deserializeFromIncomingData(FriendlyByteBuf buf, PacketSender responseSender, boolean fromClient) {
|
||||
bclibVersion = DataFixerAPI.getModVersion(buf.readInt());
|
||||
|
@ -29,9 +62,4 @@ public class HelloServer extends DataHandler {
|
|||
BCLib.LOGGER.info("Received Hello from Client. (server="+localBclibVersion+", client="+bclibVersion+")");
|
||||
reply(new HelloClient(), server);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void serializeData(FriendlyByteBuf buf) {
|
||||
buf.writeInt(DataFixerAPI.getModVersion(HelloClient.getBCLibVersion()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ public abstract class Config {
|
|||
this.registerEntries();
|
||||
this.autoSync = autoSync;
|
||||
|
||||
DataExchangeAPI.addAutoSyncFile((content)->{return false;}, keeper.getConfigFile());
|
||||
DataExchangeAPI.addAutoSyncFile(BCLib.MOD_ID, "CONFIG_"+modID+"_"+group, keeper.getConfigFile());
|
||||
}
|
||||
|
||||
public void saveChanges() {
|
||||
|
|
11
src/main/java/ru/bclib/util/Pair.java
Normal file
11
src/main/java/ru/bclib/util/Pair.java
Normal file
|
@ -0,0 +1,11 @@
|
|||
package ru.bclib.util;
|
||||
|
||||
public class Pair <A, B>{
|
||||
public final A first;
|
||||
public final B second;
|
||||
|
||||
public Pair(A first, B second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
}
|
10
src/main/java/ru/bclib/util/Triple.java
Normal file
10
src/main/java/ru/bclib/util/Triple.java
Normal file
|
@ -0,0 +1,10 @@
|
|||
package ru.bclib.util;
|
||||
|
||||
public class Triple <A, B, C> extends Pair<A, B>{
|
||||
public final C third;
|
||||
|
||||
public Triple(A first, B second, C third) {
|
||||
super(first, second);
|
||||
this.third = third;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue