2025-05-10 23:05:51 +02:00
|
|
|
package com.cimeyclust.ezcheat;
|
|
|
|
|
|
2025-05-14 17:36:23 +02:00
|
|
|
import com.google.common.reflect.TypeToken;
|
|
|
|
|
import com.google.gson.Gson;
|
2025-05-10 23:05:51 +02:00
|
|
|
import com.mojang.logging.LogUtils;
|
|
|
|
|
import net.minecraft.client.Minecraft;
|
|
|
|
|
import net.minecraft.core.registries.Registries;
|
2025-05-14 17:36:23 +02:00
|
|
|
import net.minecraft.network.chat.Component;
|
|
|
|
|
import net.minecraft.resources.ResourceLocation;
|
|
|
|
|
import net.minecraft.server.MinecraftServer;
|
|
|
|
|
import net.minecraft.server.level.ServerPlayer;
|
2025-05-10 23:05:51 +02:00
|
|
|
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;
|
2025-05-14 17:36:23 +02:00
|
|
|
import net.minecraftforge.fml.ModList;
|
2025-05-10 23:05:51 +02:00
|
|
|
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;
|
2025-05-14 17:36:23 +02:00
|
|
|
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
|
|
|
|
|
import net.minecraftforge.forgespi.language.IModInfo;
|
|
|
|
|
import net.minecraftforge.network.NetworkRegistry;
|
|
|
|
|
import net.minecraftforge.network.simple.SimpleChannel;
|
2025-05-10 23:05:51 +02:00
|
|
|
import net.minecraftforge.registries.DeferredRegister;
|
|
|
|
|
import net.minecraftforge.registries.ForgeRegistries;
|
|
|
|
|
import net.minecraftforge.registries.RegistryObject;
|
2025-05-14 17:36:23 +02:00
|
|
|
import org.apache.commons.codec.digest.DigestUtils;
|
2025-05-10 23:05:51 +02:00
|
|
|
import org.slf4j.Logger;
|
|
|
|
|
|
2025-05-14 17:36:23 +02:00
|
|
|
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;
|
|
|
|
|
|
2025-05-10 23:05:51 +02:00
|
|
|
@Mod(Ezcheat.MODID)
|
|
|
|
|
public class Ezcheat {
|
|
|
|
|
public static final String MODID = "ezcheat";
|
2025-05-14 17:36:23 +02:00
|
|
|
|
2025-05-10 23:05:51 +02:00
|
|
|
// Directly reference a slf4j logger
|
|
|
|
|
private static final Logger LOGGER = LogUtils.getLogger();
|
|
|
|
|
|
2025-05-14 17:36:23 +02:00
|
|
|
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<String, String> getInstalledModHashes() {
|
|
|
|
|
Map<String, String> modHashes = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
for (IModInfo mod : ModList.get().getMods()) {
|
|
|
|
|
Optional<Path> 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());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-05-10 23:05:51 +02:00
|
|
|
|
2025-05-14 17:36:23 +02:00
|
|
|
return modHashes;
|
2025-05-10 23:05:51 +02:00
|
|
|
}
|
|
|
|
|
|
2025-05-14 17:36:23 +02:00
|
|
|
public static void handlePlayerModHashes(ServerPlayer player, Map<String, String> 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<Map<String, String>>() {}.getType();
|
|
|
|
|
Map<String, String> allowedMods = gson.fromJson(response, type);
|
|
|
|
|
|
|
|
|
|
StringBuilder unallowedMods = new StringBuilder("Unallowed mods: ");
|
|
|
|
|
for (Map.Entry<String, String> 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);
|
|
|
|
|
}
|
|
|
|
|
});
|
2025-05-10 23:05:51 +02:00
|
|
|
}
|
|
|
|
|
|
2025-05-14 17:36:23 +02:00
|
|
|
public Ezcheat() {
|
|
|
|
|
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, Config.SPEC);
|
|
|
|
|
|
|
|
|
|
NETWORK.registerMessage(0, ModHashesPacket.class,
|
|
|
|
|
ModHashesPacket::encode,
|
|
|
|
|
ModHashesPacket::decode,
|
|
|
|
|
ModHashesPacket::handle
|
|
|
|
|
);
|
2025-05-10 23:05:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// You can use SubscribeEvent and let the Event Bus discover methods to call
|
|
|
|
|
@SubscribeEvent
|
|
|
|
|
public void onServerStarting(ServerStartingEvent event) {
|
2025-05-14 17:36:23 +02:00
|
|
|
|
2025-05-10 23:05:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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) {
|
2025-05-14 17:36:23 +02:00
|
|
|
event.enqueueWork(() -> {
|
|
|
|
|
if (Minecraft.getInstance().getConnection() != null) {
|
|
|
|
|
Map<String, String> modHashes = Ezcheat.getInstalledModHashes();
|
|
|
|
|
Ezcheat.NETWORK.sendToServer(new ModHashesPacket(modHashes));
|
|
|
|
|
}
|
|
|
|
|
});
|
2025-05-10 23:05:51 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|