package com.vinlanx.explosionoverhaul; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import com.mojang.logging.LogUtils; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.Reader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import net.minecraft.core.particles.BlockParticleOption; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; import net.neoforged.bus.api.IEventBus; import net.neoforged.fml.ModContainer; import net.neoforged.fml.common.Mod; import net.neoforged.fml.config.ModConfig; import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; import org.slf4j.Logger; @Mod(ExplosionOverhaul.MODID) public class ExplosionOverhaul { public static final String MODID = "explosionoverhaul"; public static final Logger LOGGER = LogUtils.getLogger(); private static final Map SOURCE_MODES = new HashMap<>(); private static final List EXPLOSION_BLACKLIST = new ArrayList<>(); private static final List DEFAULT_BLACKLIST = List.of( "ancient_elements:block_of_raw_infernal_ore", "ancient_elements:celestium_ore", "ancient_elements:deepslate_frost_ore", "ancient_elements:deepslate_jungle_steel_ore", "ancient_elements:deepslate_lead_ore", "ancient_elements:deepslate_steel_ore", "ancient_elements:deepslate_tin_ore", "ancient_elements:deepslate_titanium_ore", "ancient_elements:ender_steel_ore", "ancient_elements:endrium_ore", "ancient_elements:frost_ore", "ancient_elements:infernal_ore", "ancient_elements:jungle_steel_ore", "ancient_elements:lead_ore", "ancient_elements:meteorite_ore", "ancient_elements:nether_steel_ore", "ancient_elements:palladium_ore", "ancient_elements:spectrillium_ore", "ancient_elements:steel_ore", "ancient_elements:tin_ore", "ancient_elements:titanium_ore", "ancient_elements:void_steel_ore", "mofus_better_end_:void_portal_block", "mofus_better_end_:void_portal_igniter", "mofus_better_end_:star_portal"); private static final Path CONFIG_DIR = Paths.get("config", "explosionoverhaul"); private static final Path BLACKLIST_JSON = CONFIG_DIR.resolve("DestroyingBlacklist.json"); private static final Path SOURCE_MODES_JSON = CONFIG_DIR.resolve("ExplosionSourceBlacklist.json"); public ExplosionOverhaul(IEventBus modEventBus, ModContainer modContainer) { modContainer.registerConfig(ModConfig.Type.COMMON, Config.COMMON_SPEC, "explosionoverhaul/explosionoverhaul-common.toml"); modContainer.registerConfig(ModConfig.Type.CLIENT, Config.CLIENT_SPEC, "explosionoverhaul/explosionoverhaul-client.toml"); ModSounds.register(modEventBus); ModParticles.register(modEventBus); ModBlocks.register(modEventBus); ModItems.register(modEventBus); ModBlockEntities.register(modEventBus); ModCreativeTabs.register(modEventBus); modEventBus.addListener(this::commonSetup); } private void commonSetup(FMLCommonSetupEvent event) { event.enqueueWork(() -> { ensureConfigDirectory(); loadBlacklistFromJson(); loadSourceModesFromJson(); PacketHandler.register(); }); } private static void ensureConfigDirectory() { try { Files.createDirectories(CONFIG_DIR); } catch (Exception e) { LOGGER.warn("Failed to create config/explosionoverhaul directory", e); } } private static void loadBlacklistFromJson() { ensureConfigDirectory(); Gson gson = new GsonBuilder().setPrettyPrinting().create(); try { if (!Files.exists(BLACKLIST_JSON)) { try (BufferedWriter writer = Files.newBufferedWriter(BLACKLIST_JSON)) { gson.toJson(DEFAULT_BLACKLIST, writer); } EXPLOSION_BLACKLIST.clear(); EXPLOSION_BLACKLIST.addAll(DEFAULT_BLACKLIST); return; } try (BufferedReader reader = Files.newBufferedReader(BLACKLIST_JSON)) { List list = gson.fromJson((Reader) reader, new TypeToken>() {}.getType()); EXPLOSION_BLACKLIST.clear(); EXPLOSION_BLACKLIST.addAll(list == null ? DEFAULT_BLACKLIST : list); } } catch (Exception e) { LOGGER.warn("Failed to load DestroyingBlacklist.json, falling back to defaults", e); EXPLOSION_BLACKLIST.clear(); EXPLOSION_BLACKLIST.addAll(DEFAULT_BLACKLIST); } } private static void loadSourceModesFromJson() { ensureConfigDirectory(); Gson gson = new GsonBuilder().setPrettyPrinting().create(); try { if (!Files.exists(SOURCE_MODES_JSON)) { try (BufferedWriter writer = Files.newBufferedWriter(SOURCE_MODES_JSON)) { gson.toJson(SOURCE_MODES, writer); } return; } try (BufferedReader reader = Files.newBufferedReader(SOURCE_MODES_JSON)) { Map modes = gson.fromJson((Reader) reader, new TypeToken>() {}.getType()); SOURCE_MODES.clear(); if (modes != null) { SOURCE_MODES.putAll(modes); } } } catch (Exception e) { LOGGER.warn("Failed to load ExplosionSourceBlacklist.json", e); } } public static ExplosionSourceMode getSourceMode(String id) { return SOURCE_MODES.getOrDefault(id, ExplosionSourceMode.DEFAULT); } public static Map getSourceModes() { return new HashMap<>(SOURCE_MODES); } public static void setSourceModes(Map modes) { SOURCE_MODES.clear(); SOURCE_MODES.putAll(modes); writeJson(SOURCE_MODES_JSON, SOURCE_MODES); } public static List getExplosionBlacklistList() { return new ArrayList<>(EXPLOSION_BLACKLIST); } public static List getDefaultExplosionBlacklist() { return new ArrayList<>(DEFAULT_BLACKLIST); } public static void setExplosionBlacklistFromList(List list) { EXPLOSION_BLACKLIST.clear(); for (String entry : list) { if (entry != null && !entry.isBlank()) { EXPLOSION_BLACKLIST.add(entry.trim()); } } writeJson(BLACKLIST_JSON, EXPLOSION_BLACKLIST); } private static void writeJson(Path path, Object value) { ensureConfigDirectory(); try (BufferedWriter writer = Files.newBufferedWriter(path)) { new GsonBuilder().setPrettyPrinting().create().toJson(value, writer); } catch (Exception e) { LOGGER.warn("Failed to save {}", path, e); } } public static boolean isBlockBlacklisted(Block block) { ResourceLocation blockId = BuiltInRegistries.BLOCK.getKey(block); return blockId != null && EXPLOSION_BLACKLIST.contains(blockId.toString()); } public static boolean isBlockStateBlacklisted(BlockState state) { return isBlockBlacklisted(state.getBlock()); } public static void addDelayedSound(ServerPlayer player, SoundEvent sound, SoundSource source, float x, float y, float z, float volume, float pitch, long seed, long delayTicks) { } public static void addDelayedParticle(ServerLevel level, BlockParticleOption particleOption, double x, double y, double z, int count, double dx, double dy, double dz, double speed, long delayTicks, long durationTicks) { } public enum ExplosionSourceMode { DEFAULT, VANILLA, NO_DESTRUCTION, NO_DESTRUCTION_GLASSWORKS } public static class CaveEffects { public static void spawnFallingBlocksAndDust(ServerLevel level, Vec3 explosionPos, ServerPlayer player, float power, long initialDelayTicks) { } } }