Refactored AutoSync
This commit is contained in:
parent
b398e47056
commit
123a5e2dc4
17 changed files with 610 additions and 518 deletions
|
@ -7,10 +7,10 @@ import net.minecraft.resources.ResourceLocation;
|
||||||
import ru.bclib.api.TagAPI;
|
import ru.bclib.api.TagAPI;
|
||||||
import ru.bclib.api.WorldDataAPI;
|
import ru.bclib.api.WorldDataAPI;
|
||||||
import ru.bclib.api.dataexchange.DataExchangeAPI;
|
import ru.bclib.api.dataexchange.DataExchangeAPI;
|
||||||
import ru.bclib.api.dataexchange.handler.HelloClient;
|
import ru.bclib.api.dataexchange.handler.autosync.HelloClient;
|
||||||
import ru.bclib.api.dataexchange.handler.HelloServer;
|
import ru.bclib.api.dataexchange.handler.autosync.HelloServer;
|
||||||
import ru.bclib.api.dataexchange.handler.RequestFiles;
|
import ru.bclib.api.dataexchange.handler.autosync.RequestFiles;
|
||||||
import ru.bclib.api.dataexchange.handler.SendFiles;
|
import ru.bclib.api.dataexchange.handler.autosync.SendFiles;
|
||||||
import ru.bclib.api.datafixer.DataFixerAPI;
|
import ru.bclib.api.datafixer.DataFixerAPI;
|
||||||
import ru.bclib.config.Configs;
|
import ru.bclib.config.Configs;
|
||||||
import ru.bclib.recipes.CraftingRecipes;
|
import ru.bclib.recipes.CraftingRecipes;
|
||||||
|
|
|
@ -4,7 +4,9 @@ import com.google.common.collect.Lists;
|
||||||
import net.fabricmc.api.EnvType;
|
import net.fabricmc.api.EnvType;
|
||||||
import net.fabricmc.api.Environment;
|
import net.fabricmc.api.Environment;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import ru.bclib.api.dataexchange.handler.AutoSyncID;
|
import ru.bclib.api.dataexchange.handler.autosync.AutoSync;
|
||||||
|
import ru.bclib.api.dataexchange.handler.autosync.AutoSync.NeedTransferPredicate;
|
||||||
|
import ru.bclib.api.dataexchange.handler.autosync.AutoSyncID;
|
||||||
import ru.bclib.api.dataexchange.handler.DataExchange;
|
import ru.bclib.api.dataexchange.handler.DataExchange;
|
||||||
import ru.bclib.config.Config;
|
import ru.bclib.config.Config;
|
||||||
|
|
||||||
|
@ -98,7 +100,7 @@ public class DataExchangeAPI extends DataExchange {
|
||||||
* @param fileName The name of the File
|
* @param fileName The name of the File
|
||||||
*/
|
*/
|
||||||
public static void addAutoSyncFile(String modID, File fileName) {
|
public static void addAutoSyncFile(String modID, File fileName) {
|
||||||
getInstance().addAutoSyncFileData(modID, fileName, false, SyncFileHash.NEED_TRANSFER);
|
AutoSync.addAutoSyncFileData(modID, fileName, false, SyncFileHash.NEED_TRANSFER);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -113,7 +115,7 @@ public class DataExchangeAPI extends DataExchange {
|
||||||
* @param fileName The name of the File
|
* @param fileName The name of the File
|
||||||
*/
|
*/
|
||||||
public static void addAutoSyncFile(String modID, String uniqueID, File fileName) {
|
public static void addAutoSyncFile(String modID, String uniqueID, File fileName) {
|
||||||
getInstance().addAutoSyncFileData(modID, uniqueID, fileName, false, SyncFileHash.NEED_TRANSFER);
|
AutoSync.addAutoSyncFileData(modID, uniqueID, fileName, false, SyncFileHash.NEED_TRANSFER);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -131,7 +133,7 @@ public class DataExchangeAPI extends DataExchange {
|
||||||
* @param needTransfer If the predicate returns true, the file needs to get copied to the server.
|
* @param needTransfer If the predicate returns true, the file needs to get copied to the server.
|
||||||
*/
|
*/
|
||||||
public static void addAutoSyncFile(String modID, File fileName, NeedTransferPredicate needTransfer) {
|
public static void addAutoSyncFile(String modID, File fileName, NeedTransferPredicate needTransfer) {
|
||||||
getInstance().addAutoSyncFileData(modID, fileName, true, needTransfer);
|
AutoSync.addAutoSyncFileData(modID, fileName, true, needTransfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -151,7 +153,7 @@ public class DataExchangeAPI extends DataExchange {
|
||||||
* @param needTransfer If the predicate returns true, the file needs to get copied to the server.
|
* @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, NeedTransferPredicate needTransfer) {
|
public static void addAutoSyncFile(String modID, String uniqueID, File fileName, NeedTransferPredicate needTransfer) {
|
||||||
getInstance().addAutoSyncFileData(modID, uniqueID, fileName, true, needTransfer);
|
AutoSync.addAutoSyncFileData(modID, uniqueID, fileName, true, needTransfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -163,7 +165,7 @@ public class DataExchangeAPI extends DataExchange {
|
||||||
* @param callback A Function that receives the AutoSyncID as well as the Filename.
|
* @param callback A Function that receives the AutoSyncID as well as the Filename.
|
||||||
*/
|
*/
|
||||||
public static void addOnWriteCallback(BiConsumer<AutoSyncID, File> callback) {
|
public static void addOnWriteCallback(BiConsumer<AutoSyncID, File> callback) {
|
||||||
onWriteCallbacks.add(callback);
|
AutoSync.addOnWriteCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -175,7 +177,7 @@ public class DataExchangeAPI extends DataExchange {
|
||||||
* @return The path to the sync-folder
|
* @return The path to the sync-folder
|
||||||
*/
|
*/
|
||||||
public static File getModSyncFolder(String modID) {
|
public static File getModSyncFolder(String modID) {
|
||||||
File fl = SYNC_FOLDER.localFolder.resolve(modID.replace(".", "-")
|
File fl = AutoSync.SYNC_FOLDER.localFolder.resolve(modID.replace(".", "-")
|
||||||
.replace(":", "-")
|
.replace(":", "-")
|
||||||
.replace("\\", "-")
|
.replace("\\", "-")
|
||||||
.replace("/", "-"))
|
.replace("/", "-"))
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package ru.bclib.api.dataexchange;
|
package ru.bclib.api.dataexchange;
|
||||||
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import ru.bclib.api.dataexchange.handler.AutoSyncID;
|
import ru.bclib.api.dataexchange.handler.autosync.AutoSync.NeedTransferPredicate;
|
||||||
import ru.bclib.api.dataexchange.handler.DataExchange;
|
import ru.bclib.api.dataexchange.handler.autosync.AutoSyncID;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -36,7 +36,7 @@ public class SyncFileHash extends AutoSyncID {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
final static DataExchange.NeedTransferPredicate NEED_TRANSFER = (clientHash, serverHash, content)-> !clientHash.equals(serverHash);
|
final static NeedTransferPredicate NEED_TRANSFER = (clientHash, serverHash, content)-> !clientHash.equals(serverHash);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|
|
@ -4,255 +4,17 @@ import net.fabricmc.api.EnvType;
|
||||||
import net.fabricmc.api.Environment;
|
import net.fabricmc.api.Environment;
|
||||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
|
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
|
||||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import ru.bclib.BCLib;
|
|
||||||
import ru.bclib.api.dataexchange.ConnectorClientside;
|
import ru.bclib.api.dataexchange.ConnectorClientside;
|
||||||
import ru.bclib.api.dataexchange.ConnectorServerside;
|
import ru.bclib.api.dataexchange.ConnectorServerside;
|
||||||
import ru.bclib.api.dataexchange.DataExchangeAPI;
|
import ru.bclib.api.dataexchange.DataExchangeAPI;
|
||||||
import ru.bclib.api.dataexchange.DataHandler;
|
import ru.bclib.api.dataexchange.DataHandler;
|
||||||
import ru.bclib.api.dataexchange.DataHandlerDescriptor;
|
import ru.bclib.api.dataexchange.DataHandlerDescriptor;
|
||||||
import ru.bclib.api.dataexchange.FileHash;
|
|
||||||
import ru.bclib.api.dataexchange.SyncFileHash;
|
|
||||||
import ru.bclib.api.dataexchange.handler.AutoSyncID.ForDirectFileRequest;
|
|
||||||
import ru.bclib.config.Configs;
|
|
||||||
import ru.bclib.util.PathUtil;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
abstract public class DataExchange {
|
abstract public class DataExchange {
|
||||||
|
|
||||||
public final static SyncFolderDescriptor SYNC_FOLDER = new SyncFolderDescriptor("BCLIB-SYNC", FabricLoader.getInstance()
|
|
||||||
.getGameDir()
|
|
||||||
.resolve("bclib-sync")
|
|
||||||
.normalize()
|
|
||||||
.toAbsolutePath(), true);
|
|
||||||
final List<SyncFolderDescriptor> syncFolderDescriptions = Arrays.asList(SYNC_FOLDER);
|
|
||||||
|
|
||||||
public static class SyncFolderDescriptor {
|
|
||||||
static class SubFile {
|
|
||||||
public final String relPath;
|
|
||||||
public final FileHash hash;
|
|
||||||
|
|
||||||
|
|
||||||
SubFile(String relPath, FileHash hash) {
|
|
||||||
this.relPath = relPath;
|
|
||||||
this.hash = hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return relPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void serialize(FriendlyByteBuf buf) {
|
|
||||||
DataHandler.writeString(buf, relPath);
|
|
||||||
hash.serialize(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SubFile deserialize(FriendlyByteBuf buf) {
|
|
||||||
final String relPath = DataHandler.readString(buf);
|
|
||||||
FileHash hash = FileHash.deserialize(buf);
|
|
||||||
return new SubFile(relPath, hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o instanceof String) return relPath.equals(o);
|
|
||||||
if (!(o instanceof SubFile)) return false;
|
|
||||||
SubFile subFile = (SubFile) o;
|
|
||||||
return relPath.equals(subFile.relPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return relPath.hashCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public final String folderID;
|
|
||||||
public final boolean removeAdditionalFiles;
|
|
||||||
@NotNull
|
|
||||||
public final Path localFolder;
|
|
||||||
|
|
||||||
private List<SubFile> fileCache;
|
|
||||||
|
|
||||||
SyncFolderDescriptor(String folderID, Path localFolder, boolean removeAdditionalFiles) {
|
|
||||||
this.removeAdditionalFiles = removeAdditionalFiles;
|
|
||||||
this.folderID = folderID;
|
|
||||||
this.localFolder = localFolder;
|
|
||||||
fileCache = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "SyncFolderDescriptor{" + "folderID='" + folderID + '\'' + ", removeAdditionalFiles=" + removeAdditionalFiles + ", localFolder=" + localFolder + ", files=" + (fileCache == null ? "?" : fileCache.size()) + "}";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o instanceof String) {
|
|
||||||
return folderID.equals(o);
|
|
||||||
}
|
|
||||||
if (o instanceof AutoSyncID.ForDirectFileRequest) {
|
|
||||||
return folderID.equals(((ForDirectFileRequest) o).uniqueID);
|
|
||||||
}
|
|
||||||
if (!(o instanceof SyncFolderDescriptor)) return false;
|
|
||||||
SyncFolderDescriptor that = (SyncFolderDescriptor) o;
|
|
||||||
return folderID.equals(that.folderID);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return folderID.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int fileCount() {
|
|
||||||
return fileCache == null ? 0 : fileCache.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void invalidateCache() {
|
|
||||||
fileCache = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void loadCache() {
|
|
||||||
if (fileCache == null) {
|
|
||||||
fileCache = new ArrayList<>(8);
|
|
||||||
PathUtil.fileWalker(localFolder.toFile(), p -> fileCache.add(new SubFile(localFolder.relativize(p)
|
|
||||||
.toString(), FileHash.create(p.toFile()))));
|
|
||||||
|
|
||||||
/*//this tests if we can trick the system to load files that are not beneath the base-folder
|
|
||||||
if (!BCLib.isClient()) {
|
|
||||||
fileCache.add(new SubFile("../breakout.json", FileHash.create(mapAbsolute("../breakout.json").toFile())));
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void serialize(FriendlyByteBuf buf) {
|
|
||||||
final boolean debugHashes = Configs.CLIENT_CONFIG.getBoolean(Configs.MAIN_SYNC_CATEGORY, "debugHashes", false);
|
|
||||||
loadCache();
|
|
||||||
|
|
||||||
DataHandler.writeString(buf, folderID);
|
|
||||||
buf.writeBoolean(removeAdditionalFiles);
|
|
||||||
buf.writeInt(fileCache.size());
|
|
||||||
fileCache.forEach(fl -> {
|
|
||||||
BCLib.LOGGER.info(" - " + fl.relPath);
|
|
||||||
if (debugHashes) {
|
|
||||||
BCLib.LOGGER.info(" " + fl.hash);
|
|
||||||
}
|
|
||||||
fl.serialize(buf);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SyncFolderDescriptor deserialize(FriendlyByteBuf buf) {
|
|
||||||
final String folderID = DataHandler.readString(buf);
|
|
||||||
final boolean remAddFiles = buf.readBoolean();
|
|
||||||
final int count = buf.readInt();
|
|
||||||
SyncFolderDescriptor localDescriptor = DataExchange.getInstance()
|
|
||||||
.getSyncFolderDescriptor(folderID);
|
|
||||||
|
|
||||||
final SyncFolderDescriptor desc;
|
|
||||||
if (localDescriptor != null) {
|
|
||||||
desc = new SyncFolderDescriptor(folderID, localDescriptor.localFolder, remAddFiles);
|
|
||||||
desc.fileCache = new ArrayList<>(count);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
BCLib.LOGGER.warning(BCLib.isClient() ? "Client" : "Server" + " does not know Sync-Folder ID '" + folderID + "'");
|
|
||||||
desc = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
SubFile relPath = SubFile.deserialize(buf);
|
|
||||||
if (desc != null) desc.fileCache.add(relPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
return desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Note: make sure loadCache was called before using this
|
|
||||||
boolean hasRelativeFile(String relFile) {
|
|
||||||
return fileCache.stream()
|
|
||||||
.filter(sf -> sf.equals(relFile))
|
|
||||||
.findFirst()
|
|
||||||
.isPresent();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Note: make sure loadCache was called before using this
|
|
||||||
boolean hasRelativeFile(SubFile subFile) {
|
|
||||||
return hasRelativeFile(subFile.relPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Note: make sure loadCache was called before using this
|
|
||||||
SubFile getLocalSubFile(String relPath) {
|
|
||||||
return fileCache.stream()
|
|
||||||
.filter(sf -> sf.relPath.equals(relPath))
|
|
||||||
.findFirst()
|
|
||||||
.orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
Stream<SubFile> relativeFilesStream() {
|
|
||||||
loadCache();
|
|
||||||
return fileCache.stream();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Path mapAbsolute(String relPath) {
|
|
||||||
return this.localFolder.resolve(relPath)
|
|
||||||
.normalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Path mapAbsolute(SubFile subFile) {
|
|
||||||
return this.localFolder.resolve(subFile.relPath)
|
|
||||||
.normalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean acceptChildElements(Path absPath) {
|
|
||||||
return PathUtil.isChildOf(this.localFolder, absPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean acceptChildElements(SubFile subFile) {
|
|
||||||
return acceptChildElements(mapAbsolute(subFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean discardChildElements(SubFile subFile) {
|
|
||||||
return !acceptChildElements(subFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface NeedTransferPredicate {
|
|
||||||
public boolean test(SyncFileHash clientHash, SyncFileHash serverHash, FileContentWrapper content);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final static List<BiConsumer<AutoSyncID, File>> onWriteCallbacks = new ArrayList<>(2);
|
|
||||||
|
|
||||||
final static class AutoSyncTriple {
|
|
||||||
public final SyncFileHash serverHash;
|
|
||||||
public final byte[] serverContent;
|
|
||||||
public final AutoFileSyncEntry localMatch;
|
|
||||||
|
|
||||||
public AutoSyncTriple(SyncFileHash serverHash, byte[] serverContent, AutoFileSyncEntry localMatch) {
|
|
||||||
this.serverHash = serverHash;
|
|
||||||
this.serverContent = serverContent;
|
|
||||||
this.localMatch = localMatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return serverHash.modID + "." + serverHash.uniqueID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static DataExchangeAPI instance;
|
private static DataExchangeAPI instance;
|
||||||
|
|
||||||
|
@ -266,7 +28,7 @@ abstract public class DataExchange {
|
||||||
protected ConnectorServerside server;
|
protected ConnectorServerside server;
|
||||||
protected ConnectorClientside client;
|
protected ConnectorClientside client;
|
||||||
protected final Set<DataHandlerDescriptor> descriptors;
|
protected final Set<DataHandlerDescriptor> descriptors;
|
||||||
private final List<AutoFileSyncEntry> autoSyncFiles = new ArrayList<>(4);
|
|
||||||
|
|
||||||
private boolean didLoadSyncFolder = false;
|
private boolean didLoadSyncFolder = false;
|
||||||
|
|
||||||
|
@ -280,9 +42,6 @@ abstract public class DataExchange {
|
||||||
|
|
||||||
public Set<DataHandlerDescriptor> getDescriptors() { return descriptors; }
|
public Set<DataHandlerDescriptor> getDescriptors() { return descriptors; }
|
||||||
|
|
||||||
public List<AutoFileSyncEntry> getAutoSyncFiles() {
|
|
||||||
return autoSyncFiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Environment(EnvType.CLIENT)
|
@Environment(EnvType.CLIENT)
|
||||||
protected void initClientside() {
|
protected void initClientside() {
|
||||||
|
@ -344,101 +103,6 @@ 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 SyncFileHash}
|
|
||||||
* for comparison is sufficient.
|
|
||||||
*/
|
|
||||||
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 SyncFileHash#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 SyncFileHash}
|
|
||||||
* 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when {@code SendFiles} received a File on the Client and wrote it to the FileSystem.
|
|
||||||
* <p>
|
|
||||||
* This is the place where reload Code should go.
|
|
||||||
*
|
|
||||||
* @param aid The ID of the received File
|
|
||||||
* @param file The location of the FIle on the client
|
|
||||||
*/
|
|
||||||
static void didReceiveFile(AutoSyncID aid, File file) {
|
|
||||||
onWriteCallbacks.forEach(fkt -> fkt.accept(aid, file));
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> syncFolderContent;
|
|
||||||
|
|
||||||
protected List<String> getSyncFolderContent() {
|
|
||||||
if (syncFolderContent == null) {
|
|
||||||
return new ArrayList<>(0);
|
|
||||||
}
|
|
||||||
return syncFolderContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
//we call this from HelloServer to prepare transfer
|
|
||||||
protected void loadSyncFolder() {
|
|
||||||
if (Configs.MAIN_CONFIG.getBoolean(Configs.MAIN_SYNC_CATEGORY, "offersSyncFolders", true)) {
|
|
||||||
syncFolderDescriptions.forEach(desc -> desc.loadCache());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static SyncFolderDescriptor getSyncFolderDescriptor(String folderID) {
|
|
||||||
return ((DataExchange) getInstance()).syncFolderDescriptions.stream()
|
|
||||||
.filter(d -> d.equals(folderID))
|
|
||||||
.findFirst()
|
|
||||||
.orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static Path localBasePathForFolderID(String folderID) {
|
|
||||||
final SyncFolderDescriptor desc = getSyncFolderDescriptor(folderID);
|
|
||||||
if (desc != null) {
|
|
||||||
return desc.localFolder;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
BCLib.LOGGER.warning("Unknown Sync-Folder ID '" + folderID + "'");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void registerSyncFolder(String folderID, Path localBaseFolder, boolean removeAdditionalFiles) {
|
|
||||||
localBaseFolder = localBaseFolder.normalize();
|
|
||||||
if (PathUtil.isChildOf(PathUtil.GAME_FOLDER, localBaseFolder)) {
|
|
||||||
final SyncFolderDescriptor desc = new SyncFolderDescriptor(folderID, localBaseFolder, removeAdditionalFiles);
|
|
||||||
if (this.syncFolderDescriptions.contains(desc)) {
|
|
||||||
BCLib.LOGGER.warning("Tried to override Folder Sync '" + folderID + "' again.");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.syncFolderDescriptions.add(desc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
BCLib.LOGGER.error(localBaseFolder + " (from " + folderID + ") is outside the game directory " + PathUtil.GAME_FOLDER + ". Sync is not allowed.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package ru.bclib.api.dataexchange.handler;
|
package ru.bclib.api.dataexchange.handler.autosync;
|
||||||
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import ru.bclib.api.dataexchange.DataHandler;
|
import ru.bclib.api.dataexchange.DataHandler;
|
||||||
import ru.bclib.api.dataexchange.SyncFileHash;
|
import ru.bclib.api.dataexchange.SyncFileHash;
|
||||||
import ru.bclib.api.dataexchange.handler.DataExchange.SyncFolderDescriptor;
|
import ru.bclib.api.dataexchange.handler.autosync.AutoSync.NeedTransferPredicate;
|
||||||
import ru.bclib.api.dataexchange.handler.DataExchange.SyncFolderDescriptor.SubFile;
|
import ru.bclib.api.dataexchange.handler.autosync.SyncFolderDescriptor.SubFile;
|
||||||
import ru.bclib.util.Pair;
|
import ru.bclib.util.Pair;
|
||||||
import ru.bclib.util.Triple;
|
import ru.bclib.util.Triple;
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
class AutoFileSyncEntry extends AutoSyncID {
|
class AutoFileSyncEntry extends AutoSyncID {
|
||||||
static class ForDirectFileRequest extends AutoFileSyncEntry {
|
static class ForDirectFileRequest extends AutoFileSyncEntry {
|
||||||
final File relFile;
|
final File relFile;
|
||||||
|
|
||||||
ForDirectFileRequest(String syncID, File relFile, File absFile) {
|
ForDirectFileRequest(String syncID, File relFile, File absFile) {
|
||||||
|
@ -30,10 +30,10 @@ class AutoFileSyncEntry extends AutoSyncID {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static AutoFileSyncEntry.ForDirectFileRequest finishDeserializeContent(String syncID, FriendlyByteBuf buf){
|
static AutoFileSyncEntry.ForDirectFileRequest finishDeserializeContent(String syncID, FriendlyByteBuf buf) {
|
||||||
final String relFile = DataHandler.readString(buf);
|
final String relFile = DataHandler.readString(buf);
|
||||||
SyncFolderDescriptor desc = DataExchange.getSyncFolderDescriptor(syncID);
|
SyncFolderDescriptor desc = AutoSync.getSyncFolderDescriptor(syncID);
|
||||||
if (desc!=null) {
|
if (desc != null) {
|
||||||
//ensures that the file is not above the base-folder
|
//ensures that the file is not above the base-folder
|
||||||
if (desc.acceptChildElements(desc.mapAbsolute(relFile))) {
|
if (desc.acceptChildElements(desc.mapAbsolute(relFile))) {
|
||||||
return new AutoFileSyncEntry.ForDirectFileRequest(syncID, new File(relFile), desc.localFolder.resolve(relFile)
|
return new AutoFileSyncEntry.ForDirectFileRequest(syncID, new File(relFile), desc.localFolder.resolve(relFile)
|
||||||
|
@ -49,16 +49,17 @@ class AutoFileSyncEntry extends AutoSyncID {
|
||||||
return uniqueID + " - " + relFile;
|
return uniqueID + " - " + relFile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public final DataExchange.NeedTransferPredicate needTransfer;
|
|
||||||
|
public final NeedTransferPredicate needTransfer;
|
||||||
public final File fileName;
|
public final File fileName;
|
||||||
public final boolean requestContent;
|
public final boolean requestContent;
|
||||||
private SyncFileHash hash;
|
private SyncFileHash hash;
|
||||||
|
|
||||||
AutoFileSyncEntry(String modID, File fileName, boolean requestContent, DataExchange.NeedTransferPredicate needTransfer) {
|
AutoFileSyncEntry(String modID, File fileName, boolean requestContent, NeedTransferPredicate needTransfer) {
|
||||||
this(modID, fileName.getName(), fileName, requestContent, needTransfer);
|
this(modID, fileName.getName(), fileName, requestContent, needTransfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoFileSyncEntry(String modID, String uniqueID, File fileName, boolean requestContent, DataExchange.NeedTransferPredicate needTransfer) {
|
AutoFileSyncEntry(String modID, String uniqueID, File fileName, boolean requestContent, NeedTransferPredicate needTransfer) {
|
||||||
super(modID, uniqueID);
|
super(modID, uniqueID);
|
||||||
this.needTransfer = needTransfer;
|
this.needTransfer = needTransfer;
|
||||||
this.fileName = fileName;
|
this.fileName = fileName;
|
||||||
|
@ -97,9 +98,10 @@ class AutoFileSyncEntry extends AutoSyncID {
|
||||||
byte[] data = deserializeFileContent(buf);
|
byte[] data = deserializeFileContent(buf);
|
||||||
|
|
||||||
AutoFileSyncEntry entry;
|
AutoFileSyncEntry entry;
|
||||||
if (AutoSyncID.ForDirectFileRequest.MOD_ID.equals(modID)){
|
if (AutoSyncID.ForDirectFileRequest.MOD_ID.equals(modID)) {
|
||||||
entry = AutoFileSyncEntry.ForDirectFileRequest.finishDeserializeContent(uniqueID, buf);
|
entry = AutoFileSyncEntry.ForDirectFileRequest.finishDeserializeContent(uniqueID, buf);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
entry = AutoFileSyncEntry.findMatching(modID, uniqueID);
|
entry = AutoFileSyncEntry.findMatching(modID, uniqueID);
|
||||||
}
|
}
|
||||||
return new Triple<>(entry, data, new AutoSyncID(modID, uniqueID));
|
return new Triple<>(entry, data, new AutoSyncID(modID, uniqueID));
|
||||||
|
@ -115,10 +117,10 @@ class AutoFileSyncEntry extends AutoSyncID {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DataExchange.AutoSyncTriple deserializeAndMatch(FriendlyByteBuf buf) {
|
public static AutoSync.AutoSyncTriple deserializeAndMatch(FriendlyByteBuf buf) {
|
||||||
Pair<SyncFileHash, byte[]> e = deserialize(buf);
|
Pair<SyncFileHash, byte[]> e = deserialize(buf);
|
||||||
AutoFileSyncEntry match = findMatching(e.first);
|
AutoFileSyncEntry match = findMatching(e.first);
|
||||||
return new DataExchange.AutoSyncTriple(e.first, e.second, match);
|
return new AutoSync.AutoSyncTriple(e.first, e.second, match);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pair<SyncFileHash, byte[]> deserialize(FriendlyByteBuf buf) {
|
public static Pair<SyncFileHash, byte[]> deserialize(FriendlyByteBuf buf) {
|
||||||
|
@ -154,15 +156,13 @@ class AutoFileSyncEntry extends AutoSyncID {
|
||||||
public static AutoFileSyncEntry findMatching(AutoSyncID aid) {
|
public static AutoFileSyncEntry findMatching(AutoSyncID aid) {
|
||||||
if (aid instanceof AutoSyncID.ForDirectFileRequest) {
|
if (aid instanceof AutoSyncID.ForDirectFileRequest) {
|
||||||
AutoSyncID.ForDirectFileRequest freq = (AutoSyncID.ForDirectFileRequest) aid;
|
AutoSyncID.ForDirectFileRequest freq = (AutoSyncID.ForDirectFileRequest) aid;
|
||||||
SyncFolderDescriptor desc = DataExchange.getSyncFolderDescriptor(freq.uniqueID);
|
SyncFolderDescriptor desc = AutoSync.getSyncFolderDescriptor(freq.uniqueID);
|
||||||
if (desc != null) {
|
if (desc != null) {
|
||||||
SubFile subFile = desc.getLocalSubFile(freq.relFile.toString());
|
SubFile subFile = desc.getLocalSubFile(freq.relFile.toString());
|
||||||
if (subFile != null) {
|
if (subFile != null) {
|
||||||
final File absPath = desc
|
final File absPath = desc.localFolder.resolve(subFile.relPath)
|
||||||
.localFolder
|
.normalize()
|
||||||
.resolve(subFile.relPath)
|
.toFile();
|
||||||
.normalize()
|
|
||||||
.toFile();
|
|
||||||
return new AutoFileSyncEntry.ForDirectFileRequest(freq.uniqueID, new File(subFile.relPath), absPath);
|
return new AutoFileSyncEntry.ForDirectFileRequest(freq.uniqueID, new File(subFile.relPath), absPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,11 +172,10 @@ class AutoFileSyncEntry extends AutoSyncID {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AutoFileSyncEntry findMatching(String modID, String uniqueID) {
|
public static AutoFileSyncEntry findMatching(String modID, String uniqueID) {
|
||||||
return DataExchange.getInstance()
|
return AutoSync.getAutoSyncFiles()
|
||||||
.getAutoSyncFiles()
|
.stream()
|
||||||
.stream()
|
.filter(asf -> asf.modID.equals(modID) && asf.uniqueID.equals(uniqueID))
|
||||||
.filter(asf -> asf.modID.equals(modID) && asf.uniqueID.equals(uniqueID))
|
.findFirst()
|
||||||
.findFirst()
|
.orElse(null);
|
||||||
.orElse(null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,210 @@
|
||||||
|
package ru.bclib.api.dataexchange.handler.autosync;
|
||||||
|
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import ru.bclib.BCLib;
|
||||||
|
import ru.bclib.api.dataexchange.SyncFileHash;
|
||||||
|
import ru.bclib.config.Configs;
|
||||||
|
import ru.bclib.util.PathUtil;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
public class AutoSync {
|
||||||
|
public static final String MAIN_SYNC_CATEGORY = "client_sync";
|
||||||
|
public final static SyncFolderDescriptor SYNC_FOLDER = new SyncFolderDescriptor("BCLIB-SYNC", FabricLoader.getInstance()
|
||||||
|
.getGameDir()
|
||||||
|
.resolve("bclib-sync")
|
||||||
|
.normalize()
|
||||||
|
.toAbsolutePath(), true);
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface NeedTransferPredicate {
|
||||||
|
public boolean test(SyncFileHash clientHash, SyncFileHash serverHash, FileContentWrapper content);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
public static class ClientConfig {
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
static boolean shouldClientConfigPrintDebugHashes() {
|
||||||
|
return Configs.CLIENT_CONFIG.getBoolean(MAIN_SYNC_CATEGORY, "debugHashes", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
static boolean isClientConfigAllowingAutoSync() {
|
||||||
|
return Configs.CLIENT_CONFIG.getBoolean(MAIN_SYNC_CATEGORY, "enabled", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
static boolean isClientConfigAcceptingFiles() {
|
||||||
|
return Configs.CLIENT_CONFIG.getBoolean(MAIN_SYNC_CATEGORY, "acceptFiles", true) && isClientConfigAllowingAutoSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
static boolean isClientConfigAcceptingFolders() {
|
||||||
|
return Configs.CLIENT_CONFIG.getBoolean(MAIN_SYNC_CATEGORY, "acceptFolders", true) && isClientConfigAllowingAutoSync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Config {
|
||||||
|
static boolean isAllowingAutoSync() {
|
||||||
|
return Configs.MAIN_CONFIG.getBoolean(MAIN_SYNC_CATEGORY, "enabled", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isOfferingFiles() {
|
||||||
|
return Configs.MAIN_CONFIG.getBoolean(MAIN_SYNC_CATEGORY, "offerFiles", true) && ClientConfig.isClientConfigAllowingAutoSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isOfferingFolders() {
|
||||||
|
return Configs.MAIN_CONFIG.getBoolean(MAIN_SYNC_CATEGORY, "offerFolders", true) && ClientConfig.isClientConfigAllowingAutoSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isOfferingMods() {
|
||||||
|
return Configs.MAIN_CONFIG.getBoolean(MAIN_SYNC_CATEGORY, "offerMods", true) && ClientConfig.isClientConfigAllowingAutoSync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final static class AutoSyncTriple {
|
||||||
|
public final SyncFileHash serverHash;
|
||||||
|
public final byte[] serverContent;
|
||||||
|
public final AutoFileSyncEntry localMatch;
|
||||||
|
|
||||||
|
public AutoSyncTriple(SyncFileHash serverHash, byte[] serverContent, AutoFileSyncEntry localMatch) {
|
||||||
|
this.serverHash = serverHash;
|
||||||
|
this.serverContent = serverContent;
|
||||||
|
this.localMatch = localMatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return serverHash.modID + "." + serverHash.uniqueID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ##### File Syncing
|
||||||
|
protected final static List<BiConsumer<AutoSyncID, File>> onWriteCallbacks = new ArrayList<>(2);
|
||||||
|
/**
|
||||||
|
* Register a function that is called whenever the client receives a file from the server and replaced toe local
|
||||||
|
* file with the new content.
|
||||||
|
* <p>
|
||||||
|
* This callback is usefull if you need to reload the new content before the game is quit.
|
||||||
|
*
|
||||||
|
* @param callback A Function that receives the AutoSyncID as well as the Filename.
|
||||||
|
*/
|
||||||
|
public static void addOnWriteCallback(BiConsumer<AutoSyncID, File> callback) {
|
||||||
|
onWriteCallbacks.add(callback);
|
||||||
|
}
|
||||||
|
private static final List<AutoFileSyncEntry> autoSyncFiles = new ArrayList<>(4);
|
||||||
|
|
||||||
|
public static List<AutoFileSyncEntry> getAutoSyncFiles() {
|
||||||
|
return autoSyncFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 SyncFileHash}
|
||||||
|
* for comparison is sufficient.
|
||||||
|
*/
|
||||||
|
public static 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 SyncFileHash#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 SyncFileHash}
|
||||||
|
* for comparison is sufficient.
|
||||||
|
*/
|
||||||
|
public static void addAutoSyncFileData(String modID, String uniqueID, File fileName, boolean requestContent, NeedTransferPredicate needTransfer) {
|
||||||
|
autoSyncFiles.add(new AutoFileSyncEntry(modID, uniqueID, fileName, requestContent, needTransfer));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when {@code SendFiles} received a File on the Client and wrote it to the FileSystem.
|
||||||
|
* <p>
|
||||||
|
* This is the place where reload Code should go.
|
||||||
|
*
|
||||||
|
* @param aid The ID of the received File
|
||||||
|
* @param file The location of the FIle on the client
|
||||||
|
*/
|
||||||
|
static void didReceiveFile(AutoSyncID aid, File file) {
|
||||||
|
onWriteCallbacks.forEach(fkt -> fkt.accept(aid, file));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ##### Folder Syncing
|
||||||
|
static final List<SyncFolderDescriptor> syncFolderDescriptions = Arrays.asList(SYNC_FOLDER);
|
||||||
|
|
||||||
|
private List<String> syncFolderContent;
|
||||||
|
|
||||||
|
protected List<String> getSyncFolderContent() {
|
||||||
|
if (syncFolderContent == null) {
|
||||||
|
return new ArrayList<>(0);
|
||||||
|
}
|
||||||
|
return syncFolderContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
//we call this from HelloServer to prepare transfer
|
||||||
|
protected static void loadSyncFolder() {
|
||||||
|
if (Configs.MAIN_CONFIG.getBoolean(AutoSync.MAIN_SYNC_CATEGORY, "offersSyncFolders", true)) {
|
||||||
|
syncFolderDescriptions.forEach(desc -> desc.loadCache());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static SyncFolderDescriptor getSyncFolderDescriptor(String folderID) {
|
||||||
|
return syncFolderDescriptions.stream()
|
||||||
|
.filter(d -> d.equals(folderID))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static Path localBasePathForFolderID(String folderID) {
|
||||||
|
final SyncFolderDescriptor desc = getSyncFolderDescriptor(folderID);
|
||||||
|
if (desc != null) {
|
||||||
|
return desc.localFolder;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BCLib.LOGGER.warning("Unknown Sync-Folder ID '" + folderID + "'");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void registerSyncFolder(String folderID, Path localBaseFolder, boolean removeAdditionalFiles) {
|
||||||
|
localBaseFolder = localBaseFolder.normalize();
|
||||||
|
if (PathUtil.isChildOf(PathUtil.GAME_FOLDER, localBaseFolder)) {
|
||||||
|
final SyncFolderDescriptor desc = new SyncFolderDescriptor(folderID, localBaseFolder, removeAdditionalFiles);
|
||||||
|
if (syncFolderDescriptions.contains(desc)) {
|
||||||
|
BCLib.LOGGER.warning("Tried to override Folder Sync '" + folderID + "' again.");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
syncFolderDescriptions.add(desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BCLib.LOGGER.error(localBaseFolder + " (from " + folderID + ") is outside the game directory " + PathUtil.GAME_FOLDER + ". Sync is not allowed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package ru.bclib.api.dataexchange.handler;
|
package ru.bclib.api.dataexchange.handler.autosync;
|
||||||
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
|
@ -1,4 +1,4 @@
|
||||||
package ru.bclib.api.dataexchange.handler;
|
package ru.bclib.api.dataexchange.handler.autosync;
|
||||||
|
|
||||||
import ru.bclib.BCLib;
|
import ru.bclib.BCLib;
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
package ru.bclib.api.dataexchange.handler;
|
package ru.bclib.api.dataexchange.handler.autosync;
|
||||||
|
|
||||||
import net.fabricmc.api.EnvType;
|
import net.fabricmc.api.EnvType;
|
||||||
import net.fabricmc.api.Environment;
|
import net.fabricmc.api.Environment;
|
||||||
import net.fabricmc.fabric.api.networking.v1.PacketSender;
|
import net.fabricmc.fabric.api.networking.v1.PacketSender;
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
|
||||||
import net.fabricmc.loader.api.ModContainer;
|
|
||||||
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;
|
||||||
|
@ -14,13 +12,15 @@ import ru.bclib.BCLib;
|
||||||
import ru.bclib.api.dataexchange.DataExchangeAPI;
|
import ru.bclib.api.dataexchange.DataExchangeAPI;
|
||||||
import ru.bclib.api.dataexchange.DataHandler;
|
import ru.bclib.api.dataexchange.DataHandler;
|
||||||
import ru.bclib.api.dataexchange.DataHandlerDescriptor;
|
import ru.bclib.api.dataexchange.DataHandlerDescriptor;
|
||||||
import ru.bclib.api.dataexchange.handler.AutoSyncID.WithContentOverride;
|
import ru.bclib.api.dataexchange.handler.DataExchange;
|
||||||
import ru.bclib.api.dataexchange.handler.DataExchange.SyncFolderDescriptor;
|
import ru.bclib.api.dataexchange.handler.autosync.AutoSync.ClientConfig;
|
||||||
import ru.bclib.api.dataexchange.handler.DataExchange.SyncFolderDescriptor.SubFile;
|
import ru.bclib.api.dataexchange.handler.autosync.AutoSync.Config;
|
||||||
|
import ru.bclib.api.dataexchange.handler.autosync.AutoSyncID.WithContentOverride;
|
||||||
|
import ru.bclib.api.dataexchange.handler.autosync.SyncFolderDescriptor.SubFile;
|
||||||
import ru.bclib.api.datafixer.DataFixerAPI;
|
import ru.bclib.api.datafixer.DataFixerAPI;
|
||||||
import ru.bclib.config.Configs;
|
|
||||||
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.PathUtil;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -28,7 +28,6 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -44,36 +43,18 @@ public class HelloClient extends DataHandler {
|
||||||
super(DESCRIPTOR.IDENTIFIER, true);
|
super(DESCRIPTOR.IDENTIFIER, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ModContainer getModContainer(String modID) {
|
|
||||||
Optional<ModContainer> optional = FabricLoader.getInstance()
|
|
||||||
.getModContainer(modID);
|
|
||||||
return optional.orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getModVersion(String modID) {
|
|
||||||
Optional<ModContainer> optional = FabricLoader.getInstance()
|
|
||||||
.getModContainer(modID);
|
|
||||||
if (optional.isPresent()) {
|
|
||||||
ModContainer modContainer = optional.get();
|
|
||||||
return modContainer.getMetadata()
|
|
||||||
.getVersion()
|
|
||||||
.toString();
|
|
||||||
}
|
|
||||||
return "0.0.0";
|
|
||||||
}
|
|
||||||
|
|
||||||
static String getBCLibVersion() {
|
static String getBCLibVersion() {
|
||||||
return getModVersion(BCLib.MOD_ID);
|
return PathUtil.getModVersion(BCLib.MOD_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean prepareData(boolean isClient) {
|
protected boolean prepareData(boolean isClient) {
|
||||||
if (!Configs.MAIN_CONFIG.getBoolean(Configs.MAIN_SYNC_CATEGORY, "enabled", true)) {
|
if (!Config.isAllowingAutoSync()) {
|
||||||
BCLib.LOGGER.info("Auto-Sync was disabled on the server.");
|
BCLib.LOGGER.info("Auto-Sync was disabled on the server.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataExchange.getInstance().loadSyncFolder();
|
AutoSync.loadSyncFolder();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,12 +67,12 @@ public class HelloClient extends DataHandler {
|
||||||
//write BCLibVersion (=protocol version)
|
//write BCLibVersion (=protocol version)
|
||||||
buf.writeInt(DataFixerAPI.getModVersion(vbclib));
|
buf.writeInt(DataFixerAPI.getModVersion(vbclib));
|
||||||
|
|
||||||
if (Configs.MAIN_CONFIG.getBoolean(Configs.MAIN_SYNC_CATEGORY, "offerMods", true)) {
|
if (Config.isOfferingMods()) {
|
||||||
//write Plugin Versions
|
//write Plugin Versions
|
||||||
buf.writeInt(mods.size());
|
buf.writeInt(mods.size());
|
||||||
for (String modID : mods) {
|
for (String modID : mods) {
|
||||||
writeString(buf, modID);
|
writeString(buf, modID);
|
||||||
final String ver = getModVersion(modID);
|
final String ver = PathUtil.getModVersion(modID);
|
||||||
buf.writeInt(DataFixerAPI.getModVersion(ver));
|
buf.writeInt(DataFixerAPI.getModVersion(ver));
|
||||||
BCLib.LOGGER.info(" - Listing Mod " + modID + " v" + ver);
|
BCLib.LOGGER.info(" - Listing Mod " + modID + " v" + ver);
|
||||||
}
|
}
|
||||||
|
@ -101,9 +82,9 @@ public class HelloClient extends DataHandler {
|
||||||
buf.writeInt(0);
|
buf.writeInt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Configs.MAIN_CONFIG.getBoolean(Configs.MAIN_SYNC_CATEGORY, "offerFiles", true)) {
|
if (Config.isOfferingFiles()) {
|
||||||
//do only include files that exist on the server
|
//do only include files that exist on the server
|
||||||
final List<AutoFileSyncEntry> existingAutoSyncFiles = DataExchange.getInstance()
|
final List<AutoFileSyncEntry> existingAutoSyncFiles = AutoSync
|
||||||
.getAutoSyncFiles()
|
.getAutoSyncFiles()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(e -> e.fileName.exists())
|
.filter(e -> e.fileName.exists())
|
||||||
|
@ -121,9 +102,9 @@ public class HelloClient extends DataHandler {
|
||||||
buf.writeInt(0);
|
buf.writeInt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Configs.MAIN_CONFIG.getBoolean(Configs.MAIN_SYNC_CATEGORY, "offersSyncFolders", true)) {
|
if (Config.isOfferingFolders()) {
|
||||||
buf.writeInt(((DataExchange) DataExchange.getInstance()).syncFolderDescriptions.size());
|
buf.writeInt(AutoSync.syncFolderDescriptions.size());
|
||||||
((DataExchange) DataExchange.getInstance()).syncFolderDescriptions.forEach(desc -> {
|
AutoSync.syncFolderDescriptions.forEach(desc -> {
|
||||||
BCLib.LOGGER.info(" - Offering Folder " + desc.localFolder + " (allowDelete=" + desc.removeAdditionalFiles + ")");
|
BCLib.LOGGER.info(" - Offering Folder " + desc.localFolder + " (allowDelete=" + desc.removeAdditionalFiles + ")");
|
||||||
desc.serialize(buf);
|
desc.serialize(buf);
|
||||||
});
|
});
|
||||||
|
@ -132,12 +113,11 @@ public class HelloClient extends DataHandler {
|
||||||
BCLib.LOGGER.info("Server will not offer Sync Folders.");
|
BCLib.LOGGER.info("Server will not offer Sync Folders.");
|
||||||
buf.writeInt(0);
|
buf.writeInt(0);
|
||||||
}
|
}
|
||||||
Configs.MAIN_CONFIG.saveChanges();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String bclibVersion = "0.0.0";
|
String bclibVersion = "0.0.0";
|
||||||
Map<String, String> modVersion = new HashMap<>();
|
Map<String, String> modVersion = new HashMap<>();
|
||||||
List<DataExchange.AutoSyncTriple> autoSyncedFiles = null;
|
List<AutoSync.AutoSyncTriple> autoSyncedFiles = null;
|
||||||
List<SyncFolderDescriptor> autoSynFolders = null;
|
List<SyncFolderDescriptor> autoSynFolders = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -159,7 +139,7 @@ public class HelloClient extends DataHandler {
|
||||||
autoSyncedFiles = new ArrayList<>(count);
|
autoSyncedFiles = new ArrayList<>(count);
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
//System.out.println("Deserializing ");
|
//System.out.println("Deserializing ");
|
||||||
DataExchange.AutoSyncTriple t = AutoFileSyncEntry.deserializeAndMatch(buf);
|
AutoSync.AutoSyncTriple t = AutoFileSyncEntry.deserializeAndMatch(buf);
|
||||||
autoSyncedFiles.add(t);
|
autoSyncedFiles.add(t);
|
||||||
//System.out.println(t.first);
|
//System.out.println(t.first);
|
||||||
}
|
}
|
||||||
|
@ -177,7 +157,7 @@ public class HelloClient extends DataHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processAutoSyncFolder(final List<AutoSyncID> filesToRequest, final List<AutoSyncID.ForDirectFileRequest> filesToRemove) {
|
private void processAutoSyncFolder(final List<AutoSyncID> filesToRequest, final List<AutoSyncID.ForDirectFileRequest> filesToRemove) {
|
||||||
if (!Configs.CLIENT_CONFIG.getBoolean(Configs.MAIN_SYNC_CATEGORY, "syncFolders", true)) {
|
if (!ClientConfig.isClientConfigAcceptingFolders()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +167,7 @@ public class HelloClient extends DataHandler {
|
||||||
|
|
||||||
autoSynFolders.forEach(desc -> {
|
autoSynFolders.forEach(desc -> {
|
||||||
//desc contains the fileCache sent from the server, load the local version to get hold of the actual file cache on the client
|
//desc contains the fileCache sent from the server, load the local version to get hold of the actual file cache on the client
|
||||||
SyncFolderDescriptor localDescriptor = DataExchange.getSyncFolderDescriptor(desc.folderID);
|
SyncFolderDescriptor localDescriptor = AutoSync.getSyncFolderDescriptor(desc.folderID);
|
||||||
if (localDescriptor != null) {
|
if (localDescriptor != null) {
|
||||||
BCLib.LOGGER.info(" - " + desc.folderID + " (" + desc.localFolder + ", allowRemove=" + desc.removeAdditionalFiles + ")");
|
BCLib.LOGGER.info(" - " + desc.folderID + " (" + desc.localFolder + ", allowRemove=" + desc.removeAdditionalFiles + ")");
|
||||||
localDescriptor.invalidateCache();
|
localDescriptor.invalidateCache();
|
||||||
|
@ -220,7 +200,8 @@ public class HelloClient extends DataHandler {
|
||||||
if (!localSubFile.hash.equals(subFile.hash)) {
|
if (!localSubFile.hash.equals(subFile.hash)) {
|
||||||
BCLib.LOGGER.info(" * " + subFile.relPath + " (changed)");
|
BCLib.LOGGER.info(" * " + subFile.relPath + " (changed)");
|
||||||
filesToRequest.add(new AutoSyncID.ForDirectFileRequest(desc.folderID, new File(subFile.relPath)));
|
filesToRequest.add(new AutoSyncID.ForDirectFileRequest(desc.folderID, new File(subFile.relPath)));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
BCLib.LOGGER.info(" * " + subFile.relPath);
|
BCLib.LOGGER.info(" * " + subFile.relPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -241,7 +222,7 @@ public class HelloClient extends DataHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processSingleFileSync(final List<AutoSyncID> filesToRequest) {
|
private void processSingleFileSync(final List<AutoSyncID> filesToRequest) {
|
||||||
final boolean debugHashes = Configs.CLIENT_CONFIG.getBoolean(Configs.MAIN_SYNC_CATEGORY, "debugHashes", false);
|
final boolean debugHashes = ClientConfig.shouldClientConfigPrintDebugHashes();
|
||||||
|
|
||||||
if (autoSyncedFiles.size() > 0) {
|
if (autoSyncedFiles.size() > 0) {
|
||||||
BCLib.LOGGER.info("Files offered by Server:");
|
BCLib.LOGGER.info("Files offered by Server:");
|
||||||
|
@ -251,7 +232,7 @@ public class HelloClient extends DataHandler {
|
||||||
//Single files need to be registered for sync on both client and server
|
//Single files need to be registered for sync on both client and server
|
||||||
//There are no restrictions to the target folder, but the client decides the final
|
//There are no restrictions to the target folder, but the client decides the final
|
||||||
//location.
|
//location.
|
||||||
for (DataExchange.AutoSyncTriple e : autoSyncedFiles) {
|
for (AutoSync.AutoSyncTriple e : autoSyncedFiles) {
|
||||||
String actionString = "";
|
String actionString = "";
|
||||||
FileContentWrapper contentWrapper = new FileContentWrapper(e.serverContent);
|
FileContentWrapper contentWrapper = new FileContentWrapper(e.serverContent);
|
||||||
if (e.localMatch == null) {
|
if (e.localMatch == null) {
|
||||||
|
@ -281,7 +262,7 @@ public class HelloClient extends DataHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void runOnGameThread(Minecraft client, MinecraftServer server, boolean isClient) {
|
protected void runOnGameThread(Minecraft client, MinecraftServer server, boolean isClient) {
|
||||||
if (!Configs.CLIENT_CONFIG.getBoolean(Configs.MAIN_SYNC_CATEGORY, "enabled", true)) {
|
if (!ClientConfig.isClientConfigAllowingAutoSync()) {
|
||||||
BCLib.LOGGER.info("Auto-Sync was disabled on the client.");
|
BCLib.LOGGER.info("Auto-Sync was disabled on the client.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -297,7 +278,7 @@ public class HelloClient extends DataHandler {
|
||||||
final List<AutoSyncID.ForDirectFileRequest> filesToRemove = new ArrayList<>(2);
|
final List<AutoSyncID.ForDirectFileRequest> filesToRemove = new ArrayList<>(2);
|
||||||
|
|
||||||
for (Entry<String, String> e : modVersion.entrySet()) {
|
for (Entry<String, String> e : modVersion.entrySet()) {
|
||||||
String ver = getModVersion(e.getKey());
|
String ver = PathUtil.getModVersion(e.getKey());
|
||||||
BCLib.LOGGER.info(" - " + e.getKey() + " (client=" + ver + ", server=" + ver + ")");
|
BCLib.LOGGER.info(" - " + e.getKey() + " (client=" + ver + ", server=" + ver + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,7 +289,7 @@ public class HelloClient extends DataHandler {
|
||||||
//Both client and server need to know about the folder you want to sync
|
//Both client and server need to know about the folder you want to sync
|
||||||
//Files can only get placed within that folder
|
//Files can only get placed within that folder
|
||||||
|
|
||||||
if ((filesToRequest.size() > 0 || filesToRemove.size() > 0) && SendFiles.acceptFiles()) {
|
if ((filesToRequest.size() > 0 || filesToRemove.size() > 0) && ClientConfig.isClientConfigAcceptingFiles()) {
|
||||||
showDownloadConfigs(client, filesToRequest, filesToRemove);
|
showDownloadConfigs(client, filesToRequest, filesToRemove);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package ru.bclib.api.dataexchange.handler;
|
package ru.bclib.api.dataexchange.handler.autosync;
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.networking.v1.PacketSender;
|
import net.fabricmc.fabric.api.networking.v1.PacketSender;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
@ -9,56 +9,58 @@ import ru.bclib.BCLib;
|
||||||
import ru.bclib.api.dataexchange.DataExchangeAPI;
|
import ru.bclib.api.dataexchange.DataExchangeAPI;
|
||||||
import ru.bclib.api.dataexchange.DataHandler;
|
import ru.bclib.api.dataexchange.DataHandler;
|
||||||
import ru.bclib.api.dataexchange.DataHandlerDescriptor;
|
import ru.bclib.api.dataexchange.DataHandlerDescriptor;
|
||||||
|
import ru.bclib.api.dataexchange.handler.autosync.AutoSync.ClientConfig;
|
||||||
|
import ru.bclib.api.dataexchange.handler.autosync.AutoSync.Config;
|
||||||
import ru.bclib.api.datafixer.DataFixerAPI;
|
import ru.bclib.api.datafixer.DataFixerAPI;
|
||||||
import ru.bclib.config.Configs;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This message is sent once a player enters the world. It initiates a sequence of Messages that will sync files between both
|
* 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.
|
* client and server.
|
||||||
* <table>
|
* <table>
|
||||||
* <caption>Description</caption>
|
* <caption>Description</caption>
|
||||||
* <tr>
|
* <tr>
|
||||||
* <th>Server</th>
|
* <th>Server</th>
|
||||||
* <th></th>
|
* <th></th>
|
||||||
* <th>Client</th>
|
* <th>Client</th>
|
||||||
* <th></th>
|
* <th></th>
|
||||||
* </tr>
|
* </tr>
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td colspan="4">Player enters World</td>
|
* <td colspan="4">Player enters World</td>
|
||||||
* </tr>
|
* </tr>
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td></td>
|
* <td></td>
|
||||||
* <td><--</td>
|
* <td><--</td>
|
||||||
* <td>{@link HelloServer}</td>
|
* <td>{@link HelloServer}</td>
|
||||||
* <td>Sends the current BLib-Version installed on the Client</td>
|
* <td>Sends the current BLib-Version installed on the Client</td>
|
||||||
* </tr>
|
* </tr>
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td>{@link HelloClient}</td>
|
* <td>{@link HelloClient}</td>
|
||||||
* <td>--></td>
|
* <td>--></td>
|
||||||
* <td></td>
|
* <td></td>
|
||||||
* <td>Sends the current BClIb-Version, the Version of all Plugins and data for all AutpoSync-Files
|
* <td>Sends the current BClIb-Version, the Version of all Plugins and data for all AutpoSync-Files
|
||||||
* ({@link DataExchangeAPI#addAutoSyncFile(String, File)} on the Server</td>
|
* ({@link DataExchangeAPI#addAutoSyncFile(String, File)} on the Server</td>
|
||||||
* </tr>
|
* </tr>
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td></td>
|
* <td></td>
|
||||||
* <td><--</td>
|
* <td><--</td>
|
||||||
* <td>{@link RequestFiles}</td>
|
* <td>{@link RequestFiles}</td>
|
||||||
* <td>Request missing or out of sync Files from the Server</td>
|
* <td>Request missing or out of sync Files from the Server</td>
|
||||||
* </tr>
|
* </tr>
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td>{@link SendFiles}</td>
|
* <td>{@link SendFiles}</td>
|
||||||
* <td>--></td>
|
* <td>--></td>
|
||||||
* <td></td>
|
* <td></td>
|
||||||
* <td>Send Files from the Server to the Client</td>
|
* <td>Send Files from the Server to the Client</td>
|
||||||
* </tr>
|
* </tr>
|
||||||
* </table>
|
* </table>
|
||||||
*/
|
*/
|
||||||
public class HelloServer extends DataHandler {
|
public class HelloServer extends DataHandler {
|
||||||
public static DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "hello_server"), HelloServer::new, true, false);
|
public static DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "hello_server"), HelloServer::new, true, false);
|
||||||
|
|
||||||
protected String bclibVersion ="0.0.0";
|
protected String bclibVersion = "0.0.0";
|
||||||
|
|
||||||
public HelloServer() {
|
public HelloServer() {
|
||||||
super(DESCRIPTOR.IDENTIFIER, false);
|
super(DESCRIPTOR.IDENTIFIER, false);
|
||||||
}
|
}
|
||||||
|
@ -66,7 +68,7 @@ public class HelloServer extends DataHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean prepareData(boolean isClient) {
|
protected boolean prepareData(boolean isClient) {
|
||||||
if (!Configs.CLIENT_CONFIG.getBoolean(Configs.MAIN_SYNC_CATEGORY, "enabled", true)) {
|
if (!ClientConfig.isClientConfigAllowingAutoSync()) {
|
||||||
BCLib.LOGGER.info("Auto-Sync was disabled on the client.");
|
BCLib.LOGGER.info("Auto-Sync was disabled on the client.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -86,15 +88,15 @@ public class HelloServer extends DataHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void runOnGameThread(Minecraft client, MinecraftServer server, boolean isClient) {
|
protected void runOnGameThread(Minecraft client, MinecraftServer server, boolean isClient) {
|
||||||
if (!Configs.MAIN_CONFIG.getBoolean(Configs.MAIN_SYNC_CATEGORY, "enabled", true)) {
|
if (!Config.isAllowingAutoSync()) {
|
||||||
BCLib.LOGGER.info("Auto-Sync was disabled on the server.");
|
BCLib.LOGGER.info("Auto-Sync was disabled on the server.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String localBclibVersion = HelloClient.getBCLibVersion();
|
String localBclibVersion = HelloClient.getBCLibVersion();
|
||||||
BCLib.LOGGER.info("Received Hello from Client. (server="+localBclibVersion+", client="+bclibVersion+")");
|
BCLib.LOGGER.info("Received Hello from Client. (server=" + localBclibVersion + ", client=" + bclibVersion + ")");
|
||||||
|
|
||||||
if (!server.isPublished()){
|
if (!server.isPublished()) {
|
||||||
BCLib.LOGGER.info("Auto-Sync is disabled for Singleplayer worlds.");
|
BCLib.LOGGER.info("Auto-Sync is disabled for Singleplayer worlds.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package ru.bclib.api.dataexchange.handler;
|
package ru.bclib.api.dataexchange.handler.autosync;
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.networking.v1.PacketSender;
|
import net.fabricmc.fabric.api.networking.v1.PacketSender;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
@ -8,7 +8,8 @@ import net.minecraft.server.MinecraftServer;
|
||||||
import ru.bclib.BCLib;
|
import ru.bclib.BCLib;
|
||||||
import ru.bclib.api.dataexchange.DataHandler;
|
import ru.bclib.api.dataexchange.DataHandler;
|
||||||
import ru.bclib.api.dataexchange.DataHandlerDescriptor;
|
import ru.bclib.api.dataexchange.DataHandlerDescriptor;
|
||||||
import ru.bclib.config.Configs;
|
import ru.bclib.api.dataexchange.handler.autosync.AutoSync.ClientConfig;
|
||||||
|
import ru.bclib.api.dataexchange.handler.autosync.AutoSync.Config;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -20,7 +21,8 @@ public class RequestFiles extends DataHandler {
|
||||||
static String currentToken = "";
|
static String currentToken = "";
|
||||||
|
|
||||||
protected List<AutoSyncID> files;
|
protected List<AutoSyncID> files;
|
||||||
private RequestFiles(){
|
|
||||||
|
private RequestFiles() {
|
||||||
this(null);
|
this(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +33,7 @@ public class RequestFiles extends DataHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean prepareData(boolean isClient) {
|
protected boolean prepareData(boolean isClient) {
|
||||||
if (!Configs.CLIENT_CONFIG.getBoolean(Configs.MAIN_SYNC_CATEGORY, "enabled", true)) {
|
if (!ClientConfig.isClientConfigAllowingAutoSync()) {
|
||||||
BCLib.LOGGER.info("Auto-Sync was disabled on the client.");
|
BCLib.LOGGER.info("Auto-Sync was disabled on the client.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -42,15 +44,16 @@ public class RequestFiles extends DataHandler {
|
||||||
protected void serializeData(FriendlyByteBuf buf, boolean isClient) {
|
protected void serializeData(FriendlyByteBuf buf, boolean isClient) {
|
||||||
newToken();
|
newToken();
|
||||||
writeString(buf, currentToken);
|
writeString(buf, currentToken);
|
||||||
|
|
||||||
buf.writeInt(files.size());
|
buf.writeInt(files.size());
|
||||||
|
|
||||||
for (AutoSyncID a : files){
|
for (AutoSyncID a : files) {
|
||||||
a.serializeData(buf);
|
a.serializeData(buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String receivedToken = "";
|
String receivedToken = "";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void deserializeFromIncomingData(FriendlyByteBuf buf, PacketSender responseSender, boolean fromClient) {
|
protected void deserializeFromIncomingData(FriendlyByteBuf buf, PacketSender responseSender, boolean fromClient) {
|
||||||
receivedToken = readString(buf);
|
receivedToken = readString(buf);
|
||||||
|
@ -58,7 +61,7 @@ public class RequestFiles extends DataHandler {
|
||||||
files = new ArrayList<>(size);
|
files = new ArrayList<>(size);
|
||||||
|
|
||||||
BCLib.LOGGER.info("Client requested " + size + " Files:");
|
BCLib.LOGGER.info("Client requested " + size + " Files:");
|
||||||
for (int i=0; i<size; i++){
|
for (int i = 0; i < size; i++) {
|
||||||
AutoSyncID asid = AutoSyncID.deserializeData(buf);
|
AutoSyncID asid = AutoSyncID.deserializeData(buf);
|
||||||
files.add(asid);
|
files.add(asid);
|
||||||
BCLib.LOGGER.info(" - " + asid);
|
BCLib.LOGGER.info(" - " + asid);
|
||||||
|
@ -69,23 +72,24 @@ public class RequestFiles extends DataHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void runOnGameThread(Minecraft client, MinecraftServer server, boolean isClient) {
|
protected void runOnGameThread(Minecraft client, MinecraftServer server, boolean isClient) {
|
||||||
if (!Configs.MAIN_CONFIG.getBoolean(Configs.MAIN_SYNC_CATEGORY, "enabled", true)) {
|
if (!Config.isAllowingAutoSync()) {
|
||||||
BCLib.LOGGER.info("Auto-Sync was disabled on the server.");
|
BCLib.LOGGER.info("Auto-Sync was disabled on the server.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<AutoFileSyncEntry> syncEntries = files
|
List<AutoFileSyncEntry> syncEntries = files.stream()
|
||||||
.stream().map(asid -> AutoFileSyncEntry.findMatching(asid))
|
.map(asid -> AutoFileSyncEntry.findMatching(asid))
|
||||||
.filter(e -> e!=null)
|
.filter(e -> e != null)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
reply(new SendFiles(syncEntries, receivedToken), server);
|
reply(new SendFiles(syncEntries, receivedToken), server);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void newToken(){
|
public static void newToken() {
|
||||||
currentToken = UUID.randomUUID().toString();
|
currentToken = UUID.randomUUID()
|
||||||
|
.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
newToken();
|
newToken();
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package ru.bclib.api.dataexchange.handler;
|
package ru.bclib.api.dataexchange.handler.autosync;
|
||||||
|
|
||||||
import net.fabricmc.api.EnvType;
|
import net.fabricmc.api.EnvType;
|
||||||
import net.fabricmc.api.Environment;
|
import net.fabricmc.api.Environment;
|
||||||
|
@ -11,7 +11,9 @@ import net.minecraft.server.MinecraftServer;
|
||||||
import ru.bclib.BCLib;
|
import ru.bclib.BCLib;
|
||||||
import ru.bclib.api.dataexchange.DataHandler;
|
import ru.bclib.api.dataexchange.DataHandler;
|
||||||
import ru.bclib.api.dataexchange.DataHandlerDescriptor;
|
import ru.bclib.api.dataexchange.DataHandlerDescriptor;
|
||||||
import ru.bclib.config.Configs;
|
import ru.bclib.api.dataexchange.handler.DataExchange;
|
||||||
|
import ru.bclib.api.dataexchange.handler.autosync.AutoSync.ClientConfig;
|
||||||
|
import ru.bclib.api.dataexchange.handler.autosync.AutoSync.Config;
|
||||||
import ru.bclib.gui.screens.ConfirmRestartScreen;
|
import ru.bclib.gui.screens.ConfirmRestartScreen;
|
||||||
import ru.bclib.util.Pair;
|
import ru.bclib.util.Pair;
|
||||||
import ru.bclib.util.Triple;
|
import ru.bclib.util.Triple;
|
||||||
|
@ -26,26 +28,23 @@ import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class SendFiles extends DataHandler {
|
public class SendFiles extends DataHandler {
|
||||||
public static DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "send_files"), SendFiles::new, false, false);
|
public static DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "send_files"), SendFiles::new, false, false);
|
||||||
|
|
||||||
protected List<AutoFileSyncEntry> files;
|
protected List<AutoFileSyncEntry> files;
|
||||||
private String token = "";
|
private String token = "";
|
||||||
public SendFiles(){
|
|
||||||
|
public SendFiles() {
|
||||||
this(null, "");
|
this(null, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public SendFiles(List<AutoFileSyncEntry> files, String token) {
|
public SendFiles(List<AutoFileSyncEntry> files, String token) {
|
||||||
super(DESCRIPTOR.IDENTIFIER, true);
|
super(DESCRIPTOR.IDENTIFIER, true);
|
||||||
this.files = files;
|
this.files = files;
|
||||||
this.token = token;
|
this.token = token;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean acceptFiles() {
|
|
||||||
return Configs.CLIENT_CONFIG.getBoolean(Configs.MAIN_SYNC_CATEGORY, "acceptFiles", true)
|
|
||||||
&& Configs.CLIENT_CONFIG.getBoolean(Configs.MAIN_SYNC_CATEGORY, "enabled", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean prepareData(boolean isClient) {
|
protected boolean prepareData(boolean isClient) {
|
||||||
if (!Configs.MAIN_CONFIG.getBoolean(Configs.MAIN_SYNC_CATEGORY, "enabled", true)) {
|
if (!Config.isAllowingAutoSync()) {
|
||||||
BCLib.LOGGER.info("Auto-Sync was disabled on the server.");
|
BCLib.LOGGER.info("Auto-Sync was disabled on the server.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -55,7 +54,9 @@ public class SendFiles extends DataHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void serializeData(FriendlyByteBuf buf, boolean isClient) {
|
protected void serializeData(FriendlyByteBuf buf, boolean isClient) {
|
||||||
List<AutoFileSyncEntry> existingFiles = files.stream().filter(e -> e.fileName.exists()).collect(Collectors.toList());
|
List<AutoFileSyncEntry> existingFiles = files.stream()
|
||||||
|
.filter(e -> e.fileName.exists())
|
||||||
|
.collect(Collectors.toList());
|
||||||
/*
|
/*
|
||||||
//this will try to send a file that was not registered or requested by the client
|
//this will try to send a file that was not registered or requested by the client
|
||||||
existingFiles.add(new AutoFileSyncEntry("none", new File("D:\\MinecraftPlugins\\BetterNether\\run\\server.properties"),true,(a, b, content) -> {
|
existingFiles.add(new AutoFileSyncEntry("none", new File("D:\\MinecraftPlugins\\BetterNether\\run\\server.properties"),true,(a, b, content) -> {
|
||||||
|
@ -72,18 +73,19 @@ public class SendFiles extends DataHandler {
|
||||||
|
|
||||||
writeString(buf, token);
|
writeString(buf, token);
|
||||||
buf.writeInt(existingFiles.size());
|
buf.writeInt(existingFiles.size());
|
||||||
|
|
||||||
BCLib.LOGGER.info("Sending " + existingFiles.size() + " Files to Client:");
|
BCLib.LOGGER.info("Sending " + existingFiles.size() + " Files to Client:");
|
||||||
for (AutoFileSyncEntry entry : existingFiles) {
|
for (AutoFileSyncEntry entry : existingFiles) {
|
||||||
int length = entry.serializeContent(buf);
|
int length = entry.serializeContent(buf);
|
||||||
BCLib.LOGGER.info(" - " + entry + " (" + length + " Bytes)");
|
BCLib.LOGGER.info(" - " + entry + " (" + length + " Bytes)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Pair<AutoFileSyncEntry, byte[]>> receivedFiles;
|
private List<Pair<AutoFileSyncEntry, byte[]>> receivedFiles;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void deserializeFromIncomingData(FriendlyByteBuf buf, PacketSender responseSender, boolean fromClient) {
|
protected void deserializeFromIncomingData(FriendlyByteBuf buf, PacketSender responseSender, boolean fromClient) {
|
||||||
if (acceptFiles()) {
|
if (ClientConfig.isClientConfigAcceptingFiles()) {
|
||||||
token = readString(buf);
|
token = readString(buf);
|
||||||
if (!token.equals(RequestFiles.currentToken)) {
|
if (!token.equals(RequestFiles.currentToken)) {
|
||||||
RequestFiles.newToken();
|
RequestFiles.newToken();
|
||||||
|
@ -92,7 +94,7 @@ public class SendFiles extends DataHandler {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
RequestFiles.newToken();
|
RequestFiles.newToken();
|
||||||
|
|
||||||
int size = buf.readInt();
|
int size = buf.readInt();
|
||||||
receivedFiles = new ArrayList<>(size);
|
receivedFiles = new ArrayList<>(size);
|
||||||
BCLib.LOGGER.info("Server sent " + size + " Files:");
|
BCLib.LOGGER.info("Server sent " + size + " Files:");
|
||||||
|
@ -101,7 +103,8 @@ public class SendFiles extends DataHandler {
|
||||||
if (p.first != null) {
|
if (p.first != null) {
|
||||||
receivedFiles.add(p);
|
receivedFiles.add(p);
|
||||||
BCLib.LOGGER.info(" - " + p.first + " (" + p.second.length + " Bytes)");
|
BCLib.LOGGER.info(" - " + p.first + " (" + p.second.length + " Bytes)");
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
BCLib.LOGGER.error(" - Failed to receive File " + p.third + ", possibly sent from a Mod that is not installed on the client.");
|
BCLib.LOGGER.error(" - Failed to receive File " + p.third + ", possibly sent from a Mod that is not installed on the client.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,7 +113,7 @@ public class SendFiles extends DataHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void runOnGameThread(Minecraft client, MinecraftServer server, boolean isClient) {
|
protected void runOnGameThread(Minecraft client, MinecraftServer server, boolean isClient) {
|
||||||
if (acceptFiles()) {
|
if (ClientConfig.isClientConfigAcceptingFiles()) {
|
||||||
BCLib.LOGGER.info("Writing Files:");
|
BCLib.LOGGER.info("Writing Files:");
|
||||||
|
|
||||||
//TODO: Reject files that were not in the last RequestFiles.
|
//TODO: Reject files that were not in the last RequestFiles.
|
||||||
|
@ -120,7 +123,7 @@ public class SendFiles extends DataHandler {
|
||||||
|
|
||||||
writeSyncedFile(e, data, e.fileName);
|
writeSyncedFile(e, data, e.fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
showConfirmRestart(client);
|
showConfirmRestart(client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,23 +133,25 @@ public class SendFiles extends DataHandler {
|
||||||
BCLib.LOGGER.info(" - Writing " + path + " (" + data.length + " Bytes)");
|
BCLib.LOGGER.info(" - Writing " + path + " (" + data.length + " Bytes)");
|
||||||
try {
|
try {
|
||||||
final File parentFile = path.getParent()
|
final File parentFile = path.getParent()
|
||||||
.toFile();
|
.toFile();
|
||||||
if (!parentFile.exists()){
|
if (!parentFile.exists()) {
|
||||||
parentFile.mkdirs();
|
parentFile.mkdirs();
|
||||||
}
|
}
|
||||||
Files.write(path, data);
|
Files.write(path, data);
|
||||||
DataExchange.didReceiveFile(e, fileName);
|
AutoSync.didReceiveFile(e, fileName);
|
||||||
} catch (IOException ioException) {
|
}
|
||||||
|
catch (IOException ioException) {
|
||||||
BCLib.LOGGER.error(" --> Writing " + fileName + " failed: " + ioException);
|
BCLib.LOGGER.error(" --> Writing " + fileName + " failed: " + ioException);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Environment(EnvType.CLIENT)
|
@Environment(EnvType.CLIENT)
|
||||||
protected void showConfirmRestart(Minecraft client){
|
protected void showConfirmRestart(Minecraft client) {
|
||||||
client.setScreen(new ConfirmRestartScreen(() -> {
|
client.setScreen(new ConfirmRestartScreen(() -> {
|
||||||
Minecraft.getInstance().setScreen((Screen)null);
|
Minecraft.getInstance()
|
||||||
|
.setScreen((Screen) null);
|
||||||
client.stop();
|
client.stop();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,206 @@
|
||||||
|
package ru.bclib.api.dataexchange.handler.autosync;
|
||||||
|
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.bclib.BCLib;
|
||||||
|
import ru.bclib.api.dataexchange.DataHandler;
|
||||||
|
import ru.bclib.api.dataexchange.FileHash;
|
||||||
|
import ru.bclib.api.dataexchange.handler.autosync.AutoSyncID.ForDirectFileRequest;
|
||||||
|
import ru.bclib.config.Configs;
|
||||||
|
import ru.bclib.util.PathUtil;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class SyncFolderDescriptor {
|
||||||
|
static class SubFile {
|
||||||
|
public final String relPath;
|
||||||
|
public final FileHash hash;
|
||||||
|
|
||||||
|
|
||||||
|
SubFile(String relPath, FileHash hash) {
|
||||||
|
this.relPath = relPath;
|
||||||
|
this.hash = hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return relPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serialize(FriendlyByteBuf buf) {
|
||||||
|
DataHandler.writeString(buf, relPath);
|
||||||
|
hash.serialize(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SubFile deserialize(FriendlyByteBuf buf) {
|
||||||
|
final String relPath = DataHandler.readString(buf);
|
||||||
|
FileHash hash = FileHash.deserialize(buf);
|
||||||
|
return new SubFile(relPath, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o instanceof String) return relPath.equals(o);
|
||||||
|
if (!(o instanceof SubFile)) return false;
|
||||||
|
SubFile subFile = (SubFile) o;
|
||||||
|
return relPath.equals(subFile.relPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return relPath.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public final String folderID;
|
||||||
|
public final boolean removeAdditionalFiles;
|
||||||
|
@NotNull
|
||||||
|
public final Path localFolder;
|
||||||
|
|
||||||
|
private List<SubFile> fileCache;
|
||||||
|
|
||||||
|
public SyncFolderDescriptor(String folderID, Path localFolder, boolean removeAdditionalFiles) {
|
||||||
|
this.removeAdditionalFiles = removeAdditionalFiles;
|
||||||
|
this.folderID = folderID;
|
||||||
|
this.localFolder = localFolder;
|
||||||
|
fileCache = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SyncFolderDescriptor{" + "folderID='" + folderID + '\'' + ", removeAdditionalFiles=" + removeAdditionalFiles + ", localFolder=" + localFolder + ", files=" + (fileCache == null ? "?" : fileCache.size()) + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o instanceof String) {
|
||||||
|
return folderID.equals(o);
|
||||||
|
}
|
||||||
|
if (o instanceof ForDirectFileRequest) {
|
||||||
|
return folderID.equals(((ForDirectFileRequest) o).uniqueID);
|
||||||
|
}
|
||||||
|
if (!(o instanceof SyncFolderDescriptor)) return false;
|
||||||
|
SyncFolderDescriptor that = (SyncFolderDescriptor) o;
|
||||||
|
return folderID.equals(that.folderID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return folderID.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int fileCount() {
|
||||||
|
return fileCache == null ? 0 : fileCache.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void invalidateCache() {
|
||||||
|
fileCache = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadCache() {
|
||||||
|
if (fileCache == null) {
|
||||||
|
fileCache = new ArrayList<>(8);
|
||||||
|
PathUtil.fileWalker(localFolder.toFile(), p -> fileCache.add(new SubFile(localFolder.relativize(p)
|
||||||
|
.toString(), FileHash.create(p.toFile()))));
|
||||||
|
|
||||||
|
/*//this tests if we can trick the system to load files that are not beneath the base-folder
|
||||||
|
if (!BCLib.isClient()) {
|
||||||
|
fileCache.add(new SubFile("../breakout.json", FileHash.create(mapAbsolute("../breakout.json").toFile())));
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serialize(FriendlyByteBuf buf) {
|
||||||
|
final boolean debugHashes = Configs.CLIENT_CONFIG.getBoolean(AutoSync.MAIN_SYNC_CATEGORY, "debugHashes", false);
|
||||||
|
loadCache();
|
||||||
|
|
||||||
|
DataHandler.writeString(buf, folderID);
|
||||||
|
buf.writeBoolean(removeAdditionalFiles);
|
||||||
|
buf.writeInt(fileCache.size());
|
||||||
|
fileCache.forEach(fl -> {
|
||||||
|
BCLib.LOGGER.info(" - " + fl.relPath);
|
||||||
|
if (debugHashes) {
|
||||||
|
BCLib.LOGGER.info(" " + fl.hash);
|
||||||
|
}
|
||||||
|
fl.serialize(buf);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SyncFolderDescriptor deserialize(FriendlyByteBuf buf) {
|
||||||
|
final String folderID = DataHandler.readString(buf);
|
||||||
|
final boolean remAddFiles = buf.readBoolean();
|
||||||
|
final int count = buf.readInt();
|
||||||
|
SyncFolderDescriptor localDescriptor = AutoSync.getSyncFolderDescriptor(folderID);
|
||||||
|
|
||||||
|
final SyncFolderDescriptor desc;
|
||||||
|
if (localDescriptor != null) {
|
||||||
|
desc = new SyncFolderDescriptor(folderID, localDescriptor.localFolder, remAddFiles);
|
||||||
|
desc.fileCache = new ArrayList<>(count);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BCLib.LOGGER.warning(BCLib.isClient() ? "Client" : "Server" + " does not know Sync-Folder ID '" + folderID + "'");
|
||||||
|
desc = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
SubFile relPath = SubFile.deserialize(buf);
|
||||||
|
if (desc != null) desc.fileCache.add(relPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Note: make sure loadCache was called before using this
|
||||||
|
boolean hasRelativeFile(String relFile) {
|
||||||
|
return fileCache.stream()
|
||||||
|
.filter(sf -> sf.equals(relFile))
|
||||||
|
.findFirst()
|
||||||
|
.isPresent();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Note: make sure loadCache was called before using this
|
||||||
|
boolean hasRelativeFile(SubFile subFile) {
|
||||||
|
return hasRelativeFile(subFile.relPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Note: make sure loadCache was called before using this
|
||||||
|
SubFile getLocalSubFile(String relPath) {
|
||||||
|
return fileCache.stream()
|
||||||
|
.filter(sf -> sf.relPath.equals(relPath))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<SubFile> relativeFilesStream() {
|
||||||
|
loadCache();
|
||||||
|
return fileCache.stream();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path mapAbsolute(String relPath) {
|
||||||
|
return this.localFolder.resolve(relPath)
|
||||||
|
.normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path mapAbsolute(SubFile subFile) {
|
||||||
|
return this.localFolder.resolve(subFile.relPath)
|
||||||
|
.normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean acceptChildElements(Path absPath) {
|
||||||
|
return PathUtil.isChildOf(this.localFolder, absPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean acceptChildElements(SubFile subFile) {
|
||||||
|
return acceptChildElements(mapAbsolute(subFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean discardChildElements(SubFile subFile) {
|
||||||
|
return !acceptChildElements(subFile);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,8 +4,8 @@ import org.jetbrains.annotations.Nullable;
|
||||||
import ru.bclib.BCLib;
|
import ru.bclib.BCLib;
|
||||||
import ru.bclib.api.dataexchange.DataExchangeAPI;
|
import ru.bclib.api.dataexchange.DataExchangeAPI;
|
||||||
import ru.bclib.api.dataexchange.SyncFileHash;
|
import ru.bclib.api.dataexchange.SyncFileHash;
|
||||||
import ru.bclib.api.dataexchange.handler.AutoSyncID;
|
import ru.bclib.api.dataexchange.handler.autosync.AutoSyncID;
|
||||||
import ru.bclib.api.dataexchange.handler.FileContentWrapper;
|
import ru.bclib.api.dataexchange.handler.autosync.FileContentWrapper;
|
||||||
import ru.bclib.config.ConfigKeeper.BooleanEntry;
|
import ru.bclib.config.ConfigKeeper.BooleanEntry;
|
||||||
import ru.bclib.config.ConfigKeeper.Entry;
|
import ru.bclib.config.ConfigKeeper.Entry;
|
||||||
import ru.bclib.config.ConfigKeeper.FloatEntry;
|
import ru.bclib.config.ConfigKeeper.FloatEntry;
|
||||||
|
|
|
@ -6,7 +6,7 @@ import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import net.minecraft.util.GsonHelper;
|
import net.minecraft.util.GsonHelper;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import ru.bclib.api.dataexchange.handler.FileContentWrapper;
|
import ru.bclib.api.dataexchange.handler.autosync.FileContentWrapper;
|
||||||
import ru.bclib.util.JsonFactory;
|
import ru.bclib.util.JsonFactory;
|
||||||
import ru.bclib.util.Pair;
|
import ru.bclib.util.Pair;
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ public class Configs {
|
||||||
public static final PathConfig GENERATOR_CONFIG = new PathConfig(BCLib.MOD_ID, "generator");
|
public static final PathConfig GENERATOR_CONFIG = new PathConfig(BCLib.MOD_ID, "generator");
|
||||||
public static final PathConfig MAIN_CONFIG = new PathConfig(BCLib.MOD_ID, "main");
|
public static final PathConfig MAIN_CONFIG = new PathConfig(BCLib.MOD_ID, "main");
|
||||||
public static final String MAIN_PATCH_CATEGORY = "patches";
|
public static final String MAIN_PATCH_CATEGORY = "patches";
|
||||||
public static final String MAIN_SYNC_CATEGORY = "client_sync";
|
|
||||||
|
|
||||||
public static final PathConfig RECIPE_CONFIG = new PathConfig(BCLib.MOD_ID, "recipes");
|
public static final PathConfig RECIPE_CONFIG = new PathConfig(BCLib.MOD_ID, "recipes");
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package ru.bclib.util;
|
package ru.bclib.util;
|
||||||
|
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.fabricmc.loader.api.ModContainer;
|
||||||
import net.fabricmc.loader.api.metadata.ModMetadata;
|
import net.fabricmc.loader.api.metadata.ModMetadata;
|
||||||
import net.fabricmc.loader.metadata.ModMetadataParser;
|
import net.fabricmc.loader.metadata.ModMetadataParser;
|
||||||
import net.fabricmc.loader.metadata.ParseMetadataException;
|
import net.fabricmc.loader.metadata.ParseMetadataException;
|
||||||
|
@ -15,6 +16,7 @@ import java.nio.file.FileSystems;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
|
|
||||||
|
@ -127,4 +129,22 @@ public class PathUtil {
|
||||||
|
|
||||||
return mods;
|
return mods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getModVersion(String modID) {
|
||||||
|
Optional<ModContainer> optional = FabricLoader.getInstance()
|
||||||
|
.getModContainer(modID);
|
||||||
|
if (optional.isPresent()) {
|
||||||
|
ModContainer modContainer = optional.get();
|
||||||
|
return modContainer.getMetadata()
|
||||||
|
.getVersion()
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
return "0.0.0";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ModContainer getModContainer(String modID) {
|
||||||
|
Optional<ModContainer> optional = FabricLoader.getInstance()
|
||||||
|
.getModContainer(modID);
|
||||||
|
return optional.orElse(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue