desc) {
- DataExchange api = DataExchange.getInstance();
- api.getDescriptors()
- .addAll(desc);
- }
-
- /**
- * Sends the Handler.
- *
- * Depending on what the result of {@link DataHandler#getOriginatesOnServer()}, the Data is sent from the server
- * to the client (if {@code true}) or the other way around.
- *
- * The method {@link DataHandler#serializeData(FriendlyByteBuf, boolean)} is called just before the data is sent. You should
- * use this method to add the Data you need to the communication.
- *
- * @param h The Data that you want to send
- */
- public static void send(BaseDataHandler h) {
- if (h.getOriginatesOnServer()) {
- DataExchangeAPI.getInstance().server.sendToClient(h);
- } else {
- DataExchangeAPI.getInstance().client.sendToServer(h);
- }
- }
-
- /**
- * Registers a File for automatic client syncing.
- *
- * @param modID The ID of the calling Mod
- * @param fileName The name of the File
- */
- public static void addAutoSyncFile(String modID, File fileName) {
- AutoSync.addAutoSyncFileData(modID, fileName, false, SyncFileHash.NEED_TRANSFER);
- }
-
- /**
- * Registers a File for automatic client syncing.
- *
- * The file is synced of the {@link SyncFileHash} on client and server are not equal. This method will not copy the
- * configs content from the client to the server.
- *
- * @param modID The ID of the calling Mod
- * @param uniqueID A unique Identifier for the File. (see {@link SyncFileHash#uniqueID} for
- * Details
- * @param fileName The name of the File
- */
- public static void addAutoSyncFile(String modID, String uniqueID, File fileName) {
- AutoSync.addAutoSyncFileData(modID, uniqueID, fileName, false, SyncFileHash.NEED_TRANSFER);
- }
-
- /**
- * Registers a File for automatic client syncing.
- *
- * The content of the file is requested for comparison. This will copy the
- * entire file from the client to the server.
- *
- * 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.
- *
- * @param modID The ID of the calling Mod
- * @param fileName The name of the File
- * @param needTransfer If the predicate returns true, the file needs to get copied to the server.
- */
- public static void addAutoSyncFile(String modID, File fileName, AutoSync.NeedTransferPredicate needTransfer) {
- AutoSync.addAutoSyncFileData(modID, fileName, true, needTransfer);
- }
-
- /**
- * Registers a File for automatic client syncing.
- *
- * The content of the file is requested for comparison. This will copy the
- * entire file from the client to the server.
- *
- * 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.
- *
- * @param modID The ID of the calling Mod
- * @param uniqueID A unique Identifier for the File. (see {@link SyncFileHash#uniqueID} for
- * Details
- * @param fileName The name of the File
- * @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,
- AutoSync.NeedTransferPredicate needTransfer
- ) {
- AutoSync.addAutoSyncFileData(modID, uniqueID, fileName, true, needTransfer);
- }
-
- /**
- * Register a function that is called whenever the client receives a file from the server and replaced toe local
- * file with the new content.
- *
- * 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 callback) {
- AutoSync.addOnWriteCallback(callback);
- }
-
- /**
- * Returns the sync-folder for a given Mod.
- *
- * BCLib will ensure that the contents of sync-folder on the client is the same as the one on the server.
- *
- * @param modID ID of the Mod
- * @return The path to the sync-folder
- */
- public static File getModSyncFolder(String modID) {
- File fl = AutoSync.SYNC_FOLDER.localFolder.resolve(modID.replace(".", "-")
- .replace(":", "-")
- .replace("\\", "-")
- .replace("/", "-"))
- .normalize()
- .toFile();
-
- if (!fl.exists()) {
- fl.mkdirs();
- }
- return fl;
- }
-
- static {
- addOnWriteCallback(Config::reloadSyncedConfig);
- }
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/dataexchange/DataHandler.java b/src/main/java/org/betterx/bclib/api/v2/dataexchange/DataHandler.java
deleted file mode 100644
index 649956af..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/dataexchange/DataHandler.java
+++ /dev/null
@@ -1,332 +0,0 @@
-package org.betterx.bclib.api.v2.dataexchange;
-
-import org.betterx.bclib.BCLib;
-import org.betterx.bclib.api.v2.dataexchange.handler.autosync.Chunker;
-
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.multiplayer.ClientPacketListener;
-import net.minecraft.network.FriendlyByteBuf;
-import net.minecraft.resources.ResourceLocation;
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.level.ServerPlayer;
-import net.minecraft.server.network.ServerGamePacketListenerImpl;
-import net.minecraft.world.entity.player.Player;
-
-import net.fabricmc.api.EnvType;
-import net.fabricmc.api.Environment;
-import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
-import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
-import net.fabricmc.fabric.api.networking.v1.PacketSender;
-import net.fabricmc.fabric.api.networking.v1.PlayerLookup;
-import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
-
-import java.util.Collection;
-import java.util.List;
-
-public abstract class DataHandler extends BaseDataHandler {
- public abstract static class WithoutPayload extends DataHandler {
- protected WithoutPayload(ResourceLocation identifier, boolean originatesOnServer) {
- super(identifier, originatesOnServer);
- }
-
- @Override
- protected boolean prepareData(boolean isClient) {
- return true;
- }
-
- @Override
- protected void serializeData(FriendlyByteBuf buf, boolean isClient) {
- }
-
- @Override
- protected void deserializeIncomingData(FriendlyByteBuf buf, PacketSender responseSender, boolean isClient) {
- }
- }
-
- protected DataHandler(ResourceLocation identifier, boolean originatesOnServer) {
- super(identifier, originatesOnServer);
- }
-
- protected boolean prepareData(boolean isClient) {
- return true;
- }
-
- abstract protected void serializeData(FriendlyByteBuf buf, boolean isClient);
-
- abstract protected void deserializeIncomingData(FriendlyByteBuf buf, PacketSender responseSender, boolean isClient);
-
- abstract protected void runOnGameThread(Minecraft client, MinecraftServer server, boolean isClient);
-
-
- @Environment(EnvType.CLIENT)
- @Override
- void receiveFromServer(
- Minecraft client,
- ClientPacketListener handler,
- FriendlyByteBuf buf,
- PacketSender responseSender
- ) {
- deserializeIncomingData(buf, responseSender, true);
- final Runnable runner = () -> runOnGameThread(client, null, true);
-
- if (isBlocking()) client.executeBlocking(runner);
- else client.execute(runner);
- }
-
- @Override
- void receiveFromClient(
- MinecraftServer server,
- ServerPlayer player,
- ServerGamePacketListenerImpl handler,
- FriendlyByteBuf buf,
- PacketSender responseSender
- ) {
- super.receiveFromClient(server, player, handler, buf, responseSender);
-
- deserializeIncomingData(buf, responseSender, false);
- final Runnable runner = () -> runOnGameThread(null, server, false);
-
- if (isBlocking()) server.executeBlocking(runner);
- else server.execute(runner);
- }
-
- @Override
- void sendToClient(MinecraftServer server) {
- if (prepareData(false)) {
- FriendlyByteBuf buf = PacketByteBufs.create();
- serializeData(buf, false);
-
- _sendToClient(getIdentifier(), server, PlayerLookup.all(server), buf);
- }
- }
-
- @Override
- void sendToClient(MinecraftServer server, ServerPlayer player) {
- if (prepareData(false)) {
- FriendlyByteBuf buf = PacketByteBufs.create();
- serializeData(buf, false);
-
- _sendToClient(getIdentifier(), server, List.of(player), buf);
- }
- }
-
-
- public static void _sendToClient(
- ResourceLocation identifier,
- MinecraftServer server,
- Collection players,
- FriendlyByteBuf buf
- ) {
- if (buf.readableBytes() > Chunker.MAX_PACKET_SIZE) {
- final Chunker.PacketChunkSender sender = new Chunker.PacketChunkSender(buf, identifier);
- sender.sendChunks(players);
- } else {
- for (ServerPlayer player : players) {
- ServerPlayNetworking.send(player, identifier, buf);
- }
- }
- }
-
- @Environment(EnvType.CLIENT)
- @Override
- void sendToServer(Minecraft client) {
- if (prepareData(true)) {
- FriendlyByteBuf buf = PacketByteBufs.create();
- serializeData(buf, true);
- ClientPlayNetworking.send(getIdentifier(), buf);
- }
- }
-
- /**
- * A Message that always originates on the Client
- */
- public abstract static class FromClient extends BaseDataHandler {
- public abstract static class WithoutPayload extends FromClient {
- protected WithoutPayload(ResourceLocation identifier) {
- super(identifier);
- }
-
- @Override
- protected boolean prepareDataOnClient() {
- return true;
- }
-
- @Override
- protected void serializeDataOnClient(FriendlyByteBuf buf) {
- }
-
- @Override
- protected void deserializeIncomingDataOnServer(
- FriendlyByteBuf buf,
- Player player,
- PacketSender responseSender
- ) {
- }
- }
-
- protected FromClient(ResourceLocation identifier) {
- super(identifier, false);
- }
-
- @Environment(EnvType.CLIENT)
- protected boolean prepareDataOnClient() {
- return true;
- }
-
- @Environment(EnvType.CLIENT)
- abstract protected void serializeDataOnClient(FriendlyByteBuf buf);
-
- protected abstract void deserializeIncomingDataOnServer(
- FriendlyByteBuf buf,
- Player player,
- PacketSender responseSender
- );
- protected abstract void runOnServerGameThread(MinecraftServer server, Player player);
-
- @Environment(EnvType.CLIENT)
- @Override
- void receiveFromServer(
- Minecraft client,
- ClientPacketListener handler,
- FriendlyByteBuf buf,
- PacketSender responseSender
- ) {
- BCLib.LOGGER.error("[Internal Error] The message '" + getIdentifier() + "' must originate from the client!");
- }
-
- @Override
- void receiveFromClient(
- MinecraftServer server,
- ServerPlayer player,
- ServerGamePacketListenerImpl handler,
- FriendlyByteBuf buf,
- PacketSender responseSender
- ) {
- super.receiveFromClient(server, player, handler, buf, responseSender);
-
- deserializeIncomingDataOnServer(buf, player, responseSender);
- final Runnable runner = () -> runOnServerGameThread(server, player);
-
- if (isBlocking()) server.executeBlocking(runner);
- else server.execute(runner);
- }
-
- @Override
- void sendToClient(MinecraftServer server) {
- BCLib.LOGGER.error("[Internal Error] The message '" + getIdentifier() + "' must originate from the client!");
- }
-
- @Override
- void sendToClient(MinecraftServer server, ServerPlayer player) {
- BCLib.LOGGER.error("[Internal Error] The message '" + getIdentifier() + "' must originate from the client!");
- }
-
- @Environment(EnvType.CLIENT)
- @Override
- void sendToServer(Minecraft client) {
- if (prepareDataOnClient()) {
- FriendlyByteBuf buf = PacketByteBufs.create();
- serializeDataOnClient(buf);
- ClientPlayNetworking.send(getIdentifier(), buf);
- }
- }
- }
-
- /**
- * A Message that always originates on the Server
- */
- public abstract static class FromServer extends BaseDataHandler {
- public abstract static class WithoutPayload extends FromServer {
- protected WithoutPayload(ResourceLocation identifier) {
- super(identifier);
- }
-
- @Override
- protected boolean prepareDataOnServer() {
- return true;
- }
-
- @Override
- protected void serializeDataOnServer(FriendlyByteBuf buf) {
- }
-
- @Override
- protected void deserializeIncomingDataOnClient(FriendlyByteBuf buf, PacketSender responseSender) {
- }
- }
-
- protected FromServer(ResourceLocation identifier) {
- super(identifier, true);
- }
-
- protected boolean prepareDataOnServer() {
- return true;
- }
-
- abstract protected void serializeDataOnServer(FriendlyByteBuf buf);
-
- @Environment(EnvType.CLIENT)
- abstract protected void deserializeIncomingDataOnClient(FriendlyByteBuf buf, PacketSender responseSender);
-
- @Environment(EnvType.CLIENT)
- abstract protected void runOnClientGameThread(Minecraft client);
-
-
- @Environment(EnvType.CLIENT)
- @Override
- final void receiveFromServer(
- Minecraft client,
- ClientPacketListener handler,
- FriendlyByteBuf buf,
- PacketSender responseSender
- ) {
- deserializeIncomingDataOnClient(buf, responseSender);
- final Runnable runner = () -> runOnClientGameThread(client);
-
- if (isBlocking()) client.executeBlocking(runner);
- else client.execute(runner);
- }
-
- @Override
- final void receiveFromClient(
- MinecraftServer server,
- ServerPlayer player,
- ServerGamePacketListenerImpl handler,
- FriendlyByteBuf buf,
- PacketSender responseSender
- ) {
- super.receiveFromClient(server, player, handler, buf, responseSender);
- BCLib.LOGGER.error("[Internal Error] The message '" + getIdentifier() + "' must originate from the server!");
- }
-
- public void receiveFromMemory(FriendlyByteBuf buf) {
- receiveFromServer(Minecraft.getInstance(), null, buf, null);
- }
-
- @Override
- final void sendToClient(MinecraftServer server) {
- if (prepareDataOnServer()) {
- FriendlyByteBuf buf = PacketByteBufs.create();
- serializeDataOnServer(buf);
-
- _sendToClient(getIdentifier(), server, PlayerLookup.all(server), buf);
- }
- }
-
- @Override
- final void sendToClient(MinecraftServer server, ServerPlayer player) {
- if (prepareDataOnServer()) {
- FriendlyByteBuf buf = PacketByteBufs.create();
- serializeDataOnServer(buf);
-
- _sendToClient(getIdentifier(), server, List.of(player), buf);
- }
- }
-
- @Environment(EnvType.CLIENT)
- @Override
- final void sendToServer(Minecraft client) {
- BCLib.LOGGER.error("[Internal Error] The message '" + getIdentifier() + "' must originate from the server!");
- }
- }
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/dataexchange/DataHandlerDescriptor.java b/src/main/java/org/betterx/bclib/api/v2/dataexchange/DataHandlerDescriptor.java
deleted file mode 100644
index b572bc31..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/dataexchange/DataHandlerDescriptor.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.betterx.bclib.api.v2.dataexchange;
-
-import net.minecraft.resources.ResourceLocation;
-
-import java.util.Objects;
-import java.util.function.Supplier;
-import org.jetbrains.annotations.NotNull;
-
-public class DataHandlerDescriptor {
- public DataHandlerDescriptor(@NotNull ResourceLocation identifier, @NotNull Supplier instancer) {
- this(identifier, instancer, instancer, false, false);
- }
-
- public DataHandlerDescriptor(
- @NotNull ResourceLocation identifier,
- @NotNull Supplier instancer,
- boolean sendOnJoin,
- boolean sendBeforeEnter
- ) {
- this(identifier, instancer, instancer, sendOnJoin, sendBeforeEnter);
- }
-
- public DataHandlerDescriptor(
- @NotNull ResourceLocation identifier,
- @NotNull Supplier receiv_instancer,
- @NotNull Supplier join_instancer,
- boolean sendOnJoin,
- boolean sendBeforeEnter
- ) {
- this.INSTANCE = receiv_instancer;
- this.JOIN_INSTANCE = join_instancer;
- this.IDENTIFIER = identifier;
-
- this.sendOnJoin = sendOnJoin;
- this.sendBeforeEnter = sendBeforeEnter;
- }
-
- public final boolean sendOnJoin;
- public final boolean sendBeforeEnter;
- @NotNull
- public final ResourceLocation IDENTIFIER;
- @NotNull
- public final Supplier INSTANCE;
- @NotNull
- public final Supplier JOIN_INSTANCE;
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o instanceof ResourceLocation) {
- return o.equals(IDENTIFIER);
- }
- if (!(o instanceof DataHandlerDescriptor that)) return false;
- return IDENTIFIER.equals(that.IDENTIFIER);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(IDENTIFIER);
- }
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/dataexchange/FileHash.java b/src/main/java/org/betterx/bclib/api/v2/dataexchange/FileHash.java
deleted file mode 100644
index dcbef098..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/dataexchange/FileHash.java
+++ /dev/null
@@ -1,160 +0,0 @@
-package org.betterx.bclib.api.v2.dataexchange;
-
-import org.betterx.bclib.BCLib;
-
-import net.minecraft.network.FriendlyByteBuf;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Arrays;
-import java.util.Objects;
-import org.jetbrains.annotations.NotNull;
-
-public class FileHash {
- private static final int ERR_DOES_NOT_EXIST = -10;
- private static final int ERR_IO_ERROR = -20;
-
- /**
- * The md5-hash of the file
- */
- @NotNull
- public final byte[] md5;
-
- /**
- * The size (in bytes) of the input.
- */
- public final int size;
-
- /**
- * a value that is directly calculated from defined byte positions.
- */
- public final int value;
-
- FileHash(byte[] md5, int size, int value) {
- Objects.nonNull(md5);
-
- this.md5 = md5;
- this.size = size;
- this.value = value;
- }
-
- static FileHash createForEmpty(int errCode) {
- return new FileHash(new byte[0], 0, errCode);
- }
-
- public boolean noFile() {
- return md5.length == 0;
- }
-
- /**
- * Serializes the Object to a buffer
- *
- * @param buf The buffer to write to
- */
- public void serialize(FriendlyByteBuf buf) {
- buf.writeInt(size);
- buf.writeInt(value);
- buf.writeByteArray(md5);
- }
-
- /**
- * Deserialize a Buffer to a new {@link SyncFileHash}-Object
- *
- * @param buf Thea buffer to read from
- * @return The received String
- */
- public static FileHash deserialize(FriendlyByteBuf buf) {
- final int size = buf.readInt();
- final int value = buf.readInt();
- final byte[] md5 = buf.readByteArray();
-
- return new FileHash(md5, size, value);
- }
-
- /**
- * Convert the md5-hash to a human readable string
- *
- * @return The converted String
- */
- public String getMd5String() {
- return toHexString(md5);
- }
-
- /**
- * Converts a byte-array to a hex-string representation
- *
- * @param bytes The source array
- * @return The resulting string, or an empty String if the input was {@code null}
- */
- public static String toHexString(byte[] bytes) {
- if (bytes == null) return "";
-
- StringBuilder sb = new StringBuilder();
- for (byte b : bytes) {
- sb.append(String.format("%02x", b));
- }
- return sb.toString();
- }
-
- /**
- * Create a new {@link FileHash}.
- *
- * @param file The input file
- * @return A new Instance. You can compare instances using {@link #equals(Object)} to determine if two files are
- * identical. Will return {@code null} when an error occurs or the File does not exist
- */
- public static FileHash create(File file) {
- if (!file.exists()) return createForEmpty(ERR_DOES_NOT_EXIST);
- final Path path = file.toPath();
-
- int size = 0;
- byte[] md5 = new byte[0];
- int value = 0;
-
- try {
- byte[] data = Files.readAllBytes(path);
-
- size = data.length;
-
- value = size > 0 ? (data[size / 3] | (data[size / 2] << 8) | (data[size / 5] << 16)) : -1;
- if (size > 20) value |= data[20] << 24;
-
- MessageDigest md = MessageDigest.getInstance("MD5");
- md.update(data);
- md5 = md.digest();
-
- return new FileHash(md5, size, value);
- } catch (IOException e) {
- BCLib.LOGGER.error("Failed to read file: " + file);
- return null;
- } catch (NoSuchAlgorithmException e) {
- BCLib.LOGGER.error("Unable to build hash for file: " + file);
- }
-
- return createForEmpty(ERR_IO_ERROR);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof FileHash)) return false;
- FileHash fileHash = (FileHash) o;
- return size == fileHash.size && value == fileHash.value && Arrays.equals(md5, fileHash.md5);
- }
-
- @Override
- public int hashCode() {
- int result = Objects.hash(size, value);
- result = 31 * result + Arrays.hashCode(md5);
- return result;
- }
-
- @Override
- public String toString() {
- return String.format("%08x", size) + "-" + String.format("%08x", value) + "-" + getMd5String();
- }
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/dataexchange/SyncFileHash.java b/src/main/java/org/betterx/bclib/api/v2/dataexchange/SyncFileHash.java
deleted file mode 100644
index da416911..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/dataexchange/SyncFileHash.java
+++ /dev/null
@@ -1,113 +0,0 @@
-package org.betterx.bclib.api.v2.dataexchange;
-
-import org.betterx.bclib.api.v2.dataexchange.handler.autosync.AutoSync;
-import org.betterx.bclib.api.v2.dataexchange.handler.autosync.AutoSyncID;
-
-import net.minecraft.network.FriendlyByteBuf;
-
-import java.io.File;
-import java.util.Objects;
-
-/**
- * Calculates a hash based on the contents of a File.
- *
- * A File-Hash contains the md5-sum of the File, as well as its size and byte-values from defined positions
- *
- * You can compare instances using {@link #equals(Object)} to determine if two files are
- * identical.
- */
-public class SyncFileHash extends AutoSyncID {
- public final FileHash hash;
-
- SyncFileHash(String modID, File file, byte[] md5, int size, int value) {
- this(modID, file.getName(), md5, size, value);
- }
-
- SyncFileHash(String modID, String uniqueID, byte[] md5, int size, int value) {
- this(modID, uniqueID, new FileHash(md5, size, value));
- }
-
- SyncFileHash(String modID, File file, FileHash hash) {
- this(modID, file.getName(), hash);
- }
-
- SyncFileHash(String modID, String uniqueID, FileHash hash) {
- super(modID, uniqueID);
- this.hash = hash;
- }
-
-
- final static AutoSync.NeedTransferPredicate NEED_TRANSFER = (clientHash, serverHash, content) -> !clientHash.equals(
- serverHash);
-
- @Override
- public String toString() {
- return super.toString() + ": " + hash.toString();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof SyncFileHash)) return false;
- if (!super.equals(o)) return false;
- SyncFileHash that = (SyncFileHash) o;
- return hash.equals(that.hash);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(super.hashCode(), hash);
- }
-
- /**
- * Serializes the Object to a buffer
- *
- * @param buf The buffer to write to
- */
- public void serialize(FriendlyByteBuf buf) {
- hash.serialize(buf);
- DataHandler.writeString(buf, modID);
- DataHandler.writeString(buf, uniqueID);
- }
-
- /**
- * Deserialize a Buffer to a new {@link SyncFileHash}-Object
- *
- * @param buf Thea buffer to read from
- * @return The received String
- */
- public static SyncFileHash deserialize(FriendlyByteBuf buf) {
- final FileHash hash = FileHash.deserialize(buf);
- final String modID = DataHandler.readString(buf);
- final String uniqueID = DataHandler.readString(buf);
-
- return new SyncFileHash(modID, uniqueID, hash);
- }
-
- /**
- * Create a new {@link SyncFileHash}.
- *
- * Will call {@link #create(String, File, String)} using the name of the File as {@code uniqueID}.
- *
- * @param modID ID of the calling Mod
- * @param file The input file
- * @return A new Instance. You can compare instances using {@link #equals(Object)} to determine if two files are
- * identical. Will return {@code null} when an error occurs or the File does not exist
- */
- public static SyncFileHash create(String modID, File file) {
- return create(modID, file, file.getName());
- }
-
- /**
- * Create a new {@link SyncFileHash}.
- *
- * @param modID ID of the calling Mod
- * @param file The input file
- * @param uniqueID The unique ID that is used for this File (see {@link SyncFileHash#uniqueID} for Details.
- * @return A new Instance. You can compare instances using {@link #equals(Object)} to determine if two files are
- * identical. Will return {@code null} when an error occurs or the File does not exist
- */
- public static SyncFileHash create(String modID, File file, String uniqueID) {
- return new SyncFileHash(modID, uniqueID, FileHash.create(file));
- }
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/DataExchange.java b/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/DataExchange.java
deleted file mode 100644
index 255b994b..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/DataExchange.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package org.betterx.bclib.api.v2.dataexchange.handler;
-
-import org.betterx.bclib.api.v2.dataexchange.*;
-
-import net.minecraft.resources.ResourceLocation;
-
-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 java.util.HashSet;
-import java.util.Set;
-
-abstract public class DataExchange {
-
-
- private static DataExchangeAPI instance;
-
- protected static DataExchangeAPI getInstance() {
- if (instance == null) {
- instance = new DataExchangeAPI();
- }
- return instance;
- }
-
- protected ConnectorServerside server;
- protected ConnectorClientside client;
- protected final Set descriptors;
-
-
- private final boolean didLoadSyncFolder = false;
-
- abstract protected ConnectorClientside clientSupplier(DataExchange api);
-
- abstract protected ConnectorServerside serverSupplier(DataExchange api);
-
- protected DataExchange() {
- descriptors = new HashSet<>();
- }
-
- public Set getDescriptors() {
- return descriptors;
- }
-
- public static DataHandlerDescriptor getDescriptor(ResourceLocation identifier) {
- return getInstance().descriptors.stream().filter(d -> d.equals(identifier)).findFirst().orElse(null);
- }
-
- @Environment(EnvType.CLIENT)
- protected void initClientside() {
- if (client != null) return;
- client = clientSupplier(this);
-
- ClientPlayConnectionEvents.INIT.register(client::onPlayInit);
- ClientPlayConnectionEvents.JOIN.register(client::onPlayReady);
- ClientPlayConnectionEvents.DISCONNECT.register(client::onPlayDisconnect);
- }
-
- protected void initServerSide() {
- if (server != null) return;
- server = serverSupplier(this);
-
- ServerPlayConnectionEvents.INIT.register(server::onPlayInit);
- ServerPlayConnectionEvents.JOIN.register(server::onPlayReady);
- ServerPlayConnectionEvents.DISCONNECT.register(server::onPlayDisconnect);
- }
-
- /**
- * Initializes all datastructures that need to exist in the client component.
- *
- * This is automatically called by BCLib. You can register {@link DataHandler}-Objects before this Method is called
- */
- @Environment(EnvType.CLIENT)
- public static void prepareClientside() {
- DataExchange api = DataExchange.getInstance();
- api.initClientside();
-
- }
-
- /**
- * Initializes all datastructures that need to exist in the server component.
- *
- * This is automatically called by BCLib. You can register {@link DataHandler}-Objects before this Method is called
- */
- public static void prepareServerside() {
- DataExchange api = DataExchange.getInstance();
- api.initServerSide();
- }
-
-
- /**
- * Automatically called before the player enters the world.
- *
- * This is automatically called by BCLib. It will send all {@link DataHandler}-Objects that have {@link DataHandlerDescriptor#sendBeforeEnter} set to*
- * {@code true},
- */
- @Environment(EnvType.CLIENT)
- public static void sendOnEnter() {
- getInstance().descriptors.forEach((desc) -> {
- if (desc.sendBeforeEnter) {
- BaseDataHandler h = desc.JOIN_INSTANCE.get();
- if (!h.getOriginatesOnServer()) {
- getInstance().client.sendToServer(h);
- }
- }
- });
- }
-
-
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/AutoFileSyncEntry.java b/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/AutoFileSyncEntry.java
deleted file mode 100644
index 17a3920f..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/AutoFileSyncEntry.java
+++ /dev/null
@@ -1,262 +0,0 @@
-package org.betterx.bclib.api.v2.dataexchange.handler.autosync;
-
-import org.betterx.bclib.BCLib;
-import org.betterx.bclib.api.v2.dataexchange.DataHandler;
-import org.betterx.bclib.api.v2.dataexchange.SyncFileHash;
-import org.betterx.bclib.util.Pair;
-import org.betterx.bclib.util.Triple;
-import org.betterx.worlds.together.util.ModUtil;
-import org.betterx.worlds.together.util.ModUtil.ModInfo;
-import org.betterx.worlds.together.util.PathUtil;
-
-import net.minecraft.network.FriendlyByteBuf;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-
-class AutoFileSyncEntry extends AutoSyncID {
- static class ForDirectFileRequest extends AutoFileSyncEntry {
- final File relFile;
-
- ForDirectFileRequest(String syncID, File relFile, File absFile) {
- super(AutoSyncID.ForDirectFileRequest.MOD_ID, syncID, absFile, false, (a, b, c) -> false);
- this.relFile = relFile;
- }
-
- @Override
- public int serializeContent(FriendlyByteBuf buf) {
- int res = super.serializeContent(buf);
- DataHandler.writeString(buf, relFile.toString());
-
- return res;
- }
-
- static AutoFileSyncEntry.ForDirectFileRequest finishDeserializeContent(String syncID, FriendlyByteBuf buf) {
- final String relFile = DataHandler.readString(buf);
- SyncFolderDescriptor desc = AutoSync.getSyncFolderDescriptor(syncID);
- if (desc != null) {
- //ensures that the file is not above the base-folder
- if (desc.acceptChildElements(desc.mapAbsolute(relFile))) {
- return new AutoFileSyncEntry.ForDirectFileRequest(
- syncID,
- new File(relFile),
- desc.localFolder.resolve(relFile)
- .normalize()
- .toFile()
- );
- }
- }
- return null;
- }
-
- @Override
- public String toString() {
- return uniqueID + " - " + relFile;
- }
- }
-
- static class ForModFileRequest extends AutoFileSyncEntry {
- public static File getLocalPathForID(String modID, boolean matchLocalVersion) {
- ModInfo mi = ModUtil.getModInfo(modID, matchLocalVersion);
- if (mi != null) {
- return mi.jarPath.toFile();
- }
- return 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 = ModUtil.getModVersion(modID);
- else
- this.version = version;
- }
-
- @Override
- public int serializeContent(FriendlyByteBuf buf) {
- final int res = super.serializeContent(buf);
- buf.writeInt(ModUtil.convertModVersion(version));
- return res;
- }
-
- static AutoFileSyncEntry.ForModFileRequest finishDeserializeContent(String modID, FriendlyByteBuf buf) {
- final String version = ModUtil.convertModVersion(buf.readInt());
- return new AutoFileSyncEntry.ForModFileRequest(modID, false, version);
- }
-
- @Override
- public String toString() {
- return "Mod " + modID + " (v" + version + ")";
- }
- }
-
- public final AutoSync.NeedTransferPredicate needTransfer;
- public final File fileName;
- public final boolean requestContent;
- private SyncFileHash hash;
-
- AutoFileSyncEntry(
- String modID,
- File fileName,
- boolean requestContent,
- AutoSync.NeedTransferPredicate needTransfer
- ) {
- this(modID, fileName.getName(), fileName, requestContent, needTransfer);
- }
-
- AutoFileSyncEntry(
- String modID,
- String uniqueID,
- File fileName,
- boolean requestContent,
- AutoSync.NeedTransferPredicate needTransfer
- ) {
- super(modID, uniqueID);
- this.needTransfer = needTransfer;
- this.fileName = fileName;
- this.requestContent = requestContent;
- }
-
-
- public SyncFileHash getFileHash() {
- if (hash == null) {
- hash = SyncFileHash.create(modID, fileName, uniqueID);
- }
- return hash;
- }
-
- public byte[] getContent() {
- if (!fileName.exists()) return new byte[0];
- final Path path = fileName.toPath();
-
- try {
- return Files.readAllBytes(path);
- } catch (IOException e) {
-
- }
- return new byte[0];
- }
-
- public int serializeContent(FriendlyByteBuf buf) {
- DataHandler.writeString(buf, modID);
- DataHandler.writeString(buf, uniqueID);
- return serializeFileContent(buf);
- }
-
- public static Triple deserializeContent(FriendlyByteBuf buf) {
- final String modID = DataHandler.readString(buf);
- final String uniqueID = DataHandler.readString(buf);
- byte[] data = deserializeFileContent(buf);
-
- AutoFileSyncEntry entry;
- if (AutoSyncID.ForDirectFileRequest.MOD_ID.equals(modID)) {
- entry = AutoFileSyncEntry.ForDirectFileRequest.finishDeserializeContent(uniqueID, buf);
- } else if (AutoSyncID.ForModFileRequest.UNIQUE_ID.equals(uniqueID)) {
- entry = AutoFileSyncEntry.ForModFileRequest.finishDeserializeContent(modID, buf);
- } else {
- entry = AutoFileSyncEntry.findMatching(modID, uniqueID);
- }
- return new Triple<>(entry, data, new AutoSyncID(modID, uniqueID));
- }
-
-
- public void serialize(FriendlyByteBuf buf) {
- getFileHash().serialize(buf);
- buf.writeBoolean(requestContent);
-
- if (requestContent) {
- serializeFileContent(buf);
- }
- }
-
- public static AutoSync.AutoSyncTriple deserializeAndMatch(FriendlyByteBuf buf) {
- Pair e = deserialize(buf);
- AutoFileSyncEntry match = findMatching(e.first);
- return new AutoSync.AutoSyncTriple(e.first, e.second, match);
- }
-
- public static Pair deserialize(FriendlyByteBuf buf) {
- SyncFileHash hash = SyncFileHash.deserialize(buf);
- boolean withContent = buf.readBoolean();
- byte[] data = null;
- if (withContent) {
- data = deserializeFileContent(buf);
- }
-
- return new Pair(hash, data);
- }
-
- private int serializeFileContent(FriendlyByteBuf buf) {
- if (!org.betterx.worlds.together.util.PathUtil.isChildOf(
- org.betterx.worlds.together.util.PathUtil.GAME_FOLDER,
- fileName.toPath()
- )) {
- BCLib.LOGGER.error(fileName + " is not within game folder " + PathUtil.GAME_FOLDER + ". Pretending it does not exist.");
- buf.writeInt(0);
- return 0;
- }
-
- byte[] content = getContent();
- buf.writeInt(content.length);
- buf.writeByteArray(content);
- return content.length;
- }
-
- private static byte[] deserializeFileContent(FriendlyByteBuf buf) {
- byte[] data;
- int size = buf.readInt();
- data = buf.readByteArray(size);
- return data;
- }
-
-
- public static AutoFileSyncEntry findMatching(SyncFileHash hash) {
- return findMatching(hash.modID, hash.uniqueID);
- }
-
- public static AutoFileSyncEntry findMatching(AutoSyncID aid) {
- if (aid instanceof AutoSyncID.ForDirectFileRequest) {
- AutoSyncID.ForDirectFileRequest freq = (AutoSyncID.ForDirectFileRequest) aid;
- SyncFolderDescriptor desc = AutoSync.getSyncFolderDescriptor(freq.uniqueID);
- if (desc != null) {
- SyncFolderDescriptor.SubFile subFile = desc.getLocalSubFile(freq.relFile.toString());
- if (subFile != null) {
- final File absPath = desc.localFolder.resolve(subFile.relPath)
- .normalize()
- .toFile();
- return new AutoFileSyncEntry.ForDirectFileRequest(
- freq.uniqueID,
- new File(subFile.relPath),
- absPath
- );
- }
- }
- 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);
- }
-
- public static AutoFileSyncEntry findMatching(String modID, String uniqueID) {
- return AutoSync.getAutoSyncFiles()
- .stream()
- .filter(asf -> asf.modID.equals(modID) && asf.uniqueID.equals(uniqueID))
- .findFirst()
- .orElse(null);
- }
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/AutoSync.java b/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/AutoSync.java
deleted file mode 100644
index 64a3811d..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/AutoSync.java
+++ /dev/null
@@ -1,207 +0,0 @@
-package org.betterx.bclib.api.v2.dataexchange.handler.autosync;
-
-import org.betterx.bclib.BCLib;
-import org.betterx.bclib.api.v2.dataexchange.DataExchangeAPI;
-import org.betterx.bclib.api.v2.dataexchange.SyncFileHash;
-import org.betterx.bclib.config.Configs;
-import org.betterx.bclib.config.ServerConfig;
-import org.betterx.worlds.together.util.PathUtil;
-
-import net.fabricmc.loader.api.FabricLoader;
-
-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 SYNC_CATEGORY = "auto_sync";
- public final static SyncFolderDescriptor SYNC_FOLDER = new SyncFolderDescriptor(
- "BCLIB-SYNC",
- FabricLoader.getInstance()
- .getGameDir()
- .resolve("bclib-sync")
- .normalize()
- .toAbsolutePath(),
- true
- );
-
- @FunctionalInterface
- public interface NeedTransferPredicate {
- boolean test(SyncFileHash clientHash, SyncFileHash serverHash, FileContentWrapper content);
- }
-
- 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> 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.
- *
- * 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 callback) {
- onWriteCallbacks.add(callback);
- }
-
- private static final List autoSyncFiles = new ArrayList<>(4);
-
- public static List 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.
- *
- * 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
- ) {
- if (!PathUtil.isChildOf(PathUtil.GAME_FOLDER, fileName.toPath())) {
- BCLib.LOGGER.error(fileName + " is outside of Game Folder " + PathUtil.GAME_FOLDER);
- } else {
- 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.
- *
- * 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
- ) {
- if (!PathUtil.isChildOf(PathUtil.GAME_FOLDER, fileName.toPath())) {
- BCLib.LOGGER.error(fileName + " is outside of Game Folder " + PathUtil.GAME_FOLDER);
- } else {
- 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.
- *
- * 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 syncFolderDescriptions = Arrays.asList(SYNC_FOLDER);
-
- private List syncFolderContent;
-
- protected List getSyncFolderContent() {
- if (syncFolderContent == null) {
- return new ArrayList<>(0);
- }
- return syncFolderContent;
- }
-
- private static boolean didRegisterAdditionalMods = false;
-
- //we call this from HelloClient on the Server to prepare transfer
- protected static void loadSyncFolder() {
- if (Configs.SERVER_CONFIG.isOfferingFiles()) {
- syncFolderDescriptions.forEach(desc -> desc.loadCache());
- }
-
- if (!didRegisterAdditionalMods && Configs.SERVER_CONFIG.isOfferingMods()) {
- didRegisterAdditionalMods = true;
- List modIDs = Configs.SERVER_CONFIG.get(ServerConfig.ADDITIONAL_MODS);
- if (modIDs != null) {
- modIDs.stream().forEach(modID -> DataExchangeAPI.registerModDependency(modID));
- }
- }
-
- }
-
- 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.");
- }
- }
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/AutoSyncID.java b/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/AutoSyncID.java
deleted file mode 100644
index b8ace9bc..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/AutoSyncID.java
+++ /dev/null
@@ -1,144 +0,0 @@
-package org.betterx.bclib.api.v2.dataexchange.handler.autosync;
-
-import org.betterx.bclib.api.v2.dataexchange.DataHandler;
-import org.betterx.bclib.config.Config;
-import org.betterx.worlds.together.util.ModUtil;
-
-import net.minecraft.network.FriendlyByteBuf;
-
-import java.io.File;
-import java.util.Objects;
-import org.jetbrains.annotations.NotNull;
-
-public class AutoSyncID {
- static class WithContentOverride extends AutoSyncID {
- final FileContentWrapper contentWrapper;
- final File localFile;
-
- WithContentOverride(String modID, String uniqueID, FileContentWrapper contentWrapper, File localFile) {
- super(modID, uniqueID);
- this.contentWrapper = contentWrapper;
- this.localFile = localFile;
- }
-
- @Override
- public String toString() {
- return super.toString() + " (Content override)";
- }
- }
-
- static class ForDirectFileRequest extends AutoSyncID {
- public final static String MOD_ID = "bclib::FILE";
- final File relFile;
-
- ForDirectFileRequest(String syncID, File relFile) {
- super(ForDirectFileRequest.MOD_ID, syncID);
- this.relFile = relFile;
- }
-
- @Override
- void serializeData(FriendlyByteBuf buf) {
- super.serializeData(buf);
- DataHandler.writeString(buf, relFile.toString());
- }
-
- static ForDirectFileRequest finishDeserialize(String modID, String uniqueID, FriendlyByteBuf buf) {
- 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 {
- public final static String UNIQUE_ID = "bclib::MOD";
- private final String version;
-
- ForModFileRequest(String modID, String version) {
- super(modID, ForModFileRequest.UNIQUE_ID);
- this.version = version;
- }
-
- @Override
- void serializeData(FriendlyByteBuf buf) {
- super.serializeData(buf);
- buf.writeInt(ModUtil.convertModVersion(version));
- }
-
- static ForModFileRequest finishDeserialize(String modID, String uniqueID, FriendlyByteBuf buf) {
- final String version = ModUtil.convertModVersion(buf.readInt());
- return new ForModFileRequest(modID, version);
- }
-
- @Override
- public String toString() {
- return super.modID + " (v" + this.version + ")";
- }
- }
-
- /**
- * A Unique ID for the referenced File.
- *
- * Files with the same {@link #modID} need to have a unique IDs. Normally the filename from FileHash(String, File, byte[], int, int)
- * is used to generated that ID, but you can directly specify one using FileHash(String, String, byte[], int, int).
- */
- @NotNull
- public final String uniqueID;
-
- /**
- * The ID of the Mod that is registering the File
- */
- @NotNull
- public final String modID;
-
- public AutoSyncID(String modID, String uniqueID) {
- Objects.nonNull(modID);
- Objects.nonNull(uniqueID);
-
- this.modID = modID;
- this.uniqueID = uniqueID;
- }
-
- @Override
- public String toString() {
- return modID + "." + uniqueID;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof AutoSyncID)) return false;
- AutoSyncID that = (AutoSyncID) o;
- return uniqueID.equals(that.uniqueID) && modID.equals(that.modID);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(uniqueID, modID);
- }
-
- void serializeData(FriendlyByteBuf buf) {
- DataHandler.writeString(buf, modID);
- DataHandler.writeString(buf, uniqueID);
- }
-
- static AutoSyncID deserializeData(FriendlyByteBuf buf) {
- String modID = DataHandler.readString(buf);
- String uID = DataHandler.readString(buf);
-
- if (ForDirectFileRequest.MOD_ID.equals(modID)) {
- return ForDirectFileRequest.finishDeserialize(modID, uID, buf);
- } else if (ForModFileRequest.UNIQUE_ID.equals(uID)) {
- return ForModFileRequest.finishDeserialize(modID, uID, buf);
- } else {
- return new AutoSyncID(modID, uID);
- }
- }
-
- public boolean isConfigFile() {
- return this.uniqueID.startsWith(Config.CONFIG_SYNC_PREFIX);
- }
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/Chunker.java b/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/Chunker.java
deleted file mode 100644
index d9eab98e..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/Chunker.java
+++ /dev/null
@@ -1,280 +0,0 @@
-package org.betterx.bclib.api.v2.dataexchange.handler.autosync;
-
-import org.betterx.bclib.BCLib;
-import org.betterx.bclib.api.v2.dataexchange.BaseDataHandler;
-import org.betterx.bclib.api.v2.dataexchange.DataHandler;
-import org.betterx.bclib.api.v2.dataexchange.DataHandlerDescriptor;
-import org.betterx.bclib.api.v2.dataexchange.handler.DataExchange;
-
-import net.minecraft.client.Minecraft;
-import net.minecraft.network.FriendlyByteBuf;
-import net.minecraft.resources.ResourceLocation;
-import net.minecraft.server.level.ServerPlayer;
-import net.minecraft.util.ProgressListener;
-
-import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
-import net.fabricmc.fabric.api.networking.v1.PacketSender;
-import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
-
-import java.util.*;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Used to seperate large data transfers into multiple smaller messages.
- *
- * {@link DataHandler} will automatically convert larger messages into Chunks on the Server
- * and assemble the original message from those chunks on the client.
- */
-public class Chunker extends DataHandler.FromServer {
-
- /**
- * Responsible for assembling the original ByteBuffer created by {@link PacketChunkSender} on the
- * receiving end. Automatically created from the header {@link Chunker}-Message (where the serialNo==-1)
- */
- static class PacketChunkReceiver {
- @NotNull
- public final UUID uuid;
- public final int chunkCount;
- @NotNull
- private final FriendlyByteBuf networkedBuf;
- @Nullable
- private final DataHandlerDescriptor descriptor;
-
- private static final List active = new ArrayList<>(1);
-
- private static PacketChunkReceiver newReceiver(@NotNull UUID uuid, int chunkCount, ResourceLocation origin) {
- DataHandlerDescriptor desc = DataExchange.getDescriptor(origin);
- final PacketChunkReceiver r = new PacketChunkReceiver(uuid, chunkCount, desc);
- active.add(r);
- return r;
- }
-
- private static PacketChunkReceiver getOrCreate(@NotNull UUID uuid, int chunkCount, ResourceLocation origin) {
- return active.stream()
- .filter(r -> r.uuid.equals(uuid))
- .findFirst()
- .orElse(newReceiver(uuid, chunkCount, origin));
- }
-
- public static PacketChunkReceiver get(@NotNull UUID uuid) {
- return active.stream().filter(r -> r.uuid.equals(uuid)).findFirst().orElse(null);
- }
-
- private PacketChunkReceiver(@NotNull UUID uuid, int chunkCount, @Nullable DataHandlerDescriptor descriptor) {
- this.uuid = uuid;
- this.chunkCount = chunkCount;
- networkedBuf = PacketByteBufs.create();
- this.descriptor = descriptor;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof PacketChunkReceiver)) return false;
- PacketChunkReceiver that = (PacketChunkReceiver) o;
- return uuid.equals(that.uuid);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(uuid);
- }
-
- public boolean testFinished() {
- ProgressListener listener = ChunkerProgress.getProgressListener();
- if (listener != null) {
- listener.progressStagePercentage((100 * receivedCount) / chunkCount);
- }
- if (incomingBuffer == null) {
- return true;
- }
- if (lastReadSerial >= chunkCount - 1) {
- onFinish();
- return true;
- }
- return false;
- }
-
- private void addBuffer(FriendlyByteBuf input) {
- final int size = input.readableBytes();
- final int cap = networkedBuf.capacity() - networkedBuf.writerIndex();
-
- if (cap < size) {
- networkedBuf.capacity(networkedBuf.writerIndex() + size);
- }
- input.readBytes(networkedBuf, size);
- input.clear();
- }
-
- protected void onFinish() {
- incomingBuffer.clear();
- incomingBuffer = null;
-
- final BaseDataHandler baseHandler = descriptor.INSTANCE.get();
- if (baseHandler instanceof DataHandler.FromServer handler) {
- handler.receiveFromMemory(networkedBuf);
- }
- }
-
- Map incomingBuffer = new HashMap<>();
- int lastReadSerial = -1;
- int receivedCount = 0;
-
- public void processReceived(FriendlyByteBuf buf, int serialNo, int size) {
- receivedCount++;
-
- if (lastReadSerial == serialNo - 1) {
- addBuffer(buf);
- lastReadSerial = serialNo;
- } else {
- //not sure if order is guaranteed by the underlying system!
- boolean haveAll = true;
- for (int nr = lastReadSerial + 1; nr < serialNo - 1; nr++) {
- if (incomingBuffer.get(nr) == null) {
- haveAll = false;
- break;
- }
- }
-
- if (haveAll) {
- for (int nr = lastReadSerial + 1; nr < serialNo - 1; nr++) {
- addBuffer(incomingBuffer.get(nr));
- incomingBuffer.put(nr, null);
- }
- addBuffer(buf);
- lastReadSerial = serialNo;
- } else {
- incomingBuffer.put(serialNo, buf);
- }
- }
- }
- }
-
- /**
- * Responsible for splitting an outgoing ByteBuffer into several smaller Chunks and
- * send them as seperate messages to the {@link Chunker}-Channel
- */
- public static class PacketChunkSender {
- private final FriendlyByteBuf networkedBuf;
- public final UUID uuid;
- public final int chunkCount;
- public final int size;
- public final ResourceLocation origin;
-
- public PacketChunkSender(FriendlyByteBuf buf, ResourceLocation origin) {
- networkedBuf = buf;
-
- size = buf.readableBytes();
- chunkCount = (int) Math.ceil((double) size / MAX_PAYLOAD_SIZE);
- uuid = UUID.randomUUID();
- this.origin = origin;
- }
-
- public void sendChunks(Collection players) {
- BCLib.LOGGER.info("Sending Request in " + chunkCount + " Packet-Chunks");
- for (int i = -1; i < chunkCount; i++) {
- Chunker c = new Chunker(i, uuid, networkedBuf, chunkCount, origin);
- FriendlyByteBuf buf = PacketByteBufs.create();
- c.serializeDataOnServer(buf);
-
- for (ServerPlayer player : players) {
- ServerPlayNetworking.send(player, DESCRIPTOR.IDENTIFIER, buf);
- }
- }
- }
- }
-
- //header = version + UUID + serialNo + size, see serializeDataOnServer
- private static final int HEADER_SIZE = 1 + 16 + 4 + 4;
-
- public static final int MAX_PACKET_SIZE = 1024 * 1024;
- private static final int MAX_PAYLOAD_SIZE = MAX_PACKET_SIZE - HEADER_SIZE;
-
- public static final DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(
- new ResourceLocation(
- BCLib.MOD_ID,
- "chunker"
- ),
- Chunker::new,
- false,
- false
- );
-
- private int serialNo;
- private UUID uuid;
- private int chunkCount;
- private FriendlyByteBuf networkedBuf;
- private ResourceLocation origin;
-
- protected Chunker(int serialNo, UUID uuid, FriendlyByteBuf networkedBuf, int chunkCount, ResourceLocation origin) {
- super(DESCRIPTOR.IDENTIFIER);
- this.serialNo = serialNo;
- this.uuid = uuid;
- this.networkedBuf = networkedBuf;
- this.chunkCount = chunkCount;
- this.origin = origin;
- }
-
- protected Chunker() {
- super(DESCRIPTOR.IDENTIFIER);
- }
-
-
- @Override
- protected void serializeDataOnServer(FriendlyByteBuf buf) {
- //Sending Header. Make sure to change HEADER_SIZE if you change this!
- buf.writeByte(0);
- buf.writeLong(uuid.getMostSignificantBits());
- buf.writeLong(uuid.getLeastSignificantBits());
- buf.writeInt(serialNo);
-
- //sending Payload
- if (serialNo == -1) {
- //this is our header-Chunk that transports status information
- buf.writeInt(chunkCount);
- writeString(buf, origin.getNamespace());
- writeString(buf, origin.getPath());
- } else {
- //this is an actual payload chunk
- buf.capacity(MAX_PACKET_SIZE);
- final int size = Math.min(MAX_PAYLOAD_SIZE, networkedBuf.readableBytes());
- buf.writeInt(size);
- networkedBuf.readBytes(buf, size);
- }
- }
-
- private PacketChunkReceiver receiver;
-
- @Override
- protected void deserializeIncomingDataOnClient(FriendlyByteBuf buf, PacketSender responseSender) {
- final int version = buf.readByte();
- uuid = new UUID(buf.readLong(), buf.readLong());
- serialNo = buf.readInt();
-
- if (serialNo == -1) {
- chunkCount = buf.readInt();
- final String namespace = readString(buf);
- final String path = readString(buf);
- ResourceLocation ident = new ResourceLocation(namespace, path);
- BCLib.LOGGER.info("Receiving " + chunkCount + " + Packet-Chunks for " + ident);
-
- receiver = PacketChunkReceiver.getOrCreate(uuid, chunkCount, ident);
- } else {
- receiver = PacketChunkReceiver.get(uuid);
- if (receiver != null) {
- final int size = buf.readInt();
- receiver.processReceived(buf, serialNo, size);
- } else {
- BCLib.LOGGER.error("Unknown Packet-Chunk Transfer for " + uuid);
- }
- }
- }
-
- @Override
- protected void runOnClientGameThread(Minecraft client) {
- if (receiver != null) {
- receiver.testFinished();
- }
- }
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/ChunkerProgress.java b/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/ChunkerProgress.java
deleted file mode 100644
index ae82fc38..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/ChunkerProgress.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package org.betterx.bclib.api.v2.dataexchange.handler.autosync;
-
-import org.betterx.bclib.client.gui.screens.ProgressScreen;
-
-import net.minecraft.util.ProgressListener;
-
-import net.fabricmc.api.EnvType;
-import net.fabricmc.api.Environment;
-
-@Environment(EnvType.CLIENT)
-public class ChunkerProgress {
- private static ProgressScreen progressScreen;
-
- @Environment(EnvType.CLIENT)
- public static void setProgressScreen(ProgressScreen scr) {
- progressScreen = scr;
- }
-
- @Environment(EnvType.CLIENT)
- public static ProgressScreen getProgressScreen() {
- return progressScreen;
- }
-
- @Environment(EnvType.CLIENT)
- public static ProgressListener getProgressListener() {
- return progressScreen;
- }
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/FileContentWrapper.java b/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/FileContentWrapper.java
deleted file mode 100644
index 669fc955..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/FileContentWrapper.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package org.betterx.bclib.api.v2.dataexchange.handler.autosync;
-
-import org.betterx.bclib.BCLib;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-public class FileContentWrapper {
- private byte[] rawContent;
- private ByteArrayOutputStream outputStream;
-
- FileContentWrapper(byte[] content) {
- this.rawContent = content;
- this.outputStream = null;
- }
-
- public byte[] getOriginalContent() {
- return rawContent;
- }
-
- public byte[] getRawContent() {
- if (outputStream != null) {
- return outputStream.toByteArray();
- }
- return rawContent;
- }
-
- private void invalidateOutputStream() {
- if (this.outputStream != null) {
- try {
- this.outputStream.close();
- } catch (IOException e) {
- BCLib.LOGGER.debug(e);
- }
- }
- this.outputStream = null;
- }
-
- public void setRawContent(byte[] rawContent) {
- this.rawContent = rawContent;
- invalidateOutputStream();
- }
-
- public void syncWithOutputStream() {
- if (outputStream != null) {
- try {
- outputStream.flush();
- } catch (IOException e) {
- BCLib.LOGGER.error(e.getMessage());
- e.printStackTrace();
- }
- setRawContent(getRawContent());
- invalidateOutputStream();
- }
- }
-
- public ByteArrayInputStream getInputStream() {
- if (rawContent == null) return new ByteArrayInputStream(new byte[0]);
- return new ByteArrayInputStream(rawContent);
- }
-
- public ByteArrayOutputStream getOrCreateOutputStream() {
- if (this.outputStream == null) {
- return this.getEmptyOutputStream();
- }
- return this.outputStream;
- }
-
- public ByteArrayOutputStream getEmptyOutputStream() {
- invalidateOutputStream();
- this.outputStream = new ByteArrayOutputStream(this.rawContent.length);
- return this.outputStream;
- }
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/HelloClient.java b/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/HelloClient.java
deleted file mode 100644
index ead95a39..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/HelloClient.java
+++ /dev/null
@@ -1,544 +0,0 @@
-package org.betterx.bclib.api.v2.dataexchange.handler.autosync;
-
-import org.betterx.bclib.BCLib;
-import org.betterx.bclib.api.v2.dataexchange.DataExchangeAPI;
-import org.betterx.bclib.api.v2.dataexchange.DataHandler;
-import org.betterx.bclib.api.v2.dataexchange.DataHandlerDescriptor;
-import org.betterx.bclib.client.gui.screens.ModListScreen;
-import org.betterx.bclib.client.gui.screens.ProgressScreen;
-import org.betterx.bclib.client.gui.screens.SyncFilesScreen;
-import org.betterx.bclib.client.gui.screens.WarnBCLibVersionMismatch;
-import org.betterx.bclib.config.Configs;
-import org.betterx.bclib.config.ServerConfig;
-import org.betterx.worlds.together.util.ModUtil;
-import org.betterx.worlds.together.util.ModUtil.ModInfo;
-import org.betterx.worlds.together.util.PathUtil;
-
-import net.minecraft.client.Minecraft;
-import net.minecraft.network.FriendlyByteBuf;
-import net.minecraft.network.chat.CommonComponents;
-import net.minecraft.network.chat.Component;
-import net.minecraft.resources.ResourceLocation;
-
-import net.fabricmc.api.EnvType;
-import net.fabricmc.api.Environment;
-import net.fabricmc.fabric.api.networking.v1.PacketSender;
-import net.fabricmc.loader.api.metadata.ModEnvironment;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.util.*;
-import java.util.Map.Entry;
-import java.util.stream.Collectors;
-
-/**
- * Sent from the Server to the Client.
- *
- * For Details refer to {@link HelloServer}
- */
-public class HelloClient extends DataHandler.FromServer {
- public record OfferedModInfo(String version, int size, boolean canDownload) {
- }
-
- public interface IServerModMap extends Map {
- }
-
- public static class ServerModMap extends HashMap implements IServerModMap {
- }
-
- public static final DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(
- new ResourceLocation(
- BCLib.MOD_ID,
- "hello_client"
- ),
- HelloClient::new,
- false,
- false
- );
-
- public HelloClient() {
- super(DESCRIPTOR.IDENTIFIER);
- }
-
- static String getBCLibVersion() {
- return ModUtil.getModVersion(BCLib.MOD_ID);
- }
-
- @Override
- protected boolean prepareDataOnServer() {
- if (!Configs.SERVER_CONFIG.isAllowingAutoSync()) {
- BCLib.LOGGER.info("Auto-Sync was disabled on the server.");
- return false;
- }
-
- AutoSync.loadSyncFolder();
- return true;
- }
-
- @Override
- protected void serializeDataOnServer(FriendlyByteBuf buf) {
- final String vbclib = getBCLibVersion();
- BCLib.LOGGER.info("Sending Hello to Client. (server=" + vbclib + ")");
-
- //write BCLibVersion (=protocol version)
- buf.writeInt(ModUtil.convertModVersion(vbclib));
-
- if (Configs.SERVER_CONFIG.isOfferingMods() || Configs.SERVER_CONFIG.isOfferingInfosForMods()) {
- List mods = DataExchangeAPI.registeredMods();
- final List inmods = mods;
- if (Configs.SERVER_CONFIG.isOfferingAllMods() || Configs.SERVER_CONFIG.isOfferingInfosForMods()) {
- mods = new ArrayList<>(inmods.size());
- mods.addAll(inmods);
- mods.addAll(ModUtil
- .getMods()
- .entrySet()
- .stream()
- .filter(entry -> entry.getValue().metadata.getEnvironment() != ModEnvironment.SERVER && !inmods.contains(
- entry.getKey()))
- .map(entry -> entry.getKey())
- .collect(Collectors.toList())
- );
- }
-
- mods = mods
- .stream()
- .filter(entry -> !Configs.SERVER_CONFIG.get(ServerConfig.EXCLUDED_MODS).contains(entry))
- .collect(Collectors.toList());
-
- //write Plugin Versions
- buf.writeInt(mods.size());
- for (String modID : mods) {
- final String ver = ModUtil.getModVersion(modID);
- int size = 0;
-
- final ModInfo mi = ModUtil.getModInfo(modID);
- 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(ModUtil.convertModVersion(ver));
- buf.writeInt(size);
- final boolean canDownload = size > 0 && Configs.SERVER_CONFIG.isOfferingMods() && (Configs.SERVER_CONFIG.isOfferingAllMods() || inmods.contains(
- modID));
- buf.writeBoolean(canDownload);
-
- if (Configs.MAIN_CONFIG.verboseLogging())
- BCLib.LOGGER.info(" - Listing Mod " + modID + " v" + ver + " (size: " + PathUtil.humanReadableFileSize(
- size) + ", download=" + canDownload + ")");
- }
- } else {
- BCLib.LOGGER.info("Server will not list Mods.");
- buf.writeInt(0);
- }
-
- if (Configs.SERVER_CONFIG.isOfferingFiles() || Configs.SERVER_CONFIG.isOfferingConfigs()) {
- //do only include files that exist on the server
- final List existingAutoSyncFiles = AutoSync.getAutoSyncFiles()
- .stream()
- .filter(e -> e.fileName.exists())
- .filter(e -> (e.isConfigFile() && Configs.SERVER_CONFIG.isOfferingConfigs()) || (e instanceof AutoFileSyncEntry.ForDirectFileRequest && Configs.SERVER_CONFIG.isOfferingFiles()))
- .collect(Collectors.toList());
-
- //send config Data
- buf.writeInt(existingAutoSyncFiles.size());
- for (AutoFileSyncEntry entry : existingAutoSyncFiles) {
- entry.serialize(buf);
- if (Configs.MAIN_CONFIG.verboseLogging())
- BCLib.LOGGER.info(" - Offering " + (entry.isConfigFile() ? "Config " : "File ") + entry);
- }
- } else {
- BCLib.LOGGER.info("Server will neither offer Files nor Configs.");
- buf.writeInt(0);
- }
-
- if (Configs.SERVER_CONFIG.isOfferingFiles()) {
- buf.writeInt(AutoSync.syncFolderDescriptions.size());
- AutoSync.syncFolderDescriptions.forEach(desc -> {
- if (Configs.MAIN_CONFIG.verboseLogging())
- BCLib.LOGGER.info(" - Offering Folder " + desc.localFolder + " (allowDelete=" + desc.removeAdditionalFiles + ")");
- desc.serialize(buf);
- });
- } else {
- BCLib.LOGGER.info("Server will not offer Sync Folders.");
- buf.writeInt(0);
- }
-
- buf.writeBoolean(Configs.SERVER_CONFIG.isOfferingInfosForMods());
- }
-
- String bclibVersion = "0.0.0";
-
-
- IServerModMap modVersion = new ServerModMap();
- List autoSyncedFiles = null;
- List autoSynFolders = null;
- boolean serverPublishedModInfo = false;
-
- @Environment(EnvType.CLIENT)
- @Override
- protected void deserializeIncomingDataOnClient(FriendlyByteBuf buf, PacketSender responseSender) {
- //read BCLibVersion (=protocol version)
- bclibVersion = ModUtil.convertModVersion(buf.readInt());
-
- //read Plugin Versions
- modVersion = new ServerModMap();
- int count = buf.readInt();
- for (int i = 0; i < count; i++) {
- final String id = readString(buf);
- final String version = ModUtil.convertModVersion(buf.readInt());
- final int size;
- final boolean canDownload;
- //since v0.4.1 we also send the size of the mod-File
- size = buf.readInt();
- canDownload = buf.readBoolean();
- modVersion.put(id, new OfferedModInfo(version, size, canDownload));
- }
-
- //read config Data
- count = buf.readInt();
- autoSyncedFiles = new ArrayList<>(count);
- for (int i = 0; i < count; i++) {
- //System.out.println("Deserializing ");
- AutoSync.AutoSyncTriple t = AutoFileSyncEntry.deserializeAndMatch(buf);
- autoSyncedFiles.add(t);
- //System.out.println(t.first);
- }
-
-
- autoSynFolders = new ArrayList<>(1);
- //since v0.4.1 we also send the sync folders
- final int folderCount = buf.readInt();
- for (int i = 0; i < folderCount; i++) {
- SyncFolderDescriptor desc = SyncFolderDescriptor.deserialize(buf);
- autoSynFolders.add(desc);
- }
-
- serverPublishedModInfo = buf.readBoolean();
- }
-
- @Environment(EnvType.CLIENT)
- private void processAutoSyncFolder(
- final List filesToRequest,
- final List filesToRemove
- ) {
- if (!Configs.CLIENT_CONFIG.isAcceptingFiles()) {
- return;
- }
-
- if (autoSynFolders.size() > 0) {
- if (Configs.MAIN_CONFIG.verboseLogging())
- BCLib.LOGGER.info("Folders offered by Server:");
- }
-
- 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 = AutoSync.getSyncFolderDescriptor(desc.folderID);
- if (localDescriptor != null) {
- if (Configs.MAIN_CONFIG.verboseLogging())
- BCLib.LOGGER.info(" - " + desc.folderID + " (" + desc.localFolder + ", allowRemove=" + desc.removeAdditionalFiles + ")");
- localDescriptor.invalidateCache();
-
- desc.relativeFilesStream()
- .filter(desc::discardChildElements)
- .forEach(subFile -> {
- if (Configs.MAIN_CONFIG.verboseLogging())
- BCLib.LOGGER.warning(" * " + subFile.relPath + " (REJECTED)");
- });
-
-
- if (desc.removeAdditionalFiles) {
- List additionalFiles = localDescriptor.relativeFilesStream()
- .filter(subFile -> !desc.hasRelativeFile(
- subFile))
- .map(desc::mapAbsolute)
- .filter(desc::acceptChildElements)
- .map(absPath -> new AutoSyncID.ForDirectFileRequest(
- desc.folderID,
- absPath.toFile()
- ))
- .collect(Collectors.toList());
-
- if (Configs.MAIN_CONFIG.verboseLogging())
- additionalFiles.forEach(aid -> BCLib.LOGGER.info(" * " + desc.localFolder.relativize(aid.relFile.toPath()) + " (missing on server)"));
- filesToRemove.addAll(additionalFiles);
- }
-
- desc.relativeFilesStream()
- .filter(desc::acceptChildElements)
- .forEach(subFile -> {
- SyncFolderDescriptor.SubFile localSubFile = localDescriptor.getLocalSubFile(subFile.relPath);
- if (localSubFile != null) {
- //the file exists locally, check if the hashes match
- if (!localSubFile.hash.equals(subFile.hash)) {
- if (Configs.MAIN_CONFIG.verboseLogging())
- BCLib.LOGGER.info(" * " + subFile.relPath + " (changed)");
- filesToRequest.add(new AutoSyncID.ForDirectFileRequest(
- desc.folderID,
- new File(subFile.relPath)
- ));
- } else {
- if (Configs.MAIN_CONFIG.verboseLogging())
- BCLib.LOGGER.info(" * " + subFile.relPath);
- }
- } else {
- //the file is missing locally
- if (Configs.MAIN_CONFIG.verboseLogging())
- BCLib.LOGGER.info(" * " + subFile.relPath + " (missing on client)");
- filesToRequest.add(new AutoSyncID.ForDirectFileRequest(
- desc.folderID,
- new File(subFile.relPath)
- ));
- }
- });
-
- //free some memory
- localDescriptor.invalidateCache();
- } else {
- if (Configs.MAIN_CONFIG.verboseLogging())
- BCLib.LOGGER.info(" - " + desc.folderID + " (Failed to find)");
- }
- });
- }
-
- @Environment(EnvType.CLIENT)
- private void processSingleFileSync(final List filesToRequest) {
- final boolean debugHashes = Configs.CLIENT_CONFIG.shouldPrintDebugHashes();
-
- if (autoSyncedFiles.size() > 0) {
- if (Configs.MAIN_CONFIG.verboseLogging())
- BCLib.LOGGER.info("Files offered by Server:");
- }
-
- //Handle single sync files
- //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 (AutoSync.AutoSyncTriple e : autoSyncedFiles) {
- String actionString = "";
- FileContentWrapper contentWrapper = new FileContentWrapper(e.serverContent);
- if (e.localMatch == null) {
- actionString = "(unknown source -> omitting)";
- //filesToRequest.add(new AutoSyncID(e.serverHash.modID, e.serverHash.uniqueID));
- } else if (e.localMatch.needTransfer.test(e.localMatch.getFileHash(), e.serverHash, contentWrapper)) {
- actionString = "(prepare update)";
- //we did not yet receive the new content
- if (contentWrapper.getRawContent() == null) {
- filesToRequest.add(new AutoSyncID(e.serverHash.modID, e.serverHash.uniqueID));
- } else {
- filesToRequest.add(new AutoSyncID.WithContentOverride(
- e.serverHash.modID,
- e.serverHash.uniqueID,
- contentWrapper,
- e.localMatch.fileName
- ));
- }
- }
- if (Configs.MAIN_CONFIG.verboseLogging()) {
- BCLib.LOGGER.info(" - " + e + ": " + actionString);
- if (debugHashes) {
- BCLib.LOGGER.info(" * " + e.serverHash + " (Server)");
- BCLib.LOGGER.info(" * " + e.localMatch.getFileHash() + " (Client)");
- BCLib.LOGGER.info(" * local Content " + (contentWrapper.getRawContent() == null));
- }
- }
- }
- }
-
-
- @Environment(EnvType.CLIENT)
- private void processModFileSync(final List filesToRequest, final Set mismatchingMods) {
- for (Entry e : modVersion.entrySet()) {
- final String localVersion = ModUtil.convertModVersion(ModUtil.convertModVersion(ModUtil.getModVersion(e.getKey())));
- final OfferedModInfo serverInfo = e.getValue();
-
- ModInfo nfo = ModUtil.getModInfo(e.getKey());
- final boolean clientOnly = nfo != null && nfo.metadata.getEnvironment() == ModEnvironment.CLIENT;
- final boolean requestMod = !clientOnly && !serverInfo.version.equals(localVersion) && serverInfo.size > 0 && serverInfo.canDownload;
-
- if (Configs.MAIN_CONFIG.verboseLogging())
- BCLib.LOGGER.info(" - " + e.getKey() + " (client=" + localVersion + ", server=" + serverInfo.version + ", size=" + PathUtil.humanReadableFileSize(
- serverInfo.size) + (requestMod ? ", requesting" : "") + (serverInfo.canDownload
- ? ""
- : ", not offered") + (clientOnly ? ", client only" : "") + ")");
- if (requestMod) {
- filesToRequest.add(new AutoSyncID.ForModFileRequest(e.getKey(), serverInfo.version));
- }
- if (!serverInfo.version.equals(localVersion)) {
- mismatchingMods.add(e.getKey());
- }
- }
-
- mismatchingMods.addAll(ModListScreen.localMissing(modVersion));
- mismatchingMods.addAll(ModListScreen.serverMissing(modVersion));
- }
-
- @Override
- protected boolean isBlocking() {
- return true;
- }
-
- @Environment(EnvType.CLIENT)
- @Override
- protected void runOnClientGameThread(Minecraft client) {
- if (!Configs.CLIENT_CONFIG.isAllowingAutoSync()) {
- BCLib.LOGGER.info("Auto-Sync was disabled on the client.");
- return;
- }
- final String localBclibVersion = getBCLibVersion();
- BCLib.LOGGER.info("Received Hello from Server. (client=" + localBclibVersion + ", server=" + bclibVersion + ")");
-
- if (ModUtil.convertModVersion(localBclibVersion) != ModUtil.convertModVersion(bclibVersion)) {
- showBCLibError(client);
- return;
- }
-
- final List filesToRequest = new ArrayList<>(2);
- final List filesToRemove = new ArrayList<>(2);
- final Set mismatchingMods = new HashSet<>(2);
-
-
- processModFileSync(filesToRequest, mismatchingMods);
- processSingleFileSync(filesToRequest);
- processAutoSyncFolder(filesToRequest, filesToRemove);
-
- //Handle folder sync
- //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) && (Configs.CLIENT_CONFIG.isAcceptingMods() || Configs.CLIENT_CONFIG.isAcceptingConfigs() || Configs.CLIENT_CONFIG.isAcceptingFiles())) {
- showSyncFilesScreen(client, filesToRequest, filesToRemove);
- return;
- } else if (serverPublishedModInfo && mismatchingMods.size() > 0 && Configs.CLIENT_CONFIG.isShowingModInfo()) {
- client.setScreen(new ModListScreen(
- client.screen,
- Component.translatable("title.bclib.modmissmatch"),
- Component.translatable("message.bclib.modmissmatch"),
- CommonComponents.GUI_PROCEED,
- ModUtil.getMods(),
- modVersion
- ));
- return;
- }
- }
-
- @Environment(EnvType.CLIENT)
- protected void showBCLibError(Minecraft client) {
- BCLib.LOGGER.error("BCLib differs on client and server.");
- client.setScreen(new WarnBCLibVersionMismatch((download) -> {
- if (download) {
- requestBCLibDownload();
-
- this.onCloseSyncFilesScreen();
- } else {
- Minecraft.getInstance()
- .setScreen(null);
- }
- }));
- }
-
- @Environment(EnvType.CLIENT)
- protected void showSyncFilesScreen(
- Minecraft client,
- List files,
- final List filesToRemove
- ) {
- int configFiles = 0;
- int singleFiles = 0;
- int folderFiles = 0;
- int modFiles = 0;
-
- for (AutoSyncID aid : files) {
- if (aid.isConfigFile()) {
- configFiles++;
- } else if (aid instanceof AutoSyncID.ForModFileRequest) {
- modFiles++;
- } else if (aid instanceof AutoSyncID.ForDirectFileRequest) {
- folderFiles++;
- } else {
- singleFiles++;
- }
- }
-
- client.setScreen(new SyncFilesScreen(
- modFiles,
- configFiles,
- singleFiles,
- folderFiles,
- filesToRemove.size(),
- modVersion,
- (downloadMods, downloadConfigs, downloadFiles, removeFiles) -> {
- if (downloadMods || downloadConfigs || downloadFiles) {
- BCLib.LOGGER.info("Updating local Files:");
- List localChanges = new ArrayList<>(
- files.toArray().length);
- List requestFiles = new ArrayList<>(files.toArray().length);
-
- files.forEach(aid -> {
- if (aid.isConfigFile() && downloadConfigs) {
- processOfferedFile(requestFiles, aid);
- } else if (aid instanceof AutoSyncID.ForModFileRequest && downloadMods) {
- processOfferedFile(requestFiles, aid);
- } else if (downloadFiles) {
- processOfferedFile(requestFiles, aid);
- }
- });
-
- requestFileDownloads(requestFiles);
- }
- if (removeFiles) {
- filesToRemove.forEach(aid -> {
- BCLib.LOGGER.info(" - " + aid.relFile + " (removing)");
- aid.relFile.delete();
- });
- }
-
- this.onCloseSyncFilesScreen();
- }
- ));
- }
-
- @Environment(EnvType.CLIENT)
- private void onCloseSyncFilesScreen() {
- Minecraft.getInstance()
- .setScreen(ChunkerProgress.getProgressScreen());
- }
-
- private void processOfferedFile(List requestFiles, AutoSyncID aid) {
- if (aid instanceof AutoSyncID.WithContentOverride) {
- final AutoSyncID.WithContentOverride aidc = (AutoSyncID.WithContentOverride) aid;
- BCLib.LOGGER.info(" - " + aid + " (updating Content)");
-
- SendFiles.writeSyncedFile(aid, aidc.contentWrapper.getRawContent(), aidc.localFile);
- } else {
- requestFiles.add(aid);
- BCLib.LOGGER.info(" - " + aid + " (requesting)");
- }
- }
-
- private void requestBCLibDownload() {
- BCLib.LOGGER.warning("Starting download of BCLib");
- requestFileDownloads(List.of(new AutoSyncID.ForModFileRequest(BCLib.MOD_ID, bclibVersion)));
- }
-
- @Environment(EnvType.CLIENT)
- private void requestFileDownloads(List files) {
- BCLib.LOGGER.info("Starting download of Files:" + files.size());
-
- final ProgressScreen progress = new ProgressScreen(
- null,
- Component.translatable("title.bclib.filesync.progress"),
- Component.translatable("message.bclib.filesync.progress")
- );
- progress.progressStart(Component.translatable("message.bclib.filesync.progress.stage.empty"));
- ChunkerProgress.setProgressScreen(progress);
-
- DataExchangeAPI.send(new RequestFiles(files));
- }
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/HelloServer.java b/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/HelloServer.java
deleted file mode 100644
index df1994fa..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/HelloServer.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package org.betterx.bclib.api.v2.dataexchange.handler.autosync;
-
-import org.betterx.bclib.BCLib;
-import org.betterx.bclib.api.v2.dataexchange.DataExchangeAPI;
-import org.betterx.bclib.api.v2.dataexchange.DataHandler;
-import org.betterx.bclib.api.v2.dataexchange.DataHandlerDescriptor;
-import org.betterx.bclib.config.Configs;
-import org.betterx.worlds.together.util.ModUtil;
-
-import net.minecraft.network.FriendlyByteBuf;
-import net.minecraft.resources.ResourceLocation;
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.world.entity.player.Player;
-
-import net.fabricmc.api.EnvType;
-import net.fabricmc.api.Environment;
-import net.fabricmc.fabric.api.networking.v1.PacketSender;
-
-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
- * client and server.
- *
- * Description
- *
- * Server |
- * |
- * Client |
- * |
- *
- *
- * Player enters World |
- *
- *
- * |
- * <-- |
- * {@link HelloServer} |
- * Sends the current BLib-Version installed on the Client |
- *
- *
- * {@link HelloClient} |
- * --> |
- * |
- * Sends the current BClIb-Version, the Version of all Plugins and data for all AutpoSync-Files
- * ({@link DataExchangeAPI#addAutoSyncFile(String, File)} on the Server |
- *
- *
- * |
- * <-- |
- * {@link RequestFiles} |
- * Request missing or out of sync Files from the Server |
- *
- *
- * {@link SendFiles} |
- * --> |
- * |
- * Send Files from the Server to the Client |
- *
- *
- */
-public class HelloServer extends DataHandler.FromClient {
- public static final 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);
- }
-
- @Environment(EnvType.CLIENT)
- @Override
- protected boolean prepareDataOnClient() {
- if (!Configs.CLIENT_CONFIG.isAllowingAutoSync()) {
- BCLib.LOGGER.info("Auto-Sync was disabled on the client.");
- return false;
- }
-
- return true;
- }
-
- @Environment(EnvType.CLIENT)
- @Override
- protected void serializeDataOnClient(FriendlyByteBuf buf) {
- BCLib.LOGGER.info("Sending hello to server.");
- buf.writeInt(ModUtil.convertModVersion(HelloClient.getBCLibVersion()));
- }
-
- @Override
- protected void deserializeIncomingDataOnServer(FriendlyByteBuf buf, Player player, PacketSender responseSender) {
- bclibVersion = ModUtil.convertModVersion(buf.readInt());
- }
-
- @Override
- protected void runOnServerGameThread(MinecraftServer server, Player player) {
- if (!Configs.SERVER_CONFIG.isAllowingAutoSync()) {
- BCLib.LOGGER.info("Auto-Sync was disabled on the server.");
- return;
- }
-
- String localBclibVersion = HelloClient.getBCLibVersion();
- BCLib.LOGGER.info("Received Hello from Client. (server=" + localBclibVersion + ", client=" + bclibVersion + ")");
-
- if (!server.isPublished()) {
- BCLib.LOGGER.info("Auto-Sync is disabled for Singleplayer worlds.");
- return;
- }
-
- reply(new HelloClient(), server);
- }
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/RequestFiles.java b/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/RequestFiles.java
deleted file mode 100644
index ec4da863..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/RequestFiles.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package org.betterx.bclib.api.v2.dataexchange.handler.autosync;
-
-import org.betterx.bclib.BCLib;
-import org.betterx.bclib.api.v2.dataexchange.DataHandler;
-import org.betterx.bclib.api.v2.dataexchange.DataHandlerDescriptor;
-import org.betterx.bclib.config.Configs;
-
-import net.minecraft.network.FriendlyByteBuf;
-import net.minecraft.resources.ResourceLocation;
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.world.entity.player.Player;
-
-import net.fabricmc.api.EnvType;
-import net.fabricmc.api.Environment;
-import net.fabricmc.fabric.api.networking.v1.PacketSender;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-import java.util.stream.Collectors;
-
-public class RequestFiles extends DataHandler.FromClient {
- public static final DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(
- new ResourceLocation(
- BCLib.MOD_ID,
- "request_files"
- ),
- RequestFiles::new,
- false,
- false
- );
- static String currentToken = "";
-
- protected List files;
-
- private RequestFiles() {
- this(null);
- }
-
- public RequestFiles(List files) {
- super(DESCRIPTOR.IDENTIFIER);
- this.files = files;
- }
-
- @Environment(EnvType.CLIENT)
- @Override
- protected boolean prepareDataOnClient() {
- if (!Configs.CLIENT_CONFIG.isAllowingAutoSync()) {
- BCLib.LOGGER.info("Auto-Sync was disabled on the client.");
- return false;
- }
- return true;
- }
-
- @Environment(EnvType.CLIENT)
- @Override
- protected void serializeDataOnClient(FriendlyByteBuf buf) {
- newToken();
- writeString(buf, currentToken);
-
- buf.writeInt(files.size());
-
- for (AutoSyncID a : files) {
- a.serializeData(buf);
- }
- }
-
- String receivedToken = "";
-
- @Override
- protected void deserializeIncomingDataOnServer(FriendlyByteBuf buf, Player player, PacketSender responseSender) {
- receivedToken = readString(buf);
- int size = buf.readInt();
- files = new ArrayList<>(size);
-
- if (Configs.MAIN_CONFIG.verboseLogging())
- BCLib.LOGGER.info("Client requested " + size + " Files:");
- for (int i = 0; i < size; i++) {
- AutoSyncID asid = AutoSyncID.deserializeData(buf);
- files.add(asid);
- if (Configs.MAIN_CONFIG.verboseLogging())
- BCLib.LOGGER.info(" - " + asid);
- }
-
-
- }
-
- @Override
- protected void runOnServerGameThread(MinecraftServer server, Player player) {
- if (!Configs.SERVER_CONFIG.isAllowingAutoSync()) {
- BCLib.LOGGER.info("Auto-Sync was disabled on the server.");
- return;
- }
-
- List syncEntries = files.stream()
- .map(asid -> AutoFileSyncEntry.findMatching(asid))
- .filter(e -> e != null)
- .collect(Collectors.toList());
-
- reply(new SendFiles(syncEntries, receivedToken), server);
- }
-
- public static void newToken() {
- currentToken = UUID.randomUUID()
- .toString();
- }
-
- static {
- newToken();
- }
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/SendFiles.java b/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/SendFiles.java
deleted file mode 100644
index 531a7cf2..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/SendFiles.java
+++ /dev/null
@@ -1,230 +0,0 @@
-package org.betterx.bclib.api.v2.dataexchange.handler.autosync;
-
-import org.betterx.bclib.BCLib;
-import org.betterx.bclib.api.v2.dataexchange.DataHandler;
-import org.betterx.bclib.api.v2.dataexchange.DataHandlerDescriptor;
-import org.betterx.bclib.client.gui.screens.ConfirmRestartScreen;
-import org.betterx.bclib.config.Configs;
-import org.betterx.bclib.util.Pair;
-import org.betterx.bclib.util.Triple;
-import org.betterx.worlds.together.util.PathUtil;
-
-import net.minecraft.client.Minecraft;
-import net.minecraft.network.FriendlyByteBuf;
-import net.minecraft.resources.ResourceLocation;
-
-import net.fabricmc.api.EnvType;
-import net.fabricmc.api.Environment;
-import net.fabricmc.fabric.api.networking.v1.PacketSender;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
-public class SendFiles extends DataHandler.FromServer {
- public static final DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(
- new ResourceLocation(
- BCLib.MOD_ID,
- "send_files"
- ),
- SendFiles::new,
- false,
- false
- );
-
- protected List files;
- private String token;
-
- public SendFiles() {
- this(null, "");
- }
-
- public SendFiles(List files, String token) {
- super(DESCRIPTOR.IDENTIFIER);
- this.files = files;
- this.token = token;
- }
-
- @Override
- protected boolean prepareDataOnServer() {
- if (!Configs.SERVER_CONFIG.isAllowingAutoSync()) {
- BCLib.LOGGER.info("Auto-Sync was disabled on the server.");
- return false;
- }
-
- return true;
- }
-
- @Override
- protected void serializeDataOnServer(FriendlyByteBuf buf) {
- List existingFiles = files.stream()
- .filter(e -> e != null && e.fileName != null && 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) -> {
- System.out.println("Got Content:" + content.length);
- return true;
- }));*/
-
- /*//this will try to send a folder-file that was not registered or requested by the client
- existingFiles.add(new AutoFileSyncEntry.ForDirectFileRequest(DataExchange.SYNC_FOLDER.folderID, new File("test.json"), DataExchange.SYNC_FOLDER.mapAbsolute("test.json").toFile()));*/
-
- /*//this will try to send a folder-file that was not registered or requested by the client and is outside the base-folder
- existingFiles.add(new AutoFileSyncEntry.ForDirectFileRequest(DataExchange.SYNC_FOLDER.folderID, new File("../breakout.json"), DataExchange.SYNC_FOLDER.mapAbsolute("../breakout.json").toFile()));*/
-
-
- writeString(buf, token);
- buf.writeInt(existingFiles.size());
-
- if (Configs.MAIN_CONFIG.verboseLogging())
- BCLib.LOGGER.info("Sending " + existingFiles.size() + " Files to Client:");
- for (AutoFileSyncEntry entry : existingFiles) {
- int length = entry.serializeContent(buf);
- if (Configs.MAIN_CONFIG.verboseLogging())
- BCLib.LOGGER.info(" - " + entry + " (" + PathUtil.humanReadableFileSize(length) + ")");
- }
- }
-
- private List> receivedFiles;
-
- @Environment(EnvType.CLIENT)
- @Override
- protected void deserializeIncomingDataOnClient(FriendlyByteBuf buf, PacketSender responseSender) {
- if (Configs.CLIENT_CONFIG.isAcceptingConfigs() || Configs.CLIENT_CONFIG.isAcceptingFiles() || Configs.CLIENT_CONFIG.isAcceptingMods()) {
- token = readString(buf);
- if (!token.equals(RequestFiles.currentToken)) {
- RequestFiles.newToken();
- BCLib.LOGGER.error("Unrequested File Transfer!");
- receivedFiles = new ArrayList<>(0);
- return;
- }
- RequestFiles.newToken();
-
- int size = buf.readInt();
- receivedFiles = new ArrayList<>(size);
- if (Configs.MAIN_CONFIG.verboseLogging())
- BCLib.LOGGER.info("Server sent " + size + " Files:");
- for (int i = 0; i < size; i++) {
- Triple p = AutoFileSyncEntry.deserializeContent(buf);
- if (p.first != null) {
- final String type;
- if (p.first.isConfigFile() && Configs.CLIENT_CONFIG.isAcceptingConfigs()) {
- receivedFiles.add(p);
- type = "Accepted Config ";
- } else if (p.first instanceof AutoFileSyncEntry.ForModFileRequest && Configs.CLIENT_CONFIG.isAcceptingMods()) {
- receivedFiles.add(p);
- type = "Accepted Mod ";
- } else if (Configs.CLIENT_CONFIG.isAcceptingFiles()) {
- receivedFiles.add(p);
- type = "Accepted File ";
- } else {
- type = "Ignoring ";
- }
- if (Configs.MAIN_CONFIG.verboseLogging())
- BCLib.LOGGER.info(" - " + type + p.first + " (" + PathUtil.humanReadableFileSize(p.second.length) + ")");
- } else {
- if (Configs.MAIN_CONFIG.verboseLogging())
- BCLib.LOGGER.error(" - Failed to receive File " + p.third + ", possibly sent from a Mod that is not installed on the client.");
- }
- }
- }
- }
-
- @Environment(EnvType.CLIENT)
- @Override
- protected void runOnClientGameThread(Minecraft client) {
- if (Configs.CLIENT_CONFIG.isAcceptingConfigs() || Configs.CLIENT_CONFIG.isAcceptingFiles() || Configs.CLIENT_CONFIG.isAcceptingMods()) {
- BCLib.LOGGER.info("Writing Files:");
-
- for (Pair entry : receivedFiles) {
- final AutoFileSyncEntry e = entry.first;
- final byte[] data = entry.second;
-
- writeSyncedFile(e, data, e.fileName);
- }
-
- showConfirmRestart(client);
- }
- }
-
-
- @Environment(EnvType.CLIENT)
- static void writeSyncedFile(AutoSyncID e, byte[] data, File fileName) {
- if (fileName != null && !PathUtil.isChildOf(PathUtil.GAME_FOLDER, fileName.toPath())) {
- BCLib.LOGGER.error(fileName + " is not within game folder " + PathUtil.GAME_FOLDER);
- return;
- }
-
- 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 mase) {
- removeAfter = path;
- int count = 0;
- final String prefix = "_bclib_synced_";
- String name = prefix + 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 = prefix + 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();
- if (!parentFile.exists()) {
- 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);
- }
- }
-
- @Environment(EnvType.CLIENT)
- protected void showConfirmRestart(Minecraft client) {
- client.setScreen(new ConfirmRestartScreen(() -> {
- Minecraft.getInstance()
- .setScreen(null);
- client.stop();
- }));
-
- }
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/SyncFolderDescriptor.java b/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/SyncFolderDescriptor.java
deleted file mode 100644
index bc4bd275..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/dataexchange/handler/autosync/SyncFolderDescriptor.java
+++ /dev/null
@@ -1,220 +0,0 @@
-package org.betterx.bclib.api.v2.dataexchange.handler.autosync;
-
-import org.betterx.bclib.BCLib;
-import org.betterx.bclib.api.v2.dataexchange.DataHandler;
-import org.betterx.bclib.api.v2.dataexchange.FileHash;
-import org.betterx.bclib.api.v2.dataexchange.handler.autosync.AutoSyncID.ForDirectFileRequest;
-import org.betterx.bclib.config.Configs;
-import org.betterx.worlds.together.util.PathUtil;
-
-import net.minecraft.network.FriendlyByteBuf;
-
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Stream;
-import org.jetbrains.annotations.NotNull;
-
-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 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.SYNC_CATEGORY, "debugHashes", false);
- loadCache();
-
- DataHandler.writeString(buf, folderID);
- buf.writeBoolean(removeAdditionalFiles);
- buf.writeInt(fileCache.size());
- fileCache.forEach(fl -> {
- if (Configs.MAIN_CONFIG.verboseLogging()) {
- 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,
- localDescriptor.removeAdditionalFiles && 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 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);
- }
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/datafixer/DataFixerAPI.java b/src/main/java/org/betterx/bclib/api/v2/datafixer/DataFixerAPI.java
deleted file mode 100644
index 07a9cf20..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/datafixer/DataFixerAPI.java
+++ /dev/null
@@ -1,598 +0,0 @@
-package org.betterx.bclib.api.v2.datafixer;
-
-import org.betterx.bclib.BCLib;
-import org.betterx.bclib.client.gui.screens.AtomicProgressListener;
-import org.betterx.bclib.client.gui.screens.ConfirmFixScreen;
-import org.betterx.bclib.client.gui.screens.LevelFixErrorScreen;
-import org.betterx.bclib.client.gui.screens.LevelFixErrorScreen.Listener;
-import org.betterx.bclib.client.gui.screens.ProgressScreen;
-import org.betterx.bclib.config.Configs;
-import org.betterx.worlds.together.util.Logger;
-import org.betterx.worlds.together.world.WorldConfig;
-
-import net.minecraft.Util;
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.gui.components.toasts.SystemToast;
-import net.minecraft.client.gui.screens.worldselection.EditWorldScreen;
-import net.minecraft.nbt.*;
-import net.minecraft.network.chat.Component;
-import net.minecraft.world.level.ChunkPos;
-import net.minecraft.world.level.chunk.storage.RegionFile;
-import net.minecraft.world.level.storage.LevelResource;
-import net.minecraft.world.level.storage.LevelStorageSource;
-import net.minecraft.world.level.storage.LevelStorageSource.LevelStorageAccess;
-
-import net.fabricmc.api.EnvType;
-import net.fabricmc.api.Environment;
-
-import java.io.*;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.Supplier;
-import java.util.zip.ZipException;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * API to manage Patches that need to get applied to a world
- */
-public class DataFixerAPI {
- static final Logger LOGGER = new Logger("DataFixerAPI");
-
- static class State {
- public boolean didFail = false;
- protected ArrayList errors = new ArrayList<>();
-
- public void addError(String s) {
- errors.add(s);
- }
-
- public boolean hasError() {
- return errors.size() > 0;
- }
-
- public String getErrorMessage() {
- return errors.stream().reduce("", (a, b) -> a + " - " + b + "\n");
- }
-
- public String[] getErrorMessages() {
- String[] res = new String[errors.size()];
- return errors.toArray(res);
- }
- }
-
- @FunctionalInterface
- public interface Callback {
- void call();
- }
-
- private static boolean wrapCall(
- LevelStorageSource levelSource,
- String levelID,
- Function runWithLevel
- ) {
- LevelStorageSource.LevelStorageAccess levelStorageAccess;
- try {
- levelStorageAccess = levelSource.createAccess(levelID);
- } catch (IOException e) {
- BCLib.LOGGER.warning("Failed to read level {} data", levelID, e);
- SystemToast.onWorldAccessFailure(Minecraft.getInstance(), levelID);
- Minecraft.getInstance().setScreen(null);
- return true;
- }
-
- boolean returnValue = runWithLevel.apply(levelStorageAccess);
-
- try {
- levelStorageAccess.close();
- } catch (IOException e) {
- BCLib.LOGGER.warning("Failed to unlock access to level {}", levelID, e);
- }
-
- return returnValue;
- }
-
- /**
- * Will apply necessary Patches to the world.
- *
- * @param levelSource The SourceStorage for this Minecraft instance, You can get this using
- * {@code Minecraft.getInstance().getLevelSource()}
- * @param levelID The ID of the Level you want to patch
- * @param showUI {@code true}, if you want to present the user with a Screen that offers to backup the world
- * before applying the patches
- * @param onResume When this method retursn {@code true}, this function will be called when the world is ready
- * @return {@code true} if the UI was displayed. The UI is only displayed if {@code showUI} was {@code true} and
- * patches were enabled in the config and the Guardian did find any patches that need to be applied to the world.
- */
- public static boolean fixData(
- LevelStorageSource levelSource,
- String levelID,
- boolean showUI,
- Consumer onResume
- ) {
- return wrapCall(levelSource, levelID, (levelStorageAccess) -> fixData(levelStorageAccess, showUI, onResume));
- }
-
- /**
- * Will apply necessary Patches to the world.
- *
- * @param levelStorageAccess The access class of the level you want to patch
- * @param showUI {@code true}, if you want to present the user with a Screen that offers to backup the world
- * before applying the patches
- * @param onResume When this method retursn {@code true}, this function will be called when the world is ready
- * @return {@code true} if the UI was displayed. The UI is only displayed if {@code showUI} was {@code true} and
- * patches were enabled in the config and the Guardian did find any patches that need to be applied to the world.
- */
- public static boolean fixData(
- LevelStorageSource.LevelStorageAccess levelStorageAccess,
- boolean showUI,
- Consumer onResume
- ) {
- File levelPath = levelStorageAccess.getLevelPath(LevelResource.ROOT).toFile();
- return fixData(levelPath, levelStorageAccess.getLevelId(), showUI, onResume);
- }
-
- /**
- * Creates the patch level file for new worlds
- */
- public static void initializePatchData() {
- getMigrationProfile().markApplied();
- WorldConfig.saveFile(BCLib.MOD_ID);
- }
-
-
- @Environment(EnvType.CLIENT)
- private static AtomicProgressListener showProgressScreen() {
- ProgressScreen ps = new ProgressScreen(
- Minecraft.getInstance().screen,
- Component.translatable("title.bclib.datafixer.progress"),
- Component.translatable("message.bclib.datafixer.progress")
- );
- Minecraft.getInstance().setScreen(ps);
- return ps;
- }
-
- private static boolean fixData(File dir, String levelID, boolean showUI, Consumer onResume) {
- MigrationProfile profile = loadProfileIfNeeded(dir);
-
- BiConsumer runFixes = (createBackup, applyFixes) -> {
- final AtomicProgressListener progress;
- if (applyFixes) {
- if (showUI) {
- progress = showProgressScreen();
- } else {
- progress = new AtomicProgressListener() {
- private long timeStamp = Util.getMillis();
- private AtomicInteger counter = new AtomicInteger(0);
-
- @Override
- public void incAtomic(int maxProgress) {
- int percentage = (100 * counter.incrementAndGet()) / maxProgress;
- if (Util.getMillis() - this.timeStamp >= 1000L) {
- this.timeStamp = Util.getMillis();
- BCLib.LOGGER.info("Patching... {}%", percentage);
- }
- }
-
- @Override
- public void resetAtomic() {
- counter = new AtomicInteger(0);
- }
-
- public void stop() {
- }
-
- public void progressStage(Component component) {
- BCLib.LOGGER.info("Patcher Stage... {}%", component.getString());
- }
- };
- }
- } else {
- progress = null;
- }
-
- Supplier runner = () -> {
- if (createBackup) {
- progress.progressStage(Component.translatable("message.bclib.datafixer.progress.waitbackup"));
- EditWorldScreen.makeBackupAndShowToast(Minecraft.getInstance().getLevelSource(), levelID);
- }
-
- if (applyFixes) {
- return runDataFixes(dir, profile, progress);
- }
-
- return new State();
- };
-
- if (showUI) {
- Thread fixerThread = new Thread(() -> {
- final State state = runner.get();
-
- Minecraft.getInstance()
- .execute(() -> {
- if (profile != null && showUI) {
- //something went wrong, show the user our error
- if (state.didFail || state.hasError()) {
- showLevelFixErrorScreen(state, (markFixed) -> {
- if (markFixed) {
- profile.markApplied();
- }
- onResume.accept(applyFixes);
- });
- } else {
- onResume.accept(applyFixes);
- }
- }
- });
-
- });
- fixerThread.start();
- } else {
- State state = runner.get();
- if (state.hasError()) {
- LOGGER.error("There were Errors while fixing the Level:");
- LOGGER.error(state.getErrorMessage());
- }
- }
- };
-
- //we have some migrations
- if (profile != null) {
- //display the confirm UI.
- if (showUI) {
- showBackupWarning(levelID, runFixes);
- return true;
- } else {
- BCLib.LOGGER.warning("Applying Fixes on Level");
- runFixes.accept(false, true);
- }
- }
- return false;
- }
-
- @Environment(EnvType.CLIENT)
- private static void showLevelFixErrorScreen(State state, Listener onContinue) {
- Minecraft.getInstance()
- .setScreen(new LevelFixErrorScreen(
- Minecraft.getInstance().screen,
- state.getErrorMessages(),
- onContinue
- ));
- }
-
- private static MigrationProfile loadProfileIfNeeded(File levelBaseDir) {
- if (!Configs.MAIN_CONFIG.applyPatches()) {
- LOGGER.info("World Patches are disabled");
- return null;
- }
-
- MigrationProfile profile = getMigrationProfile();
- profile.runPrePatches(levelBaseDir);
-
- if (!profile.hasAnyFixes()) {
- LOGGER.info("Everything up to date");
- return null;
- }
-
- return profile;
- }
-
- @NotNull
- private static MigrationProfile getMigrationProfile() {
- final CompoundTag patchConfig = WorldConfig.getCompoundTag(BCLib.MOD_ID, Configs.MAIN_PATCH_CATEGORY);
- MigrationProfile profile = Patch.createMigrationData(patchConfig);
- return profile;
- }
-
- @Environment(EnvType.CLIENT)
- static void showBackupWarning(String levelID, BiConsumer whenFinished) {
- Minecraft.getInstance().setScreen(new ConfirmFixScreen(null, whenFinished::accept));
- }
-
- private static State runDataFixes(File dir, MigrationProfile profile, AtomicProgressListener progress) {
- State state = new State();
- progress.resetAtomic();
-
- progress.progressStage(Component.translatable("message.bclib.datafixer.progress.reading"));
- List players = getAllPlayers(dir);
- List regions = getAllRegions(dir, null);
- final int maxProgress = players.size() + regions.size() + 4;
- progress.incAtomic(maxProgress);
-
- progress.progressStage(Component.translatable("message.bclib.datafixer.progress.players"));
- players.parallelStream().forEach((file) -> {
- fixPlayer(profile, state, file);
- progress.incAtomic(maxProgress);
- });
-
- progress.progressStage(Component.translatable("message.bclib.datafixer.progress.level"));
- fixLevel(profile, state, dir);
- progress.incAtomic(maxProgress);
-
- progress.progressStage(Component.translatable("message.bclib.datafixer.progress.worlddata"));
- try {
- profile.patchWorldData();
- } catch (PatchDidiFailException e) {
- state.didFail = true;
- state.addError("Failed fixing worldconfig (" + e.getMessage() + ")");
- BCLib.LOGGER.error(e.getMessage());
- }
- progress.incAtomic(maxProgress);
-
- progress.progressStage(Component.translatable("message.bclib.datafixer.progress.regions"));
- regions.parallelStream().forEach((file) -> {
- fixRegion(profile, state, file);
- progress.incAtomic(maxProgress);
- });
-
- if (!state.didFail) {
- progress.progressStage(Component.translatable("message.bclib.datafixer.progress.saving"));
- profile.markApplied();
- WorldConfig.saveFile(BCLib.MOD_ID);
- }
- progress.incAtomic(maxProgress);
-
- progress.stop();
-
- return state;
- }
-
- private static void fixLevel(MigrationProfile profile, State state, File levelBaseDir) {
- try {
- LOGGER.info("Inspecting level.dat in " + levelBaseDir);
-
- //load the level (could already contain patches applied by patchLevelDat)
- CompoundTag level = profile.getLevelDat(levelBaseDir);
- boolean[] changed = {profile.isLevelDatChanged()};
-
- if (profile.getPrePatchException() != null) {
- throw profile.getPrePatchException();
- }
-
- if (level.contains("Data")) {
- CompoundTag dataTag = (CompoundTag) level.get("Data");
- if (dataTag.contains("Player")) {
- CompoundTag player = (CompoundTag) dataTag.get("Player");
- fixPlayerNbt(player, changed, profile);
- }
- }
-
- if (changed[0]) {
- LOGGER.warning("Writing '{}'", profile.getLevelDatFile());
- NbtIo.writeCompressed(level, profile.getLevelDatFile());
- }
- } catch (Exception e) {
- BCLib.LOGGER.error("Failed fixing Level-Data.");
- state.addError("Failed fixing Level-Data in level.dat (" + e.getMessage() + ")");
- state.didFail = true;
- e.printStackTrace();
- }
- }
-
- private static void fixPlayer(MigrationProfile data, State state, File file) {
- try {
- LOGGER.info("Inspecting " + file);
-
- CompoundTag player = readNbt(file);
- boolean[] changed = {false};
- fixPlayerNbt(player, changed, data);
-
- if (changed[0]) {
- LOGGER.warning("Writing '{}'", file);
- NbtIo.writeCompressed(player, file);
- }
- } catch (Exception e) {
- BCLib.LOGGER.error("Failed fixing Player-Data.");
- state.addError("Failed fixing Player-Data in " + file.getName() + " (" + e.getMessage() + ")");
- state.didFail = true;
- e.printStackTrace();
- }
- }
-
- private static void fixPlayerNbt(CompoundTag player, boolean[] changed, MigrationProfile data) {
- //Checking Inventory
- ListTag inventory = player.getList("Inventory", Tag.TAG_COMPOUND);
- fixItemArrayWithID(inventory, changed, data, true);
-
- //Checking EnderChest
- ListTag enderitems = player.getList("EnderItems", Tag.TAG_COMPOUND);
- fixItemArrayWithID(enderitems, changed, data, true);
-
- //Checking ReceipBook
- if (player.contains("recipeBook")) {
- CompoundTag recipeBook = player.getCompound("recipeBook");
- changed[0] |= fixStringIDList(recipeBook, "recipes", data);
- changed[0] |= fixStringIDList(recipeBook, "toBeDisplayed", data);
- }
- }
-
- static boolean fixStringIDList(CompoundTag root, String name, MigrationProfile data) {
- boolean _changed = false;
- if (root.contains(name)) {
- ListTag items = root.getList(name, Tag.TAG_STRING);
- ListTag newItems = new ListTag();
-
- for (Tag tag : items) {
- final StringTag str = (StringTag) tag;
- final String replace = data.replaceStringFromIDs(str.getAsString());
- if (replace != null) {
- _changed = true;
- newItems.add(StringTag.valueOf(replace));
- } else {
- newItems.add(tag);
- }
- }
- if (_changed) {
- root.put(name, newItems);
- }
- }
- return _changed;
- }
-
- private static void fixRegion(MigrationProfile data, State state, File file) {
- try {
- Path path = file.toPath();
- LOGGER.info("Inspecting " + path);
- boolean[] changed = new boolean[1];
- RegionFile region = new RegionFile(path, path.getParent(), true);
-
- for (int x = 0; x < 32; x++) {
- for (int z = 0; z < 32; z++) {
- ChunkPos pos = new ChunkPos(x, z);
- changed[0] = false;
- if (region.hasChunk(pos) && !state.didFail) {
- DataInputStream input = region.getChunkDataInputStream(pos);
- CompoundTag root = NbtIo.read(input);
- // if ((root.toString().contains("betternether:chest") || root.toString().contains("bclib:chest"))) {
- // NbtIo.write(root, new File(file.toString() + "-" + x + "-" + z + ".nbt"));
- // }
- input.close();
-
- //Checking TileEntities
- ListTag tileEntities = root.getCompound("Level")
- .getList("TileEntities", Tag.TAG_COMPOUND);
- fixItemArrayWithID(tileEntities, changed, data, true);
-
- //Checking Entities
- ListTag entities = root.getList("Entities", Tag.TAG_COMPOUND);
- fixItemArrayWithID(entities, changed, data, true);
-
- //Checking Block Palette
- ListTag sections = root.getCompound("Level")
- .getList("Sections", Tag.TAG_COMPOUND);
- sections.forEach((tag) -> {
- ListTag palette = ((CompoundTag) tag).getList("Palette", Tag.TAG_COMPOUND);
- palette.forEach((blockTag) -> {
- CompoundTag blockTagCompound = ((CompoundTag) blockTag);
- changed[0] |= data.replaceStringFromIDs(blockTagCompound, "Name");
- });
-
- try {
- changed[0] |= data.patchBlockState(
- palette,
- ((CompoundTag) tag).getList(
- "BlockStates",
- Tag.TAG_LONG
- )
- );
- } catch (PatchDidiFailException e) {
- BCLib.LOGGER.error("Failed fixing BlockState in " + pos);
- state.addError("Failed fixing BlockState in " + pos + " (" + e.getMessage() + ")");
- state.didFail = true;
- changed[0] = false;
- e.printStackTrace();
- }
- });
-
- if (changed[0]) {
- LOGGER.warning("Writing '{}': {}/{}", file, x, z);
- // NbtIo.write(root, new File(file.toString() + "-" + x + "-" + z + "-changed.nbt"));
- DataOutputStream output = region.getChunkDataOutputStream(pos);
- NbtIo.write(root, output);
- output.close();
- }
- }
- }
- }
- region.close();
- } catch (Exception e) {
- BCLib.LOGGER.error("Failed fixing Region.");
- state.addError("Failed fixing Region in " + file.getName() + " (" + e.getMessage() + ")");
- state.didFail = true;
- e.printStackTrace();
- }
- }
-
- static CompoundTag patchConfTag = null;
-
- static CompoundTag getPatchData() {
- if (patchConfTag == null) {
- patchConfTag = WorldConfig.getCompoundTag(BCLib.MOD_ID, Configs.MAIN_PATCH_CATEGORY);
- }
- return patchConfTag;
- }
-
- static void fixItemArrayWithID(ListTag items, boolean[] changed, MigrationProfile data, boolean recursive) {
- items.forEach(inTag -> {
- fixID((CompoundTag) inTag, changed, data, recursive);
- });
- }
-
-
- static void fixID(CompoundTag inTag, boolean[] changed, MigrationProfile data, boolean recursive) {
- final CompoundTag tag = inTag;
-
- changed[0] |= data.replaceStringFromIDs(tag, "id");
- if (tag.contains("Item")) {
- CompoundTag item = (CompoundTag) tag.get("Item");
- fixID(item, changed, data, recursive);
- }
-
- if (recursive && tag.contains("Items")) {
- fixItemArrayWithID(tag.getList("Items", Tag.TAG_COMPOUND), changed, data, true);
- }
- if (recursive && tag.contains("Inventory")) {
- ListTag inventory = tag.getList("Inventory", Tag.TAG_COMPOUND);
- fixItemArrayWithID(inventory, changed, data, true);
- }
- if (tag.contains("tag")) {
- CompoundTag entityTag = (CompoundTag) tag.get("tag");
- if (entityTag.contains("BlockEntityTag")) {
- CompoundTag blockEntityTag = (CompoundTag) entityTag.get("BlockEntityTag");
- fixID(blockEntityTag, changed, data, recursive);
- /*ListTag items = blockEntityTag.getList("Items", Tag.TAG_COMPOUND);
- fixItemArrayWithID(items, changed, data, recursive);*/
- }
- }
- }
-
- private static List getAllPlayers(File dir) {
- List list = new ArrayList<>();
- dir = new File(dir, "playerdata");
- if (!dir.exists() || !dir.isDirectory()) {
- return list;
- }
- for (File file : dir.listFiles()) {
- if (file.isFile() && file.getName().endsWith(".dat")) {
- list.add(file);
- }
- }
- return list;
- }
-
- private static List getAllRegions(File dir, List list) {
- if (list == null) {
- list = new ArrayList<>();
- }
- for (File file : dir.listFiles()) {
- if (file.isDirectory()) {
- getAllRegions(file, list);
- } else if (file.isFile() && file.getName().endsWith(".mca")) {
- list.add(file);
- }
- }
- return list;
- }
-
- /**
- * register a new Patch
- *
- * @param patch A #Supplier that will instantiate the new Patch Object
- */
- public static void registerPatch(Supplier patch) {
- Patch.getALL().add(patch.get());
- }
-
- private static CompoundTag readNbt(File file) throws IOException {
- try {
- return NbtIo.readCompressed(file);
- } catch (ZipException | EOFException e) {
- return NbtIo.read(file);
- }
- }
-
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/datafixer/ForcedLevelPatch.java b/src/main/java/org/betterx/bclib/api/v2/datafixer/ForcedLevelPatch.java
deleted file mode 100644
index 0d18a7e0..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/datafixer/ForcedLevelPatch.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package org.betterx.bclib.api.v2.datafixer;
-
-import org.betterx.bclib.interfaces.PatchBiFunction;
-import org.betterx.bclib.interfaces.PatchFunction;
-
-import net.minecraft.nbt.CompoundTag;
-import net.minecraft.nbt.ListTag;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import org.jetbrains.annotations.NotNull;
-
-
-/**
- * A Patch for level.dat that is always executed no matter what Patchlevel is set in a world.
- */
-public abstract class ForcedLevelPatch extends Patch {
- protected ForcedLevelPatch(@NotNull String modID, String version) {
- super(modID, version, true);
- }
-
- @Override
- public final Map getIDReplacements() {
- return new HashMap();
- }
-
- @Override
- public final PatchFunction getWorldDataPatcher() {
- return null;
- }
-
- @Override
- public final PatchBiFunction getBlockStatePatcher() {
- return null;
- }
-
- @Override
- public final List getWorldDataIDPaths() {
- return null;
- }
-
- @Override
- public PatchFunction getLevelDatPatcher() {
- return this::runLevelDatPatch;
- }
-
- /**
- * Called with the contents of level.dat in {@code root}
- *
- * @param root The contents of level.dat
- * @param profile The active migration profile
- * @return true, if the run did change the contents of root
- */
- abstract protected Boolean runLevelDatPatch(CompoundTag root, MigrationProfile profile);
-}
-
diff --git a/src/main/java/org/betterx/bclib/api/v2/datafixer/MigrationProfile.java b/src/main/java/org/betterx/bclib/api/v2/datafixer/MigrationProfile.java
deleted file mode 100644
index 931773ca..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/datafixer/MigrationProfile.java
+++ /dev/null
@@ -1,374 +0,0 @@
-package org.betterx.bclib.api.v2.datafixer;
-
-import org.betterx.bclib.BCLib;
-import org.betterx.bclib.interfaces.PatchBiFunction;
-import org.betterx.bclib.interfaces.PatchFunction;
-import org.betterx.worlds.together.util.ModUtil;
-import org.betterx.worlds.together.world.WorldConfig;
-
-import net.minecraft.nbt.CompoundTag;
-import net.minecraft.nbt.ListTag;
-import net.minecraft.nbt.NbtIo;
-import net.minecraft.nbt.Tag;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.*;
-import java.util.stream.Collectors;
-import org.jetbrains.annotations.NotNull;
-
-public class MigrationProfile {
- final Set mods;
- final Map idReplacements;
- final List> levelPatchers;
- final List> statePatchers;
- final List worldDataPatchers;
- final Map> worldDataIDPaths;
-
- private final CompoundTag config;
- private CompoundTag level;
- private File levelBaseDir;
- private boolean prePatchChangedLevelDat;
- private boolean didRunPrePatch;
- private Exception prePatchException;
-
- MigrationProfile(CompoundTag config, boolean applyAll) {
- this.config = config;
-
- this.mods = Collections.unmodifiableSet(Patch.getALL()
- .stream()
- .map(p -> p.modID)
- .collect(Collectors.toSet()));
-
- HashMap replacements = new HashMap();
- List> levelPatches = new LinkedList<>();
- List worldDataPatches = new LinkedList<>();
- List> statePatches = new LinkedList<>();
- HashMap> worldDataIDPaths = new HashMap<>();
- for (String modID : mods) {
-
- Patch.getALL()
- .stream()
- .filter(p -> p.modID.equals(modID))
- .forEach(patch -> {
- List paths = patch.getWorldDataIDPaths();
- if (paths != null) worldDataIDPaths.put(modID, paths);
-
- if (applyAll || currentPatchLevel(modID) < patch.level || patch.alwaysApply) {
- replacements.putAll(patch.getIDReplacements());
- if (patch.getLevelDatPatcher() != null)
- levelPatches.add(patch.getLevelDatPatcher());
- if (patch.getWorldDataPatcher() != null)
- worldDataPatches.add(patch);
- if (patch.getBlockStatePatcher() != null)
- statePatches.add(patch.getBlockStatePatcher());
- DataFixerAPI.LOGGER.info("Applying " + patch);
- } else {
- DataFixerAPI.LOGGER.info("Ignoring " + patch);
- }
- });
- }
-
- this.worldDataIDPaths = Collections.unmodifiableMap(worldDataIDPaths);
- this.idReplacements = Collections.unmodifiableMap(replacements);
- this.levelPatchers = Collections.unmodifiableList(levelPatches);
- this.worldDataPatchers = Collections.unmodifiableList(worldDataPatches);
- this.statePatchers = Collections.unmodifiableList(statePatches);
- }
-
- /**
- * This method is supposed to be used by developers to apply id-patches to custom nbt structures. It is only
- * available in Developer-Mode
- */
- public static void fixCustomFolder(File dir) {
- if (!BCLib.isDevEnvironment()) return;
- MigrationProfile profile = Patch.createMigrationData();
- List nbts = getAllNbts(dir, null);
- nbts.parallelStream().forEach((file) -> {
- DataFixerAPI.LOGGER.info("Loading NBT " + file);
- try {
- CompoundTag root = NbtIo.readCompressed(file);
- boolean[] changed = {false};
- int spawnerIdx = -1;
- if (root.contains("palette")) {
- ListTag items = root.getList("palette", Tag.TAG_COMPOUND);
- for (int idx = 0; idx < items.size(); idx++) {
- final CompoundTag tag = (CompoundTag) items.get(idx);
- if (tag.contains("Name") && tag.getString("Name").equals("minecraft:spawner"))
- spawnerIdx = idx;
- if (tag.contains("Name") && (tag.getString("Name").equals("minecraft:") || tag.getString("Name")
- .equals(""))) {
- System.out.println("Empty Name");
- }
- if (tag.contains("id") && (tag.getString("id").equals("minecraft:") || tag.getString("id")
- .equals(""))) {
- System.out.println("Empty ID");
- }
- changed[0] |= profile.replaceStringFromIDs(tag, "Name");
- }
- }
-
- if (spawnerIdx >= 0 && root.contains("blocks")) {
- ListTag items = root.getList("blocks", Tag.TAG_COMPOUND);
- for (int idx = 0; idx < items.size(); idx++) {
- final CompoundTag blockTag = (CompoundTag) items.get(idx);
- if (blockTag.contains("state") && blockTag.getInt("state") == spawnerIdx && blockTag.contains(
- "nbt")) {
- CompoundTag nbt = blockTag.getCompound("nbt");
- if (nbt.contains("SpawnData")) {
- final CompoundTag entity = nbt.getCompound("SpawnData");
- if (!entity.contains("entity")) {
- CompoundTag data = new CompoundTag();
- data.put("entity", entity);
- nbt.put("SpawnData", data);
-
- changed[0] = true;
- }
- }
- if (nbt.contains("SpawnPotentials")) {
- ListTag pots = nbt.getList("SpawnPotentials", Tag.TAG_COMPOUND);
- for (Tag potItemIn : pots) {
- final CompoundTag potItem = (CompoundTag) potItemIn;
- if (potItem.contains("Weight")) {
- int weight = potItem.getInt("Weight");
- potItem.putInt("weight", weight);
- potItem.remove("Weight");
-
- changed[0] = true;
- }
-
- if (potItem.contains("Entity")) {
- CompoundTag entity = potItem.getCompound("Entity");
- CompoundTag data = new CompoundTag();
- data.put("entity", entity);
-
- potItem.put("data", data);
- potItem.remove("Entity");
-
- changed[0] = true;
- }
- }
- }
- }
- }
- }
-
- if (changed[0]) {
- DataFixerAPI.LOGGER.info("Writing NBT " + file);
- NbtIo.writeCompressed(root, file);
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- });
- }
-
- private static List getAllNbts(File dir, List list) {
- if (list == null) {
- list = new ArrayList<>();
- }
- for (File file : dir.listFiles()) {
- if (file.isDirectory()) {
- getAllNbts(file, list);
- } else if (file.isFile() && file.getName().endsWith(".nbt")) {
- list.add(file);
- }
- }
- return list;
- }
-
- final public CompoundTag getLevelDat(File levelBaseDir) {
- if (level == null || this.levelBaseDir == null || !this.levelBaseDir.equals(levelBaseDir)) {
- runPrePatches(levelBaseDir);
- }
- return level;
- }
-
- final public boolean isLevelDatChanged() {
- return prePatchChangedLevelDat;
- }
-
- final public File getLevelDatFile() {
- return new File(levelBaseDir, "level.dat");
- }
-
- final public Exception getPrePatchException() {
- return prePatchException;
- }
-
-
- final public void runPrePatches(File levelBaseDir) {
- if (didRunPrePatch) {
- BCLib.LOGGER.warning("Already did run PrePatches for " + this.levelBaseDir + ".");
- }
- BCLib.LOGGER.info("Running Pre Patchers on " + levelBaseDir);
-
- this.levelBaseDir = levelBaseDir;
- this.level = null;
- this.prePatchException = null;
- didRunPrePatch = true;
-
- this.prePatchChangedLevelDat = runPreLevelPatches(getLevelDatFile());
- }
-
- private boolean runPreLevelPatches(File levelDat) {
- try {
- level = NbtIo.readCompressed(levelDat);
-
- boolean changed = patchLevelDat(level);
- return changed;
- } catch (IOException | PatchDidiFailException e) {
- prePatchException = e;
- return false;
- }
- }
-
- final public void markApplied() {
- for (String modID : mods) {
- DataFixerAPI.LOGGER.info(
- "Updating Patch-Level for '{}' from {} to {}",
- modID,
- ModUtil.convertModVersion(currentPatchLevel(modID)),
- ModUtil.convertModVersion(Patch.maxPatchLevel(modID))
- );
- if (config != null)
- config.putString(modID, Patch.maxPatchVersion(modID));
- }
- }
-
- public String currentPatchVersion(@NotNull String modID) {
- if (config == null || !config.contains(modID)) return "0.0.0";
- return config.getString(modID);
- }
-
- public int currentPatchLevel(@NotNull String modID) {
- return ModUtil.convertModVersion(currentPatchVersion(modID));
- }
-
- public boolean hasAnyFixes() {
- boolean hasLevelDatPatches;
- if (didRunPrePatch != false) {
- hasLevelDatPatches = prePatchChangedLevelDat;
- } else {
- hasLevelDatPatches = levelPatchers.size() > 0;
- }
-
- return idReplacements.size() > 0 || hasLevelDatPatches || worldDataPatchers.size() > 0;
- }
-
- public String replaceStringFromIDs(@NotNull String val) {
- final String replace = idReplacements.get(val);
- return replace;
- }
-
- public boolean replaceStringFromIDs(@NotNull CompoundTag tag, @NotNull String key) {
- if (!tag.contains(key)) return false;
-
- final String val = tag.getString(key);
- final String replace = idReplacements.get(val);
-
- if (replace != null) {
- DataFixerAPI.LOGGER.warning("Replacing ID '{}' with '{}'.", val, replace);
- tag.putString(key, replace);
- return true;
- }
-
- return false;
- }
-
- private boolean replaceIDatPath(@NotNull ListTag list, @NotNull String[] parts, int level) {
- boolean[] changed = {false};
- if (level == parts.length - 1) {
- DataFixerAPI.fixItemArrayWithID(list, changed, this, true);
- } else {
- list.forEach(inTag -> changed[0] |= replaceIDatPath((CompoundTag) inTag, parts, level + 1));
- }
- return changed[0];
- }
-
- private boolean replaceIDatPath(@NotNull CompoundTag tag, @NotNull String[] parts, int level) {
- boolean changed = false;
- for (int i = level; i < parts.length - 1; i++) {
- final String part = parts[i];
- if (tag.contains(part)) {
- final byte type = tag.getTagType(part);
- if (type == Tag.TAG_LIST) {
- ListTag list = tag.getList(part, Tag.TAG_COMPOUND);
- return replaceIDatPath(list, parts, i);
- } else if (type == Tag.TAG_COMPOUND) {
- tag = tag.getCompound(part);
- }
- } else {
- return false;
- }
- }
-
- if (tag != null && parts.length > 0) {
- final String key = parts[parts.length - 1];
- final byte type = tag.getTagType(key);
- if (type == Tag.TAG_LIST) {
- final ListTag list = tag.getList(key, Tag.TAG_COMPOUND);
- final boolean[] _changed = {false};
- if (list.size() == 0) {
- _changed[0] = DataFixerAPI.fixStringIDList(tag, key, this);
- } else {
- DataFixerAPI.fixItemArrayWithID(list, _changed, this, true);
- }
- return _changed[0];
- } else if (type == Tag.TAG_STRING) {
- return replaceStringFromIDs(tag, key);
- } else if (type == Tag.TAG_COMPOUND) {
- final CompoundTag cTag = tag.getCompound(key);
- boolean[] _changed = {false};
- DataFixerAPI.fixID(cTag, _changed, this, true);
- return _changed[0];
- }
- }
-
-
- return false;
- }
-
- public boolean replaceIDatPath(@NotNull CompoundTag root, @NotNull String path) {
- String[] parts = path.split("\\.");
- return replaceIDatPath(root, parts, 0);
- }
-
- public boolean patchLevelDat(@NotNull CompoundTag level) throws PatchDidiFailException {
- boolean changed = false;
- for (PatchFunction f : levelPatchers) {
- changed |= f.apply(level, this);
- }
- return changed;
- }
-
- public void patchWorldData() throws PatchDidiFailException {
- for (Patch patch : worldDataPatchers) {
- CompoundTag root = WorldConfig.getRootTag(patch.modID);
- boolean changed = patch.getWorldDataPatcher().apply(root, this);
- if (changed) {
- WorldConfig.saveFile(patch.modID);
- }
- }
-
- for (Map.Entry> entry : worldDataIDPaths.entrySet()) {
- CompoundTag root = WorldConfig.getRootTag(entry.getKey());
- boolean[] changed = {false};
- entry.getValue().forEach(path -> {
- changed[0] |= replaceIDatPath(root, path);
- });
-
- if (changed[0]) {
- WorldConfig.saveFile(entry.getKey());
- }
- }
- }
-
- public boolean patchBlockState(ListTag palette, ListTag states) throws PatchDidiFailException {
- boolean changed = false;
- for (PatchBiFunction f : statePatchers) {
- changed |= f.apply(palette, states, this);
- }
- return changed;
- }
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/datafixer/Patch.java b/src/main/java/org/betterx/bclib/api/v2/datafixer/Patch.java
deleted file mode 100644
index cadf2ec3..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/datafixer/Patch.java
+++ /dev/null
@@ -1,237 +0,0 @@
-package org.betterx.bclib.api.v2.datafixer;
-
-import org.betterx.bclib.interfaces.PatchBiFunction;
-import org.betterx.bclib.interfaces.PatchFunction;
-import org.betterx.worlds.together.util.ModUtil;
-
-import net.minecraft.nbt.CompoundTag;
-import net.minecraft.nbt.ListTag;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import org.jetbrains.annotations.NotNull;
-
-public abstract class Patch {
- private static final List ALL = new ArrayList<>(10);
-
- /**
- * The Patch-Level derived from {@link #version}
- */
- public final int level;
-
- /**
- * The Patch-Version string
- */
- public final String version;
-
- /**
- * The Mod-ID that registered this Patch
- */
-
- @NotNull
- public final String modID;
-
- /**
- * This Mod is tested for each level start
- */
- public final boolean alwaysApply;
-
- static List getALL() {
- return ALL;
- }
-
- /**
- * Returns the highest Patch-Version that is available for the given mod. If no patches were
- * registerd for the mod, this will return 0.0.0
- *
- * @param modID The ID of the mod you want to query
- * @return The highest Patch-Version that was found
- */
- public static String maxPatchVersion(@NotNull String modID) {
- return ALL.stream().filter(p -> p.modID.equals(modID)).map(p -> p.version).reduce((p, c) -> c).orElse("0.0.0");
- }
-
- /**
- * Returns the highest patch-level that is available for the given mod. If no patches were
- * registerd for the mod, this will return 0
- *
- * @param modID The ID of the mod you want to query
- * @return The highest Patch-Level that was found
- */
- public static int maxPatchLevel(@NotNull String modID) {
- return ALL.stream().filter(p -> p.modID.equals(modID)).mapToInt(p -> p.level).max().orElse(0);
- }
-
- /**
- * Called by inheriting classes.
- *
- * Performs some sanity checks on the values and might throw a #RuntimeException if any
- * inconsistencies are found.
- *
- * @param modID The ID of the Mod you want to register a patch for. This should be your
- * ModID only. The ModID can not be {@code null} or an empty String.
- * @param version The mod-version that introduces the patch. This needs Semantic-Version String
- * like x.x.x. Developers are responsible for registering their patches in the correct
- * order (with increasing versions). You are not allowed to register a new
- * Patch with a version lower or equal than
- * {@link Patch#maxPatchVersion(String)}
- */
- protected Patch(@NotNull String modID, String version) {
- this(modID, version, false);
- }
-
- /**
- * Internal Constructor used to create patches that can allways run (no matter what patchlevel a level has)
- *
- * @param modID The ID of the Mod
- * @param version The mod-version that introduces the patch. When {@Code runAllways} is set, this version will
- * determine the patchlevel that is written to the level
- * @param alwaysApply When true, this patch is always active, no matter the patchlevel of the world.
- * This should be used sparingly and just for patches that apply to level.dat (as they only take
- * effect when changes are detected). Use {@link ForcedLevelPatch} to instatiate.
- */
- Patch(@NotNull String modID, String version, boolean alwaysApply) {
- //Patchlevels need to be unique and registered in ascending order
- if (modID == null || modID.isEmpty()) {
- throw new RuntimeException("[INTERNAL ERROR] Patches need a valid modID!");
- }
-
- if (version == null || version.isEmpty()) {
- throw new RuntimeException("Invalid Mod-Version");
- }
-
- this.version = version;
- this.alwaysApply = alwaysApply;
- this.level = ModUtil.convertModVersion(version);
- if (!ALL.stream().filter(p -> p.modID.equals(modID)).noneMatch(p -> p.level >= this.level) || this.level <= 0) {
- throw new RuntimeException(
- "[INTERNAL ERROR] Patch-levels need to be created in ascending order beginning with 1.");
- }
-
- this.modID = modID;
- }
-
- @Override
- public String toString() {
- return "Patch{" + modID + ':' + version + ':' + level + '}';
- }
-
-
- /**
- * Return block data fixes. Fixes will be applied on world load if current patch-level for
- * the linked mod is lower than the {@link #level}.
- *
- * The default implementation of this method returns an empty map.
- *
- * @return The returned Map should contain the replacements. All occurences of the
- * {@code KeySet} are replaced with the associated value.
- */
- public Map getIDReplacements() {
- return new HashMap();
- }
-
- /**
- * Return a {@link PatchFunction} that is called with the content of level.dat.
- *
- * The function needs to return {@code true}, if changes were made to the data.
- * If an error occurs, the method should throw a {@link PatchDidiFailException}
- *
- * The default implementation of this method returns null.
- *
- * @return {@code true} if changes were applied and we need to save the data
- */
- public PatchFunction getLevelDatPatcher() {
- return null;
- }
-
- /**
- * Return a {@link PatchFunction} that is called with the content from the
- * {@link org.betterx.worlds.together.world.WorldConfig} for this Mod.
- * The function needs to return {@code true}, if changes were made to the data.
- * If an error occurs, the method should throw a {@link PatchDidiFailException}
- *
- * The default implementation of this method returns null.
- *
- * @return {@code true} if changes were applied and we need to save the data
- */
- public PatchFunction getWorldDataPatcher() {
- return null;
- }
-
- /**
- * Return a {@link PatchBiFunction} that is called with pallette and blockstate of
- * each chunk in every region. This method is called AFTER all ID replacements
- * from {@link #getIDReplacements()} were applied to the pallete.
- *
- * The first parameter is the palette and the second is the blockstate.
- *
- * The function needs to return {@code true}, if changes were made to the data.
- * If an error occurs, the method should throw a {@link PatchDidiFailException}
- *
- * The default implementation of this method returns null.
- *
- * @return {@code true} if changes were applied and we need to save the data
- */
- public PatchBiFunction getBlockStatePatcher() {
- return null;
- }
-
- /**
- * Generates ready to use data for all currently registered patches. The list of
- * patches is selected by the current patch-level of the world.
- *
- * A {@link #Patch} with a given {@link #level} is only included if the patch-level of the
- * world is less
- *
- * @param config The current patch-level configuration*
- * @return a new {@link MigrationProfile} Object.
- */
- static MigrationProfile createMigrationData(CompoundTag config) {
- return new MigrationProfile(config, false);
- }
-
- /**
- * This method is supposed to be used by developers to apply id-patches to custom nbt structures. It is only
- * available in Developer-Mode
- */
- static MigrationProfile createMigrationData() {
- return new MigrationProfile(null, true);
- }
-
- /**
- * Returns a list of paths where your mod stores IDs in your {@link org.betterx.worlds.together.world.WorldConfig}-File.
- *
- * {@link DataFixerAPI} will use information from the latest patch that returns a non-null-result. This list is used
- * to automatically fix changed IDs from all active patches (see {@link Patch#getIDReplacements()}
- *
- * The end of the path can either be a {@link net.minecraft.nbt.StringTag}, a {@link net.minecraft.nbt.ListTag} or
- * a {@link CompoundTag}. If the Path contains a non-leaf {@link net.minecraft.nbt.ListTag}, all members of that
- * list will be processed. For example:
- *
- * - global +
- * | - key (String)
- * | - items (List) +
- * | - { id (String) }
- * | - { id (String) }
- *
- * The path global.items.id will fix all id-entries in the items-list, while the path
- * global.key will only fix the key-entry.
- *
- * if the leaf-entry (= the last part of the path, which would be items in global.items) is a
- * {@link CompoundTag}, the system will fix any id entry. If the {@link CompoundTag} contains an item
- * or tag.BlockEntityTag entry, the system will recursivley continue with those. If an items
- * or inventory-{@link net.minecraft.nbt.ListTag} was found, the system will continue recursivley with
- * every item of that list.
- *
- * if the leaf-entry is a {@link net.minecraft.nbt.ListTag}, it is handle the same as a child items entry
- * of a {@link CompoundTag}.
- *
- * @return {@code null} if nothing changes or a list of Paths in your {@link org.betterx.worlds.together.world.WorldConfig}-File.
- * Paths are dot-seperated (see {@link org.betterx.worlds.together.world.WorldConfig#getCompoundTag(String, String)}).
- */
- public List getWorldDataIDPaths() {
- return null;
- }
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/datafixer/PatchDidiFailException.java b/src/main/java/org/betterx/bclib/api/v2/datafixer/PatchDidiFailException.java
deleted file mode 100644
index 053d29fe..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/datafixer/PatchDidiFailException.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package org.betterx.bclib.api.v2.datafixer;
-
-public class PatchDidiFailException extends Exception {
- public PatchDidiFailException() {
- super();
- }
-
- public PatchDidiFailException(Exception e) {
- super(e);
- }
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/generator/BCLBiomeSource.java b/src/main/java/org/betterx/bclib/api/v2/generator/BCLBiomeSource.java
deleted file mode 100644
index 56c40309..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/generator/BCLBiomeSource.java
+++ /dev/null
@@ -1,299 +0,0 @@
-package org.betterx.bclib.api.v2.generator;
-
-import org.betterx.bclib.BCLib;
-import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiome;
-import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiomeRegistry;
-import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI;
-import org.betterx.bclib.config.Configs;
-import org.betterx.worlds.together.biomesource.BiomeSourceFromRegistry;
-import org.betterx.worlds.together.biomesource.BiomeSourceHelper;
-import org.betterx.worlds.together.biomesource.MergeableBiomeSource;
-import org.betterx.worlds.together.biomesource.ReloadableBiomeSource;
-import org.betterx.worlds.together.world.BiomeSourceWithNoiseRelatedSettings;
-import org.betterx.worlds.together.world.BiomeSourceWithSeed;
-import org.betterx.worlds.together.world.event.WorldBootstrap;
-
-import net.minecraft.core.Holder;
-import net.minecraft.core.HolderGetter;
-import net.minecraft.core.Registry;
-import net.minecraft.core.RegistryAccess;
-import net.minecraft.core.registries.Registries;
-import net.minecraft.resources.ResourceKey;
-import net.minecraft.world.level.biome.Biome;
-import net.minecraft.world.level.biome.BiomeSource;
-import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
-
-import com.google.common.collect.Sets;
-
-import java.util.*;
-import org.jetbrains.annotations.NotNull;
-
-public abstract class BCLBiomeSource extends BiomeSource implements BiomeSourceWithSeed, MergeableBiomeSource, BiomeSourceWithNoiseRelatedSettings, ReloadableBiomeSource, BiomeSourceFromRegistry {
- @FunctionalInterface
- public interface PickerAdder {
- boolean add(BCLBiome bclBiome, BiomeAPI.BiomeType type, BiomePicker picker);
- }
-
- @FunctionalInterface
- public interface CustomTypeFinder {
- BiomeAPI.BiomeType find(ResourceKey biomeKey, BiomeAPI.BiomeType defaultType);
- }
-
- protected long currentSeed;
- protected int maxHeight;
- private boolean didCreatePickers;
- Set> dynamicPossibleBiomes;
-
- protected BCLBiomeSource(long seed) {
- super(List.of());
- this.dynamicPossibleBiomes = Set.of();
- this.currentSeed = seed;
- this.didCreatePickers = false;
- }
-
- @Override
- public Set> possibleBiomes() {
- return dynamicPossibleBiomes;
- }
-
- @Override
- public boolean didBiomeRegistryChange() {
- return false;
- //return this.registryModificationCounter != InternalBiomeAPI.getBiomeRegistryModificationCount(biomeRegistry);
- }
-
- protected boolean wasBound() {
- return didCreatePickers;
- }
-
- final public void setSeed(long seed) {
- if (seed != currentSeed) {
- BCLib.LOGGER.debug(this + "\n --> new seed = " + seed);
- this.currentSeed = seed;
- initMap(seed);
- }
- }
-
- /**
- * Set world height
- *
- * @param maxHeight height of the World.
- */
- final public void setMaxHeight(int maxHeight) {
- if (this.maxHeight != maxHeight) {
- BCLib.LOGGER.debug(this + "\n --> new height = " + maxHeight);
- this.maxHeight = maxHeight;
- onHeightChange(maxHeight);
- }
- }
-
- protected final void initMap(long seed) {
- BCLib.LOGGER.debug(this + "\n --> Map Update");
- onInitMap(seed);
- }
-
- protected abstract void onInitMap(long newSeed);
- protected abstract void onHeightChange(int newHeight);
-
- public BCLBiomeSource createCopyForDatapack(Set> datapackBiomes) {
- Set> mutableSet = Sets.newHashSet();
- mutableSet.addAll(datapackBiomes);
- return cloneForDatapack(mutableSet);
- }
-
- protected abstract BCLBiomeSource cloneForDatapack(Set> datapackBiomes);
-
- @NotNull
- protected String getNamespaces() {
- return BiomeSourceHelper.getNamespaces(possibleBiomes());
- }
-
-// public interface ValidBiomePredicate {
-// boolean isValid(Holder biome, ResourceLocation location);
-// }
-
- protected boolean addToPicker(BCLBiome bclBiome, BiomeAPI.BiomeType type, BiomePicker picker) {
- picker.addBiome(bclBiome);
- return true;
- }
-
- protected BiomeAPI.BiomeType typeForUnknownBiome(ResourceKey biomeKey, BiomeAPI.BiomeType defaultType) {
- return defaultType;
- }
-
-
- protected static Set> populateBiomePickers(
- Map acceptedBiomeTypes,
- BiomeAPI.BiomeType exclusionListType,
- PickerAdder pickerAdder,
- CustomTypeFinder typeFinder
- ) {
- final RegistryAccess access = WorldBootstrap.getLastRegistryAccess();
- if (access == null) {
- if (Configs.MAIN_CONFIG.verboseLogging() && !BCLib.isDatagen()) {
- BCLib.LOGGER.info("Unable to build Biome List yet");
- }
- return null;
- }
-
- final Set> allBiomes = new HashSet<>();
- final Map> includeMap = Configs.BIOMES_CONFIG.getBiomeIncludeMap();
- final List excludeList = Configs.BIOMES_CONFIG.getExcludeMatching(exclusionListType);
- final Registry biomes = access.registryOrThrow(Registries.BIOME);
- final Registry bclBiomes = access.registryOrThrow(BCLBiomeRegistry.BCL_BIOMES_REGISTRY);
-
- final List, Biome>> sortedList = biomes
- .entrySet()
- .stream()
- .sorted(Comparator.comparing(a -> a.getKey().location().toString()))
- .toList();
-
- for (Map.Entry, Biome> biomeEntry : sortedList) {
- if (excludeList.contains(biomeEntry.getKey().location())) continue;
-
- BiomeAPI.BiomeType type = BiomeAPI.BiomeType.NONE;
- boolean foundBCLBiome = false;
- if (BCLBiomeRegistry.hasBiome(biomeEntry.getKey(), bclBiomes)) {
- foundBCLBiome = true;
- type = BCLBiomeRegistry.getBiome(biomeEntry.getKey(), bclBiomes).getIntendedType();
- } else {
- type = typeFinder.find(biomeEntry.getKey(), type);
- }
-
- type = getBiomeType(includeMap, biomeEntry.getKey(), type);
-
- for (Map.Entry pickerEntry : acceptedBiomeTypes.entrySet()) {
- if (type.is(pickerEntry.getKey())) {
- BCLBiome bclBiome;
- if (foundBCLBiome) {
- bclBiome = BCLBiomeRegistry.getBiome(biomeEntry.getKey(), bclBiomes);
- } else {
- //create and register a biome wrapper
- bclBiome = new BCLBiome(biomeEntry.getKey().location(), type);
- BCLBiomeRegistry.register(bclBiome);
- foundBCLBiome = true;
- }
-
- boolean isPossible;
- if (!bclBiome.hasParentBiome()) {
- isPossible = pickerAdder.add(bclBiome, pickerEntry.getKey(), pickerEntry.getValue());
- } else {
- isPossible = true;
- }
-
- if (isPossible) {
- allBiomes.add(biomes.getHolderOrThrow(biomeEntry.getKey()));
- }
- }
- }
- }
-
-
- return allBiomes;
- }
-
- protected abstract BiomeAPI.BiomeType defaultBiomeType();
- protected abstract Map createFreshPickerMap();
-
- public abstract String toShortString();
-
- protected void onFinishBiomeRebuild(Map pickerMap) {
- for (var picker : pickerMap.values()) {
- picker.rebuild();
- }
- }
-
- protected final void rebuildBiomes(boolean force) {
- if (!force && didCreatePickers) return;
-
- if (Configs.MAIN_CONFIG.verboseLogging()) {
- BCLib.LOGGER.info("Updating Pickers for " + this.toShortString());
- }
-
- Map pickerMap = createFreshPickerMap();
- this.dynamicPossibleBiomes = populateBiomePickers(
- pickerMap,
- defaultBiomeType(),
- this::addToPicker,
- this::typeForUnknownBiome
- );
- if (this.dynamicPossibleBiomes == null) {
- this.dynamicPossibleBiomes = Set.of();
- } else {
- this.didCreatePickers = true;
- }
-
- onFinishBiomeRebuild(pickerMap);
- }
-
- @Override
- public BCLBiomeSource mergeWithBiomeSource(BiomeSource inputBiomeSource) {
- final RegistryAccess access = WorldBootstrap.getLastRegistryAccess();
- if (access == null) {
- BCLib.LOGGER.error("Unable to merge Biomesources!");
- return this;
- }
-
- final Map> includeMap = Configs.BIOMES_CONFIG.getBiomeIncludeMap();
- final List excludeList = Configs.BIOMES_CONFIG.getExcludeMatching(defaultBiomeType());
- final Registry bclBiomes = access.registryOrThrow(BCLBiomeRegistry.BCL_BIOMES_REGISTRY);
-
- for (Holder possibleBiome : inputBiomeSource.possibleBiomes()) {
- ResourceKey key = possibleBiome.unwrapKey().orElse(null);
- if (key != null) {
- //skip over all biomes that were excluded in the config
- if (excludeList.contains(key.location())) continue;
-
- //this is a biome that has no type entry => create a new one for the default type of this registry
- if (!BCLBiomeRegistry.hasBiome(key, bclBiomes)) {
- BiomeAPI.BiomeType type = typeForUnknownBiome(key, defaultBiomeType());
-
- //check if there was an override defined in the configs
- type = getBiomeType(includeMap, key, type);
-
- //create and register a biome wrapper
- BCLBiome bclBiome = new BCLBiome(key.location(), type);
- BCLBiomeRegistry.register(bclBiome);
- }
- }
- }
-
- this.reloadBiomes();
- return this;
- }
-
- private static BiomeAPI.BiomeType getBiomeType(
- Map> includeMap,
- ResourceKey biomeKey,
- BiomeAPI.BiomeType defaultType
- ) {
- for (Map.Entry> includeList : includeMap.entrySet()) {
- if (includeList.getValue().contains(biomeKey.location().toString())) {
- return includeList.getKey();
- }
- }
-
-
- return defaultType;
- }
-
- public void onLoadGeneratorSettings(NoiseGeneratorSettings generator) {
- this.setMaxHeight(generator.noiseSettings().height());
- }
-
- @Override
- public HolderGetter getBiomeRegistry() {
- //return biomeRegistry;
- return null;
- }
-
- protected void reloadBiomes(boolean force) {
- rebuildBiomes(force);
- this.initMap(currentSeed);
- }
-
- @Override
- public void reloadBiomes() {
- reloadBiomes(true);
- }
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/generator/BCLChunkGenerator.java b/src/main/java/org/betterx/bclib/api/v2/generator/BCLChunkGenerator.java
deleted file mode 100644
index 1c522619..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/generator/BCLChunkGenerator.java
+++ /dev/null
@@ -1,224 +0,0 @@
-package org.betterx.bclib.api.v2.generator;
-
-import org.betterx.bclib.BCLib;
-import org.betterx.bclib.api.v2.levelgen.LevelGenUtil;
-import org.betterx.bclib.interfaces.NoiseGeneratorSettingsProvider;
-import org.betterx.bclib.mixin.common.ChunkGeneratorAccessor;
-import org.betterx.worlds.together.WorldsTogether;
-import org.betterx.worlds.together.biomesource.MergeableBiomeSource;
-import org.betterx.worlds.together.biomesource.ReloadableBiomeSource;
-import org.betterx.worlds.together.chunkgenerator.EnforceableChunkGenerator;
-import org.betterx.worlds.together.chunkgenerator.InjectableSurfaceRules;
-import org.betterx.worlds.together.chunkgenerator.RestorableBiomeSource;
-import org.betterx.worlds.together.world.BiomeSourceWithNoiseRelatedSettings;
-
-import com.mojang.serialization.Codec;
-import com.mojang.serialization.codecs.RecordCodecBuilder;
-import net.minecraft.core.Holder;
-import net.minecraft.core.HolderGetter;
-import net.minecraft.core.Registry;
-import net.minecraft.core.RegistryAccess;
-import net.minecraft.core.registries.Registries;
-import net.minecraft.data.worldgen.BootstapContext;
-import net.minecraft.data.worldgen.SurfaceRuleData;
-import net.minecraft.resources.ResourceKey;
-import net.minecraft.world.level.biome.Biome;
-import net.minecraft.world.level.biome.BiomeGenerationSettings;
-import net.minecraft.world.level.biome.BiomeSource;
-import net.minecraft.world.level.biome.FeatureSorter;
-import net.minecraft.world.level.block.Blocks;
-import net.minecraft.world.level.chunk.ChunkGenerator;
-import net.minecraft.world.level.dimension.DimensionType;
-import net.minecraft.world.level.dimension.LevelStem;
-import net.minecraft.world.level.levelgen.*;
-
-import com.google.common.base.Suppliers;
-
-import java.util.List;
-import java.util.function.Function;
-
-public class BCLChunkGenerator extends NoiseBasedChunkGenerator implements RestorableBiomeSource, InjectableSurfaceRules, EnforceableChunkGenerator {
-
- public static final Codec CODEC = RecordCodecBuilder
- .create((RecordCodecBuilder.Instance builderInstance) -> {
-
- RecordCodecBuilder biomeSourceCodec = BiomeSource.CODEC
- .fieldOf("biome_source")
- .forGetter((BCLChunkGenerator generator) -> generator.biomeSource);
-
- RecordCodecBuilder> settingsCodec = NoiseGeneratorSettings.CODEC
- .fieldOf("settings")
- .forGetter((BCLChunkGenerator generator) -> generator.generatorSettings());
-
-
- return builderInstance.group(biomeSourceCodec, settingsCodec)
- .apply(builderInstance, builderInstance.stable(BCLChunkGenerator::new));
- });
- protected static final NoiseSettings NETHER_NOISE_SETTINGS_AMPLIFIED = NoiseSettings.create(0, 256, 1, 4);
- public static final ResourceKey AMPLIFIED_NETHER = ResourceKey.create(
- Registries.NOISE_SETTINGS,
- BCLib.makeID("amplified_nether")
- );
-
- public final BiomeSource initialBiomeSource;
-
- public BCLChunkGenerator(
- BiomeSource biomeSource,
- Holder holder
- ) {
- super(biomeSource, holder);
- initialBiomeSource = biomeSource;
- if (biomeSource instanceof BiomeSourceWithNoiseRelatedSettings bcl && holder.isBound()) {
- bcl.onLoadGeneratorSettings(holder.value());
- }
-
- if (WorldsTogether.RUNS_TERRABLENDER) {
- BCLib.LOGGER.info("Make sure features are loaded from terrablender" + biomeSource);
-
- //terrablender is invalidating the feature initialization
- //we redo it at this point, otherwise we will get blank biomes
- rebuildFeaturesPerStep(biomeSource);
- }
- }
-
- private void rebuildFeaturesPerStep(BiomeSource biomeSource) {
- if (this instanceof ChunkGeneratorAccessor acc) {
- Function, BiomeGenerationSettings> function = (Holder hh) -> hh.value()
- .getGenerationSettings();
-
- acc.bcl_setFeaturesPerStep(Suppliers.memoize(() -> FeatureSorter.buildFeaturesPerStep(
- List.copyOf(biomeSource.possibleBiomes()),
- (hh) -> function.apply(hh).features(),
- true
- )));
- }
- }
-
- /**
- * Other Mods like TerraBlender might inject new BiomeSources. We und that change after the world setup did run.
- *
- * @param dimensionKey The Dimension where this ChunkGenerator is used from
- */
- @Override
- public void restoreInitialBiomeSource(ResourceKey dimensionKey) {
- if (initialBiomeSource != getBiomeSource()) {
- if (this instanceof ChunkGeneratorAccessor acc) {
- if (initialBiomeSource instanceof MergeableBiomeSource bs) {
- acc.bcl_setBiomeSource(bs.mergeWithBiomeSource(getBiomeSource()));
- } else if (initialBiomeSource instanceof ReloadableBiomeSource bs) {
- bs.reloadBiomes();
- }
-
- rebuildFeaturesPerStep(getBiomeSource());
- }
- }
- }
-
-
- @Override
- protected Codec extends ChunkGenerator> codec() {
- return CODEC;
- }
-
- @Override
- public String toString() {
- return "BCLib - Chunk Generator (" + Integer.toHexString(hashCode()) + ")";
- }
-
- // This method is injected by Terrablender.
- // We make sure terrablender does not rewrite the feature-set for our ChunkGenerator by overwriting the
- // Mixin-Method with an empty implementation
- public void appendFeaturesPerStep() {
- }
-
- @Override
- public Registry enforceGeneratorInWorldGenSettings(
- RegistryAccess access,
- ResourceKey dimensionKey,
- ResourceKey dimensionTypeKey,
- ChunkGenerator loadedChunkGenerator,
- Registry dimensionRegistry
- ) {
- BCLib.LOGGER.info("Enforcing Correct Generator for " + dimensionKey.location().toString() + ".");
-
- ChunkGenerator referenceGenerator = this;
- if (loadedChunkGenerator instanceof org.betterx.bclib.interfaces.ChunkGeneratorAccessor generator) {
- if (loadedChunkGenerator instanceof NoiseGeneratorSettingsProvider noiseProvider) {
- if (referenceGenerator instanceof NoiseGeneratorSettingsProvider referenceProvider) {
- final BiomeSource bs;
- if (referenceGenerator.getBiomeSource() instanceof MergeableBiomeSource mbs) {
- bs = mbs.mergeWithBiomeSource(loadedChunkGenerator.getBiomeSource());
- } else {
- bs = referenceGenerator.getBiomeSource();
- }
-
- referenceGenerator = new BCLChunkGenerator(
- bs,
- buildGeneratorSettings(
- referenceProvider.bclib_getNoiseGeneratorSettingHolders(),
- noiseProvider.bclib_getNoiseGeneratorSettingHolders(),
- bs
- )
- );
- }
- }
- }
-
- return LevelGenUtil.replaceGenerator(
- dimensionKey,
- dimensionTypeKey,
- access,
- dimensionRegistry,
- referenceGenerator
- );
-
- }
-
- private static Holder buildGeneratorSettings(
- Holder reference,
- Holder settings,
- BiomeSource biomeSource
- ) {
- return settings;
-// NoiseGeneratorSettings old = settings.value();
-// NoiseGeneratorSettings noise = new NoiseGeneratorSettings(
-// old.noiseSettings(),
-// old.defaultBlock(),
-// old.defaultFluid(),
-// old.noiseRouter(),
-// SurfaceRuleRegistry.mergeSurfaceRulesFromBiomes(old.surfaceRule(), biomeSource),
-// //SurfaceRuleUtil.addRulesForBiomeSource(old.surfaceRule(), biomeSource),
-// old.spawnTarget(),
-// old.seaLevel(),
-// old.disableMobGeneration(),
-// old.aquifersEnabled(),
-// old.oreVeinsEnabled(),
-// old.useLegacyRandomSource()
-// );
-//
-//
-// return Holder.direct(noise);
- }
-
-
- public static NoiseGeneratorSettings amplifiedNether(BootstapContext bootstapContext) {
- HolderGetter densityGetter = bootstapContext.lookup(Registries.DENSITY_FUNCTION);
- return new NoiseGeneratorSettings(
- NETHER_NOISE_SETTINGS_AMPLIFIED,
- Blocks.NETHERRACK.defaultBlockState(),
- Blocks.LAVA.defaultBlockState(),
- NoiseRouterData.noNewCaves(
- densityGetter,
- bootstapContext.lookup(Registries.NOISE),
- NoiseRouterData.slideNetherLike(densityGetter, 0, 256)
- ),
- SurfaceRuleData.nether(),
- List.of(),
- 32,
- false,
- false,
- false,
- true
- );
- }
-}
diff --git a/src/main/java/org/betterx/bclib/api/v2/generator/BCLibEndBiomeSource.java b/src/main/java/org/betterx/bclib/api/v2/generator/BCLibEndBiomeSource.java
deleted file mode 100644
index ff5d40d5..00000000
--- a/src/main/java/org/betterx/bclib/api/v2/generator/BCLibEndBiomeSource.java
+++ /dev/null
@@ -1,565 +0,0 @@
-package org.betterx.bclib.api.v2.generator;
-
-import org.betterx.bclib.BCLib;
-import org.betterx.bclib.api.v2.generator.config.BCLEndBiomeSourceConfig;
-import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiome;
-import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiomeRegistry;
-import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI;
-import org.betterx.bclib.config.Configs;
-import org.betterx.bclib.interfaces.BiomeMap;
-import org.betterx.worlds.together.biomesource.BiomeSourceWithConfig;
-
-import com.mojang.serialization.Codec;
-import com.mojang.serialization.codecs.RecordCodecBuilder;
-import net.minecraft.core.*;
-import net.minecraft.core.registries.BuiltInRegistries;
-import net.minecraft.core.registries.Registries;
-import net.minecraft.resources.RegistryOps;
-import net.minecraft.resources.ResourceKey;
-import net.minecraft.resources.ResourceLocation;
-import net.minecraft.tags.BiomeTags;
-import net.minecraft.world.level.biome.Biome;
-import net.minecraft.world.level.biome.BiomeSource;
-import net.minecraft.world.level.biome.Biomes;
-import net.minecraft.world.level.biome.Climate;
-import net.minecraft.world.level.levelgen.DensityFunction;
-
-import java.awt.*;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import org.jetbrains.annotations.NotNull;
-
-public class BCLibEndBiomeSource extends BCLBiomeSource implements BiomeSourceWithConfig {
- public static Codec CODEC
- = RecordCodecBuilder.create((instance) -> instance
- .group(
- RegistryOps.retrieveGetter(Registries.BIOME),
- RegistryOps.retrieveGetter(BCLBiomeRegistry.BCL_BIOMES_REGISTRY),
- Codec
- .LONG
- .fieldOf("seed")
- .stable()
- .forGetter(source -> source.currentSeed),
- BCLEndBiomeSourceConfig
- .CODEC
- .fieldOf("config")
- .orElse(BCLEndBiomeSourceConfig.DEFAULT)
- .forGetter(o -> o.config)
- )
- .apply(
- instance,
- instance.stable(BCLibEndBiomeSource::new)
- )
- );
- private final Point pos;
- private BiomeMap mapLand;
- private BiomeMap mapVoid;
- private BiomeMap mapCenter;
- private BiomeMap mapBarrens;
-
- private BiomePicker endLandBiomePicker;
- private BiomePicker endVoidBiomePicker;
- private BiomePicker endCenterBiomePicker;
- private BiomePicker endBarrensBiomePicker;
- private List deciders;
-
- private BCLEndBiomeSourceConfig config;
-
- private BCLibEndBiomeSource(
- HolderGetter biomeRegistry,
- HolderGetter bclBiomeRegistry,
- long seed,
- BCLEndBiomeSourceConfig config
- ) {
- this(biomeRegistry, bclBiomeRegistry, seed, config, true);
- }
-
- public BCLibEndBiomeSource(
- HolderGetter biomeRegistry,
- HolderGetter bclBiomeRegistry,
- BCLEndBiomeSourceConfig config
- ) {
- this(biomeRegistry, bclBiomeRegistry, 0, config, false);
- }
-
- private BCLibEndBiomeSource(
- HolderGetter biomeRegistry,
- HolderGetter bclBiomeRegistry,
- long seed,
- BCLEndBiomeSourceConfig config,
- boolean initMaps
- ) {
- this(biomeRegistry, bclBiomeRegistry, null, seed, config, initMaps);
- }
-
- private BCLibEndBiomeSource(
- HolderGetter