Implemented ModSync
This commit is contained in:
parent
8588191556
commit
71ad055ea5
6 changed files with 165 additions and 29 deletions
|
@ -40,6 +40,7 @@ public class BCLib implements ModInitializer {
|
|||
CraftingRecipes.init();
|
||||
WorldDataAPI.registerModCache(MOD_ID);
|
||||
DataExchangeAPI.registerMod(MOD_ID);
|
||||
DataExchangeAPI.registerModDependency("wunderreich");
|
||||
DataFixerAPI.registerPatch(() -> new BCLibPatch());
|
||||
DataExchangeAPI.registerDescriptors(List.of(
|
||||
HelloClient.DESCRIPTOR,
|
||||
|
|
|
@ -6,6 +6,7 @@ import ru.bclib.api.dataexchange.DataHandler;
|
|||
import ru.bclib.api.dataexchange.SyncFileHash;
|
||||
import ru.bclib.api.dataexchange.handler.autosync.AutoSync.NeedTransferPredicate;
|
||||
import ru.bclib.api.dataexchange.handler.autosync.SyncFolderDescriptor.SubFile;
|
||||
import ru.bclib.api.datafixer.DataFixerAPI;
|
||||
import ru.bclib.util.Pair;
|
||||
import ru.bclib.util.PathUtil;
|
||||
import ru.bclib.util.PathUtil.ModInfo;
|
||||
|
@ -54,34 +55,41 @@ class AutoFileSyncEntry extends AutoSyncID {
|
|||
}
|
||||
|
||||
static class ForModFileRequest extends AutoFileSyncEntry {
|
||||
public static Path getLocalPathForID(String modID){
|
||||
ModInfo mi = PathUtil.getModInfo(modID);
|
||||
public static File getLocalPathForID(String modID, boolean matchLocalVersion){
|
||||
ModInfo mi = PathUtil.getModInfo(modID, matchLocalVersion);
|
||||
if (mi!=null){
|
||||
return mi.jarPath;
|
||||
return mi.jarPath.toFile();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
ForModFileRequest(String modID) {
|
||||
super(modID, AutoSyncID.ForModFileRequest.UNIQUE_ID, getLocalPathForID(modID).toFile(), false, (a, b, c) -> false);
|
||||
if (this.fileName == null){
|
||||
public final String version;
|
||||
ForModFileRequest(String modID, boolean matchLocalVersion, String version) {
|
||||
super(modID, AutoSyncID.ForModFileRequest.UNIQUE_ID, getLocalPathForID(modID, matchLocalVersion), false, (a, b, c) -> false);
|
||||
if (this.fileName == null && matchLocalVersion){
|
||||
BCLib.LOGGER.error("Unknown mod '"+modID+"'.");
|
||||
}
|
||||
if (version==null)
|
||||
this.version = PathUtil.getModVersion(modID);
|
||||
else
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serializeContent(FriendlyByteBuf buf) {
|
||||
final int res = super.serializeContent(buf);
|
||||
buf.writeInt(DataFixerAPI.getModVersion(version));
|
||||
return res;
|
||||
}
|
||||
|
||||
static AutoFileSyncEntry.ForModFileRequest finishDeserializeContent(String modID, FriendlyByteBuf buf) {
|
||||
return new AutoFileSyncEntry.ForModFileRequest(modID);
|
||||
final String version = DataFixerAPI.getModVersion(buf.readInt());
|
||||
return new AutoFileSyncEntry.ForModFileRequest(modID, false, version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return modID;
|
||||
return "Mod " + modID + " (v" + version + ")";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,7 +145,7 @@ class AutoFileSyncEntry extends AutoSyncID {
|
|||
entry = AutoFileSyncEntry.ForDirectFileRequest.finishDeserializeContent(uniqueID, buf);
|
||||
}
|
||||
else if (AutoSyncID.ForModFileRequest.UNIQUE_ID.equals(uniqueID)) {
|
||||
entry = AutoFileSyncEntry.ForModFileRequest.finishDeserializeContent(uniqueID, buf);
|
||||
entry = AutoFileSyncEntry.ForModFileRequest.finishDeserializeContent(modID, buf);
|
||||
}
|
||||
else {
|
||||
entry = AutoFileSyncEntry.findMatching(modID, uniqueID);
|
||||
|
@ -205,6 +213,9 @@ class AutoFileSyncEntry extends AutoSyncID {
|
|||
}
|
||||
}
|
||||
return null;
|
||||
} else if (aid instanceof AutoSyncID.ForModFileRequest) {
|
||||
AutoSyncID.ForModFileRequest mreq = (AutoSyncID.ForModFileRequest) aid;
|
||||
return new AutoFileSyncEntry.ForModFileRequest(mreq.modID, true, null);
|
||||
}
|
||||
return findMatching(aid.modID, aid.uniqueID);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,11 @@ public class AutoSyncID {
|
|||
this.contentWrapper = contentWrapper;
|
||||
this.localFile = localFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " (Content override)";
|
||||
}
|
||||
}
|
||||
|
||||
static class ForDirectFileRequest extends AutoSyncID {
|
||||
|
@ -39,6 +44,11 @@ public class AutoSyncID {
|
|||
final File fl = new File(DataHandler.readString(buf));
|
||||
return new ForDirectFileRequest(uniqueID, fl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.uniqueID + " (" + this.relFile + ")";
|
||||
}
|
||||
}
|
||||
|
||||
static class ForModFileRequest extends AutoSyncID {
|
||||
|
@ -59,6 +69,11 @@ public class AutoSyncID {
|
|||
final String version = DataFixerAPI.getModVersion(buf.readInt());
|
||||
return new ForModFileRequest(modID, version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.modID + " (v" + this.version + ")";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,9 +18,13 @@ import ru.bclib.api.dataexchange.handler.autosync.SyncFolderDescriptor.SubFile;
|
|||
import ru.bclib.api.datafixer.DataFixerAPI;
|
||||
import ru.bclib.gui.screens.SyncFilesScreen;
|
||||
import ru.bclib.gui.screens.WarnBCLibVersionMismatch;
|
||||
import ru.bclib.util.Pair;
|
||||
import ru.bclib.util.PathUtil;
|
||||
import ru.bclib.util.PathUtil.ModInfo;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -69,10 +73,23 @@ public class HelloClient extends DataHandler.FromServer {
|
|||
//write Plugin Versions
|
||||
buf.writeInt(mods.size());
|
||||
for (String modID : mods) {
|
||||
writeString(buf, modID);
|
||||
final String ver = PathUtil.getModVersion(modID);
|
||||
final ModInfo mi = PathUtil.getModInfo(modID);
|
||||
int size = 0;
|
||||
if (mi!=null) {
|
||||
try {
|
||||
size = (int)Files.size(mi.jarPath);
|
||||
}
|
||||
catch (IOException e) {
|
||||
BCLib.LOGGER.error("Unable to get File Size: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
writeString(buf, modID);
|
||||
buf.writeInt(DataFixerAPI.getModVersion(ver));
|
||||
BCLib.LOGGER.info(" - Listing Mod " + modID + " v" + ver);
|
||||
buf.writeInt(size);
|
||||
|
||||
BCLib.LOGGER.info(" - Listing Mod " + modID + " v" + ver + " ("+PathUtil.humanReadableFileSize(size)+")");
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -114,7 +131,7 @@ public class HelloClient extends DataHandler.FromServer {
|
|||
}
|
||||
|
||||
String bclibVersion = "0.0.0";
|
||||
Map<String, String> modVersion = new HashMap<>();
|
||||
Map<String, Pair<String, Integer>> modVersion = new HashMap<>();
|
||||
List<AutoSync.AutoSyncTriple> autoSyncedFiles = null;
|
||||
List<SyncFolderDescriptor> autoSynFolders = null;
|
||||
|
||||
|
@ -123,14 +140,23 @@ public class HelloClient extends DataHandler.FromServer {
|
|||
protected void deserializeIncomingDataOnClient(FriendlyByteBuf buf, PacketSender responseSender) {
|
||||
//read BCLibVersion (=protocol version)
|
||||
bclibVersion = DataFixerAPI.getModVersion(buf.readInt());
|
||||
final boolean protocolVersion_0_4_1 = DataFixerAPI.isLargerOrEqualVersion(bclibVersion, "0.4.1");
|
||||
|
||||
|
||||
//read Plugin Versions
|
||||
modVersion = new HashMap<>();
|
||||
int count = buf.readInt();
|
||||
for (int i = 0; i < count; i++) {
|
||||
String id = readString(buf);
|
||||
String version = DataFixerAPI.getModVersion(buf.readInt());
|
||||
modVersion.put(id, version);
|
||||
final String id = readString(buf);
|
||||
final String version = DataFixerAPI.getModVersion(buf.readInt());
|
||||
final int size;
|
||||
//since v0.4.1 we also send the size of the mod-File
|
||||
if (protocolVersion_0_4_1) {
|
||||
size = buf.readInt();
|
||||
} else {
|
||||
size = 0;
|
||||
}
|
||||
modVersion.put(id, new Pair<>(version, size));
|
||||
}
|
||||
|
||||
//read config Data
|
||||
|
@ -146,7 +172,7 @@ public class HelloClient extends DataHandler.FromServer {
|
|||
|
||||
autoSynFolders = new ArrayList<>(1);
|
||||
//since v0.4.1 we also send the sync folders
|
||||
if (DataFixerAPI.isLargerOrEqualVersion(bclibVersion, "0.4.1")) {
|
||||
if (protocolVersion_0_4_1) {
|
||||
final int folderCount = buf.readInt();
|
||||
for (int i = 0; i < folderCount; i++) {
|
||||
SyncFolderDescriptor desc = SyncFolderDescriptor.deserialize(buf);
|
||||
|
@ -262,14 +288,14 @@ public class HelloClient extends DataHandler.FromServer {
|
|||
|
||||
@Environment(EnvType.CLIENT)
|
||||
private void processModFileSync(final List<AutoSyncID> filesToRequest) {
|
||||
for (Entry<String, String> e : modVersion.entrySet()) {
|
||||
for (Entry<String, Pair<String, Integer>> e : modVersion.entrySet()) {
|
||||
final String localVersion = PathUtil.getModVersion(e.getKey());
|
||||
final String serverVersion = e.getValue();
|
||||
final boolean requestMod = !serverVersion.equals(localVersion);
|
||||
final Pair<String, Integer> serverInfo = e.getValue();
|
||||
final boolean requestMod = !serverInfo.first.equals(localVersion) && serverInfo.second>0;
|
||||
|
||||
BCLib.LOGGER.info(" - " + e.getKey() + " (client=" + localVersion + ", server=" + serverVersion + (requestMod?", requesting":"") +")");
|
||||
BCLib.LOGGER.info(" - " + e.getKey() + " (client=" + localVersion + ", server=" + serverInfo.first + ", size=" + PathUtil.humanReadableFileSize(serverInfo.second) + (requestMod?", requesting":"") +")");
|
||||
if (requestMod){
|
||||
filesToRequest.add(new AutoSyncID.ForModFileRequest(e.getKey(), serverVersion));
|
||||
filesToRequest.add(new AutoSyncID.ForModFileRequest(e.getKey(), serverInfo.first));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ 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.PathUtil;
|
||||
import ru.bclib.util.Triple;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -75,7 +76,7 @@ public class SendFiles extends DataHandler.FromServer {
|
|||
BCLib.LOGGER.info("Sending " + existingFiles.size() + " Files to Client:");
|
||||
for (AutoFileSyncEntry entry : existingFiles) {
|
||||
int length = entry.serializeContent(buf);
|
||||
BCLib.LOGGER.info(" - " + entry + " (" + length + " Bytes)");
|
||||
BCLib.LOGGER.info(" - " + entry + " (" + PathUtil.humanReadableFileSize(length) + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,7 +102,7 @@ public class SendFiles extends DataHandler.FromServer {
|
|||
Triple<AutoFileSyncEntry, byte[], AutoSyncID> p = AutoFileSyncEntry.deserializeContent(buf);
|
||||
if (p.first != null) {
|
||||
receivedFiles.add(p);
|
||||
BCLib.LOGGER.info(" - " + p.first + " (" + p.second.length + " Bytes)");
|
||||
BCLib.LOGGER.info(" - " + p.first + " (" + PathUtil.humanReadableFileSize(p.second.length) + ")");
|
||||
}
|
||||
else {
|
||||
BCLib.LOGGER.error(" - Failed to receive File " + p.third + ", possibly sent from a Mod that is not installed on the client.");
|
||||
|
@ -128,10 +129,36 @@ public class SendFiles extends DataHandler.FromServer {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public static void writeSyncedFile(AutoSyncID e, byte[] data, File fileName) {
|
||||
Path path = fileName.toPath();
|
||||
BCLib.LOGGER.info(" - Writing " + path + " (" + data.length + " Bytes)");
|
||||
if (!PathUtil.MOD_BAK_FOLDER.toFile().exists()){
|
||||
PathUtil.MOD_BAK_FOLDER.toFile().mkdirs();
|
||||
}
|
||||
|
||||
Path path = fileName!=null?fileName.toPath():null;
|
||||
Path removeAfter = null;
|
||||
if (e instanceof AutoFileSyncEntry.ForModFileRequest){
|
||||
AutoFileSyncEntry.ForModFileRequest mase = (AutoFileSyncEntry.ForModFileRequest)e;
|
||||
removeAfter = path;
|
||||
int count = 0;
|
||||
String name = "bclib_synced_" + mase.modID + "_" + mase.version.replace(".", "_") + ".jar";
|
||||
do {
|
||||
if (path != null) {
|
||||
//move to the same directory as the existing Mod
|
||||
path = path.getParent()
|
||||
.resolve(name);
|
||||
}
|
||||
else {
|
||||
//move to the default mode location
|
||||
path = PathUtil.MOD_FOLDER.resolve(name);
|
||||
}
|
||||
count++;
|
||||
name = "bclib_synced_" + mase.modID + "_" + mase.version.replace(".", "_") + "__" + String.format("%03d", count) + ".jar";
|
||||
} while (path.toFile().exists());
|
||||
}
|
||||
|
||||
BCLib.LOGGER.info(" - Writing " + path + " (" + PathUtil.humanReadableFileSize(data.length) + ")");
|
||||
try {
|
||||
final File parentFile = path.getParent()
|
||||
.toFile();
|
||||
|
@ -139,7 +166,23 @@ public class SendFiles extends DataHandler.FromServer {
|
|||
parentFile.mkdirs();
|
||||
}
|
||||
Files.write(path, data);
|
||||
if (removeAfter != null){
|
||||
final String bakFileName = removeAfter.toFile().getName();
|
||||
String collisionFreeName = bakFileName;
|
||||
Path targetPath;
|
||||
int count = 0;
|
||||
do {
|
||||
targetPath = PathUtil.MOD_BAK_FOLDER.resolve(collisionFreeName);
|
||||
count++;
|
||||
collisionFreeName = String.format("%03d", count) + "_" + bakFileName;
|
||||
} while (targetPath.toFile().exists());
|
||||
|
||||
BCLib.LOGGER.info(" - Moving " + removeAfter + " to " +targetPath);
|
||||
removeAfter.toFile().renameTo(targetPath.toFile());
|
||||
}
|
||||
AutoSync.didReceiveFile(e, fileName);
|
||||
|
||||
|
||||
}
|
||||
catch (IOException ioException) {
|
||||
BCLib.LOGGER.error(" --> Writing " + fileName + " failed: " + ioException);
|
||||
|
|
|
@ -30,6 +30,9 @@ public class PathUtil {
|
|||
.resolve("mods")
|
||||
.normalize();
|
||||
|
||||
public final static Path MOD_BAK_FOLDER = MOD_FOLDER.resolve("_bclib_deactivated")
|
||||
.normalize();
|
||||
|
||||
/**
|
||||
* Tests if a path is a child-path.
|
||||
* <p>
|
||||
|
@ -95,7 +98,13 @@ public class PathUtil {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ModInfo{" + "id=" + metadata.getId()+ "version=" + metadata.getVersion() + "jarPath=" + jarPath + '}';
|
||||
return "ModInfo{" + "id=" + metadata.getId() + ", version=" + metadata.getVersion() + ", jarPath=" + jarPath + '}';
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
if (metadata == null) return "0.0.0";
|
||||
return metadata.getVersion()
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,10 +124,11 @@ public class PathUtil {
|
|||
* calling {@link #invalidateCachedMods()}
|
||||
* <p>
|
||||
* An error message is printed if a mod fails to load, but the parsing will continue.
|
||||
*
|
||||
* @return A map of all found mods. (key=ModID, value={@link ModInfo})
|
||||
*/
|
||||
public static Map<String, ModInfo> getMods() {
|
||||
if (mods!=null) return mods;
|
||||
if (mods != null) return mods;
|
||||
|
||||
mods = new HashMap<>();
|
||||
org.apache.logging.log4j.Logger logger = LogManager.getFormatterLogger("BCLib|ModLoader");
|
||||
|
@ -150,18 +160,24 @@ public class PathUtil {
|
|||
* <p>
|
||||
* The call will also return null if the mode-Version in the jar-File is not the same
|
||||
* as the version of the loaded Mod.
|
||||
*
|
||||
* @param modID The mod ID to query
|
||||
* @return A {@link ModInfo}-Object for the querried Mod.
|
||||
*/
|
||||
public static ModInfo getModInfo(String modID){
|
||||
public static ModInfo getModInfo(String modID) {
|
||||
return getModInfo(modID, true);
|
||||
}
|
||||
|
||||
public static ModInfo getModInfo(String modID, boolean matchVersion) {
|
||||
getMods();
|
||||
final ModInfo mi = mods.get(modID);
|
||||
if (!getModVersion(modID).equals(mi.metadata.getVersion())) return null;
|
||||
if (mi == null || !getModVersion(modID).equals(mi.getVersion())) return null;
|
||||
return mi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Mod Version for the queried Mod
|
||||
*
|
||||
* @param modID The mod ID to query
|
||||
* @return The version of the locally installed Mod
|
||||
*/
|
||||
|
@ -176,4 +192,28 @@ public class PathUtil {
|
|||
}
|
||||
return "0.0.0";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a human readable File-Size
|
||||
*
|
||||
* @param size Filesize in bytes
|
||||
* @return A Human readable String
|
||||
*/
|
||||
public static String humanReadableFileSize(long size) {
|
||||
final int threshold = 2;
|
||||
final int factor = 1024;
|
||||
if (size < 0) return "? Byte";
|
||||
if (size < factor * threshold) {
|
||||
return size + " Byte";
|
||||
}
|
||||
char[] units = {'K', 'M', 'G', 'T', 'P'};
|
||||
int unitIndex = 0;
|
||||
double fSize = size;
|
||||
do {
|
||||
unitIndex++;
|
||||
fSize /= 1024;
|
||||
} while (fSize > factor * threshold && unitIndex < units.length);
|
||||
|
||||
return String.format("%.1f %ciB", fSize, units[unitIndex - 1]);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue