package com.cimeyclust.ezcheat; import com.google.common.reflect.TypeToken; import com.google.gson.Gson; import com.mojang.logging.LogUtils; import net.minecraft.client.Minecraft; import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.food.FoodProperties; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.CreativeModeTabs; import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.material.MapColor; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.BuildCreativeModeTabContentsEvent; import net.minecraftforge.event.server.ServerStartingEvent; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.config.ModConfig; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo; import net.minecraftforge.forgespi.language.IModInfo; import net.minecraftforge.network.NetworkRegistry; import net.minecraftforge.network.simple.SimpleChannel; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.RegistryObject; import org.apache.commons.codec.digest.DigestUtils; import org.slf4j.Logger; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Type; import java.net.HttpURLConnection; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.Optional; @Mod(Ezcheat.MODID) public class Ezcheat { public static final String MODID = "ezcheat"; // Directly reference a slf4j logger private static final Logger LOGGER = LogUtils.getLogger(); public static final String PROTOCOL_VERSION = "1"; public static final SimpleChannel NETWORK = NetworkRegistry.newSimpleChannel( new ResourceLocation(MODID, "main"), () -> PROTOCOL_VERSION, PROTOCOL_VERSION::equals, PROTOCOL_VERSION::equals ); public static Map getInstalledModHashes() { Map modHashes = new HashMap<>(); for (IModInfo mod : ModList.get().getMods()) { Optional modFile = Optional.ofNullable(mod.getOwningFile().getFile().getFilePath()); modFile.ifPresent(path -> { try (InputStream in = Files.newInputStream(path)) { String hash = DigestUtils.sha256Hex(in); // Apache Commons Codec modHashes.put(mod.getModId(), hash); } catch (IOException e) { LOGGER.error("Failed to read mod file for {}: {}", mod.getModId(), e.getMessage()); } }); } return modHashes; } public static void handlePlayerModHashes(ServerPlayer player, Map modHashes) { // Request an external whitelist MinecraftServer server = player.getServer(); if (server == null) return; server.execute(() -> { try { URL url = new URL(Config.modEndpointUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); InputStream in = conn.getInputStream(); String response = new String(in.readAllBytes()); in.close(); Gson gson = new Gson(); Type type = new TypeToken>() {}.getType(); Map allowedMods = gson.fromJson(response, type); StringBuilder unallowedMods = new StringBuilder("Unallowed mods: "); for (Map.Entry entry : modHashes.entrySet()) { String modid = entry.getKey(); String hash = entry.getValue(); if (!allowedMods.containsKey(modid) || !allowedMods.get(modid).equalsIgnoreCase(hash)) { unallowedMods.append(modid).append(", "); } } if (!unallowedMods.isEmpty()) { unallowedMods.setLength(unallowedMods.length() - 2); // Remove last comma and space player.connection.disconnect(Component.literal(unallowedMods.toString())); } } catch (IOException e) { Ezcheat.LOGGER.error("Modprüfung fehlgeschlagen", e); } }); } public Ezcheat() { ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, Config.SPEC); NETWORK.registerMessage(0, ModHashesPacket.class, ModHashesPacket::encode, ModHashesPacket::decode, ModHashesPacket::handle ); } // You can use SubscribeEvent and let the Event Bus discover methods to call @SubscribeEvent public void onServerStarting(ServerStartingEvent event) { } // You can use EventBusSubscriber to automatically register all static methods in the class annotated with @SubscribeEvent @Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) public static class ClientModEvents { @SubscribeEvent public static void onClientSetup(FMLClientSetupEvent event) { event.enqueueWork(() -> { if (Minecraft.getInstance().getConnection() != null) { Map modHashes = Ezcheat.getInstalledModHashes(); Ezcheat.NETWORK.sendToServer(new ModHashesPacket(modHashes)); } }); } } }