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.WorldDataAPI;
|
||||
import ru.bclib.api.dataexchange.DataExchangeAPI;
|
||||
import ru.bclib.api.dataexchange.handler.HelloClient;
|
||||
import ru.bclib.api.dataexchange.handler.HelloServer;
|
||||
import ru.bclib.api.dataexchange.handler.RequestFiles;
|
||||
import ru.bclib.api.dataexchange.handler.SendFiles;
|
||||
import ru.bclib.api.dataexchange.handler.autosync.HelloClient;
|
||||
import ru.bclib.api.dataexchange.handler.autosync.HelloServer;
|
||||
import ru.bclib.api.dataexchange.handler.autosync.RequestFiles;
|
||||
import ru.bclib.api.dataexchange.handler.autosync.SendFiles;
|
||||
import ru.bclib.api.datafixer.DataFixerAPI;
|
||||
import ru.bclib.config.Configs;
|
||||
import ru.bclib.recipes.CraftingRecipes;
|
||||
|
|
|
@ -4,7 +4,9 @@ import com.google.common.collect.Lists;
|
|||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
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.config.Config;
|
||||
|
||||
|
@ -98,7 +100,7 @@ public class DataExchangeAPI extends DataExchange {
|
|||
* @param fileName The name of the File
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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("/", "-"))
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package ru.bclib.api.dataexchange;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import ru.bclib.api.dataexchange.handler.AutoSyncID;
|
||||
import ru.bclib.api.dataexchange.handler.DataExchange;
|
||||
import ru.bclib.api.dataexchange.handler.autosync.AutoSync.NeedTransferPredicate;
|
||||
import ru.bclib.api.dataexchange.handler.autosync.AutoSyncID;
|
||||
|
||||
import java.io.File;
|
||||
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
|
||||
public String toString() {
|
||||
|
|
|
@ -4,255 +4,17 @@ import net.fabricmc.api.EnvType;
|
|||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
|
||||
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.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.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.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
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;
|
||||
|
||||
|
@ -266,7 +28,7 @@ abstract public class DataExchange {
|
|||
protected ConnectorServerside server;
|
||||
protected ConnectorClientside client;
|
||||
protected final Set<DataHandlerDescriptor> descriptors;
|
||||
private final List<AutoFileSyncEntry> autoSyncFiles = new ArrayList<>(4);
|
||||
|
||||
|
||||
private boolean didLoadSyncFolder = false;
|
||||
|
||||
|
@ -280,9 +42,6 @@ abstract public class DataExchange {
|
|||
|
||||
public Set<DataHandlerDescriptor> getDescriptors() { return descriptors; }
|
||||
|
||||
public List<AutoFileSyncEntry> getAutoSyncFiles() {
|
||||
return autoSyncFiles;
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
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 ru.bclib.api.dataexchange.DataHandler;
|
||||
import ru.bclib.api.dataexchange.SyncFileHash;
|
||||
import ru.bclib.api.dataexchange.handler.DataExchange.SyncFolderDescriptor;
|
||||
import ru.bclib.api.dataexchange.handler.DataExchange.SyncFolderDescriptor.SubFile;
|
||||
import ru.bclib.api.dataexchange.handler.autosync.AutoSync.NeedTransferPredicate;
|
||||
import ru.bclib.api.dataexchange.handler.autosync.SyncFolderDescriptor.SubFile;
|
||||
import ru.bclib.util.Pair;
|
||||
import ru.bclib.util.Triple;
|
||||
|
||||
|
@ -32,7 +32,7 @@ class AutoFileSyncEntry extends AutoSyncID {
|
|||
|
||||
static AutoFileSyncEntry.ForDirectFileRequest finishDeserializeContent(String syncID, FriendlyByteBuf buf) {
|
||||
final String relFile = DataHandler.readString(buf);
|
||||
SyncFolderDescriptor desc = DataExchange.getSyncFolderDescriptor(syncID);
|
||||
SyncFolderDescriptor desc = AutoSync.getSyncFolderDescriptor(syncID);
|
||||
if (desc != null) {
|
||||
//ensures that the file is not above the base-folder
|
||||
if (desc.acceptChildElements(desc.mapAbsolute(relFile))) {
|
||||
|
@ -49,16 +49,17 @@ class AutoFileSyncEntry extends AutoSyncID {
|
|||
return uniqueID + " - " + relFile;
|
||||
}
|
||||
}
|
||||
public final DataExchange.NeedTransferPredicate needTransfer;
|
||||
|
||||
public final NeedTransferPredicate needTransfer;
|
||||
public final File fileName;
|
||||
public final boolean requestContent;
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
this.needTransfer = needTransfer;
|
||||
this.fileName = fileName;
|
||||
|
@ -99,7 +100,8 @@ class AutoFileSyncEntry extends AutoSyncID {
|
|||
AutoFileSyncEntry entry;
|
||||
if (AutoSyncID.ForDirectFileRequest.MOD_ID.equals(modID)) {
|
||||
entry = AutoFileSyncEntry.ForDirectFileRequest.finishDeserializeContent(uniqueID, buf);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
entry = AutoFileSyncEntry.findMatching(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);
|
||||
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) {
|
||||
|
@ -154,13 +156,11 @@ class AutoFileSyncEntry extends AutoSyncID {
|
|||
public static AutoFileSyncEntry findMatching(AutoSyncID aid) {
|
||||
if (aid instanceof AutoSyncID.ForDirectFileRequest) {
|
||||
AutoSyncID.ForDirectFileRequest freq = (AutoSyncID.ForDirectFileRequest) aid;
|
||||
SyncFolderDescriptor desc = DataExchange.getSyncFolderDescriptor(freq.uniqueID);
|
||||
SyncFolderDescriptor desc = AutoSync.getSyncFolderDescriptor(freq.uniqueID);
|
||||
if (desc != null) {
|
||||
SubFile subFile = desc.getLocalSubFile(freq.relFile.toString());
|
||||
if (subFile != null) {
|
||||
final File absPath = desc
|
||||
.localFolder
|
||||
.resolve(subFile.relPath)
|
||||
final File absPath = desc.localFolder.resolve(subFile.relPath)
|
||||
.normalize()
|
||||
.toFile();
|
||||
return new AutoFileSyncEntry.ForDirectFileRequest(freq.uniqueID, new File(subFile.relPath), absPath);
|
||||
|
@ -172,8 +172,7 @@ class AutoFileSyncEntry extends AutoSyncID {
|
|||
}
|
||||
|
||||
public static AutoFileSyncEntry findMatching(String modID, String uniqueID) {
|
||||
return DataExchange.getInstance()
|
||||
.getAutoSyncFiles()
|
||||
return AutoSync.getAutoSyncFiles()
|
||||
.stream()
|
||||
.filter(asf -> asf.modID.equals(modID) && asf.uniqueID.equals(uniqueID))
|
||||
.findFirst()
|
|
@ -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 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;
|
||||
|
|
@ -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.Environment;
|
||||
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.gui.screens.Screen;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
|
@ -14,13 +12,15 @@ 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.handler.AutoSyncID.WithContentOverride;
|
||||
import ru.bclib.api.dataexchange.handler.DataExchange.SyncFolderDescriptor;
|
||||
import ru.bclib.api.dataexchange.handler.DataExchange.SyncFolderDescriptor.SubFile;
|
||||
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.api.dataexchange.handler.autosync.AutoSyncID.WithContentOverride;
|
||||
import ru.bclib.api.dataexchange.handler.autosync.SyncFolderDescriptor.SubFile;
|
||||
import ru.bclib.api.datafixer.DataFixerAPI;
|
||||
import ru.bclib.config.Configs;
|
||||
import ru.bclib.gui.screens.SyncFilesScreen;
|
||||
import ru.bclib.gui.screens.WarnBCLibVersionMismatch;
|
||||
import ru.bclib.util.PathUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
@ -28,7 +28,6 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -44,36 +43,18 @@ public class HelloClient extends DataHandler {
|
|||
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() {
|
||||
return getModVersion(BCLib.MOD_ID);
|
||||
return PathUtil.getModVersion(BCLib.MOD_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
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.");
|
||||
return false;
|
||||
}
|
||||
|
||||
DataExchange.getInstance().loadSyncFolder();
|
||||
AutoSync.loadSyncFolder();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -86,12 +67,12 @@ public class HelloClient extends DataHandler {
|
|||
//write BCLibVersion (=protocol version)
|
||||
buf.writeInt(DataFixerAPI.getModVersion(vbclib));
|
||||
|
||||
if (Configs.MAIN_CONFIG.getBoolean(Configs.MAIN_SYNC_CATEGORY, "offerMods", true)) {
|
||||
if (Config.isOfferingMods()) {
|
||||
//write Plugin Versions
|
||||
buf.writeInt(mods.size());
|
||||
for (String modID : mods) {
|
||||
writeString(buf, modID);
|
||||
final String ver = getModVersion(modID);
|
||||
final String ver = PathUtil.getModVersion(modID);
|
||||
buf.writeInt(DataFixerAPI.getModVersion(ver));
|
||||
BCLib.LOGGER.info(" - Listing Mod " + modID + " v" + ver);
|
||||
}
|
||||
|
@ -101,9 +82,9 @@ public class HelloClient extends DataHandler {
|
|||
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
|
||||
final List<AutoFileSyncEntry> existingAutoSyncFiles = DataExchange.getInstance()
|
||||
final List<AutoFileSyncEntry> existingAutoSyncFiles = AutoSync
|
||||
.getAutoSyncFiles()
|
||||
.stream()
|
||||
.filter(e -> e.fileName.exists())
|
||||
|
@ -121,9 +102,9 @@ public class HelloClient extends DataHandler {
|
|||
buf.writeInt(0);
|
||||
}
|
||||
|
||||
if (Configs.MAIN_CONFIG.getBoolean(Configs.MAIN_SYNC_CATEGORY, "offersSyncFolders", true)) {
|
||||
buf.writeInt(((DataExchange) DataExchange.getInstance()).syncFolderDescriptions.size());
|
||||
((DataExchange) DataExchange.getInstance()).syncFolderDescriptions.forEach(desc -> {
|
||||
if (Config.isOfferingFolders()) {
|
||||
buf.writeInt(AutoSync.syncFolderDescriptions.size());
|
||||
AutoSync.syncFolderDescriptions.forEach(desc -> {
|
||||
BCLib.LOGGER.info(" - Offering Folder " + desc.localFolder + " (allowDelete=" + desc.removeAdditionalFiles + ")");
|
||||
desc.serialize(buf);
|
||||
});
|
||||
|
@ -132,12 +113,11 @@ public class HelloClient extends DataHandler {
|
|||
BCLib.LOGGER.info("Server will not offer Sync Folders.");
|
||||
buf.writeInt(0);
|
||||
}
|
||||
Configs.MAIN_CONFIG.saveChanges();
|
||||
}
|
||||
|
||||
String bclibVersion = "0.0.0";
|
||||
Map<String, String> modVersion = new HashMap<>();
|
||||
List<DataExchange.AutoSyncTriple> autoSyncedFiles = null;
|
||||
List<AutoSync.AutoSyncTriple> autoSyncedFiles = null;
|
||||
List<SyncFolderDescriptor> autoSynFolders = null;
|
||||
|
||||
@Override
|
||||
|
@ -159,7 +139,7 @@ public class HelloClient extends DataHandler {
|
|||
autoSyncedFiles = new ArrayList<>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
//System.out.println("Deserializing ");
|
||||
DataExchange.AutoSyncTriple t = AutoFileSyncEntry.deserializeAndMatch(buf);
|
||||
AutoSync.AutoSyncTriple t = AutoFileSyncEntry.deserializeAndMatch(buf);
|
||||
autoSyncedFiles.add(t);
|
||||
//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) {
|
||||
if (!Configs.CLIENT_CONFIG.getBoolean(Configs.MAIN_SYNC_CATEGORY, "syncFolders", true)) {
|
||||
if (!ClientConfig.isClientConfigAcceptingFolders()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -187,7 +167,7 @@ public class HelloClient extends DataHandler {
|
|||
|
||||
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
|
||||
SyncFolderDescriptor localDescriptor = DataExchange.getSyncFolderDescriptor(desc.folderID);
|
||||
SyncFolderDescriptor localDescriptor = AutoSync.getSyncFolderDescriptor(desc.folderID);
|
||||
if (localDescriptor != null) {
|
||||
BCLib.LOGGER.info(" - " + desc.folderID + " (" + desc.localFolder + ", allowRemove=" + desc.removeAdditionalFiles + ")");
|
||||
localDescriptor.invalidateCache();
|
||||
|
@ -220,7 +200,8 @@ public class HelloClient extends DataHandler {
|
|||
if (!localSubFile.hash.equals(subFile.hash)) {
|
||||
BCLib.LOGGER.info(" * " + subFile.relPath + " (changed)");
|
||||
filesToRequest.add(new AutoSyncID.ForDirectFileRequest(desc.folderID, new File(subFile.relPath)));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
BCLib.LOGGER.info(" * " + subFile.relPath);
|
||||
}
|
||||
}
|
||||
|
@ -241,7 +222,7 @@ public class HelloClient extends DataHandler {
|
|||
}
|
||||
|
||||
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) {
|
||||
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
|
||||
//There are no restrictions to the target folder, but the client decides the final
|
||||
//location.
|
||||
for (DataExchange.AutoSyncTriple e : autoSyncedFiles) {
|
||||
for (AutoSync.AutoSyncTriple e : autoSyncedFiles) {
|
||||
String actionString = "";
|
||||
FileContentWrapper contentWrapper = new FileContentWrapper(e.serverContent);
|
||||
if (e.localMatch == null) {
|
||||
|
@ -281,7 +262,7 @@ public class HelloClient extends DataHandler {
|
|||
|
||||
@Override
|
||||
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.");
|
||||
return;
|
||||
}
|
||||
|
@ -297,7 +278,7 @@ public class HelloClient extends DataHandler {
|
|||
final List<AutoSyncID.ForDirectFileRequest> filesToRemove = new ArrayList<>(2);
|
||||
|
||||
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 + ")");
|
||||
}
|
||||
|
||||
|
@ -308,7 +289,7 @@ public class HelloClient extends DataHandler {
|
|||
//Both client and server need to know about the folder you want to sync
|
||||
//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);
|
||||
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.minecraft.client.Minecraft;
|
||||
|
@ -9,8 +9,9 @@ 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.handler.autosync.AutoSync.ClientConfig;
|
||||
import ru.bclib.api.dataexchange.handler.autosync.AutoSync.Config;
|
||||
import ru.bclib.api.datafixer.DataFixerAPI;
|
||||
import ru.bclib.config.Configs;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
@ -59,6 +60,7 @@ public class HelloServer extends DataHandler {
|
|||
public static DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "hello_server"), HelloServer::new, true, false);
|
||||
|
||||
protected String bclibVersion = "0.0.0";
|
||||
|
||||
public HelloServer() {
|
||||
super(DESCRIPTOR.IDENTIFIER, false);
|
||||
}
|
||||
|
@ -66,7 +68,7 @@ public class HelloServer extends DataHandler {
|
|||
|
||||
@Override
|
||||
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.");
|
||||
return false;
|
||||
}
|
||||
|
@ -86,7 +88,7 @@ public class HelloServer extends DataHandler {
|
|||
|
||||
@Override
|
||||
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.");
|
||||
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.minecraft.client.Minecraft;
|
||||
|
@ -8,7 +8,8 @@ import net.minecraft.server.MinecraftServer;
|
|||
import ru.bclib.BCLib;
|
||||
import ru.bclib.api.dataexchange.DataHandler;
|
||||
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.List;
|
||||
|
@ -20,6 +21,7 @@ public class RequestFiles extends DataHandler {
|
|||
static String currentToken = "";
|
||||
|
||||
protected List<AutoSyncID> files;
|
||||
|
||||
private RequestFiles() {
|
||||
this(null);
|
||||
}
|
||||
|
@ -31,7 +33,7 @@ public class RequestFiles extends DataHandler {
|
|||
|
||||
@Override
|
||||
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.");
|
||||
return false;
|
||||
}
|
||||
|
@ -51,6 +53,7 @@ public class RequestFiles extends DataHandler {
|
|||
}
|
||||
|
||||
String receivedToken = "";
|
||||
|
||||
@Override
|
||||
protected void deserializeFromIncomingData(FriendlyByteBuf buf, PacketSender responseSender, boolean fromClient) {
|
||||
receivedToken = readString(buf);
|
||||
|
@ -69,13 +72,13 @@ public class RequestFiles extends DataHandler {
|
|||
|
||||
@Override
|
||||
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.");
|
||||
return;
|
||||
}
|
||||
|
||||
List<AutoFileSyncEntry> syncEntries = files
|
||||
.stream().map(asid -> AutoFileSyncEntry.findMatching(asid))
|
||||
List<AutoFileSyncEntry> syncEntries = files.stream()
|
||||
.map(asid -> AutoFileSyncEntry.findMatching(asid))
|
||||
.filter(e -> e != null)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
@ -83,7 +86,8 @@ public class RequestFiles extends DataHandler {
|
|||
}
|
||||
|
||||
public static void newToken() {
|
||||
currentToken = UUID.randomUUID().toString();
|
||||
currentToken = UUID.randomUUID()
|
||||
.toString();
|
||||
}
|
||||
|
||||
static {
|
|
@ -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.Environment;
|
||||
|
@ -11,7 +11,9 @@ import net.minecraft.server.MinecraftServer;
|
|||
import ru.bclib.BCLib;
|
||||
import ru.bclib.api.dataexchange.DataHandler;
|
||||
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.util.Pair;
|
||||
import ru.bclib.util.Triple;
|
||||
|
@ -29,23 +31,20 @@ public class SendFiles extends DataHandler {
|
|||
|
||||
protected List<AutoFileSyncEntry> files;
|
||||
private String token = "";
|
||||
|
||||
public SendFiles() {
|
||||
this(null, "");
|
||||
}
|
||||
|
||||
public SendFiles(List<AutoFileSyncEntry> files, String token) {
|
||||
super(DESCRIPTOR.IDENTIFIER, true);
|
||||
this.files = files;
|
||||
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
|
||||
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.");
|
||||
return false;
|
||||
}
|
||||
|
@ -55,7 +54,9 @@ public class SendFiles extends DataHandler {
|
|||
|
||||
@Override
|
||||
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
|
||||
existingFiles.add(new AutoFileSyncEntry("none", new File("D:\\MinecraftPlugins\\BetterNether\\run\\server.properties"),true,(a, b, content) -> {
|
||||
|
@ -81,9 +82,10 @@ public class SendFiles extends DataHandler {
|
|||
}
|
||||
|
||||
private List<Pair<AutoFileSyncEntry, byte[]>> receivedFiles;
|
||||
|
||||
@Override
|
||||
protected void deserializeFromIncomingData(FriendlyByteBuf buf, PacketSender responseSender, boolean fromClient) {
|
||||
if (acceptFiles()) {
|
||||
if (ClientConfig.isClientConfigAcceptingFiles()) {
|
||||
token = readString(buf);
|
||||
if (!token.equals(RequestFiles.currentToken)) {
|
||||
RequestFiles.newToken();
|
||||
|
@ -101,7 +103,8 @@ public class SendFiles extends DataHandler {
|
|||
if (p.first != null) {
|
||||
receivedFiles.add(p);
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +113,7 @@ public class SendFiles extends DataHandler {
|
|||
|
||||
@Override
|
||||
protected void runOnGameThread(Minecraft client, MinecraftServer server, boolean isClient) {
|
||||
if (acceptFiles()) {
|
||||
if (ClientConfig.isClientConfigAcceptingFiles()) {
|
||||
BCLib.LOGGER.info("Writing Files:");
|
||||
|
||||
//TODO: Reject files that were not in the last RequestFiles.
|
||||
|
@ -135,8 +138,9 @@ public class SendFiles extends DataHandler {
|
|||
parentFile.mkdirs();
|
||||
}
|
||||
Files.write(path, data);
|
||||
DataExchange.didReceiveFile(e, fileName);
|
||||
} catch (IOException ioException) {
|
||||
AutoSync.didReceiveFile(e, fileName);
|
||||
}
|
||||
catch (IOException ioException) {
|
||||
BCLib.LOGGER.error(" --> Writing " + fileName + " failed: " + ioException);
|
||||
}
|
||||
}
|
||||
|
@ -144,7 +148,8 @@ public class SendFiles extends DataHandler {
|
|||
@Environment(EnvType.CLIENT)
|
||||
protected void showConfirmRestart(Minecraft client) {
|
||||
client.setScreen(new ConfirmRestartScreen(() -> {
|
||||
Minecraft.getInstance().setScreen((Screen)null);
|
||||
Minecraft.getInstance()
|
||||
.setScreen((Screen) null);
|
||||
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.api.dataexchange.DataExchangeAPI;
|
||||
import ru.bclib.api.dataexchange.SyncFileHash;
|
||||
import ru.bclib.api.dataexchange.handler.AutoSyncID;
|
||||
import ru.bclib.api.dataexchange.handler.FileContentWrapper;
|
||||
import ru.bclib.api.dataexchange.handler.autosync.AutoSyncID;
|
||||
import ru.bclib.api.dataexchange.handler.autosync.FileContentWrapper;
|
||||
import ru.bclib.config.ConfigKeeper.BooleanEntry;
|
||||
import ru.bclib.config.ConfigKeeper.Entry;
|
||||
import ru.bclib.config.ConfigKeeper.FloatEntry;
|
||||
|
|
|
@ -6,7 +6,7 @@ import com.google.gson.JsonElement;
|
|||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.util.GsonHelper;
|
||||
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.Pair;
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ public class Configs {
|
|||
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 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");
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package ru.bclib.util;
|
||||
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.fabricmc.loader.api.ModContainer;
|
||||
import net.fabricmc.loader.api.metadata.ModMetadata;
|
||||
import net.fabricmc.loader.metadata.ModMetadataParser;
|
||||
import net.fabricmc.loader.metadata.ParseMetadataException;
|
||||
|
@ -15,6 +16,7 @@ import java.nio.file.FileSystems;
|
|||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
|
@ -127,4 +129,22 @@ public class PathUtil {
|
|||
|
||||
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