package com.cimeyclust.ezcheat.client; import com.cimeyclust.ezcheat.Ezcheat; import com.cimeyclust.ezcheat.EzcheatPayload; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.loader.api.FabricLoader; import org.apache.commons.codec.digest.DigestUtils; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; public class EzcheatClient implements ClientModInitializer { @Override public void onInitializeClient() { ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> { if (!client.isInSingleplayer()) { this.sendHashes(); } }); } /** Called client‑side to compute & send hashes */ private void sendHashes() { // gather mod files Path modsDir = FabricLoader.getInstance() .getGameDir() .resolve("mods") .toAbsolutePath(); Map hashes = new HashMap<>(); for (var mod : FabricLoader.getInstance().getAllMods()) { try { Path path = null; var paths = mod.getOrigin().getPaths(); for (Path p : paths) { if (Files.isRegularFile(p)) { path = p; break; } } if (path == null) { Ezcheat.LOGGER.debug("Skipping mod {}: No valid path", mod.getMetadata().getId()); continue; } if (path.startsWith(modsDir)) { try (InputStream in = Files.newInputStream(path)) { hashes.put(mod.getMetadata().getId(), DigestUtils.sha256Hex(in)); } } } catch (IOException e) { Ezcheat.LOGGER.warn("Could not hash {}: {}", mod.getMetadata().getId(), e.getMessage()); } } EzcheatPayload payload = new EzcheatPayload(hashes); ClientPlayNetworking.send(payload); } }