diff --git a/src/main/java/com/vinlanx/explosionoverhaul/Config.java b/src/main/java/com/vinlanx/explosionoverhaul/Config.java index 3c2560c..ce1007c 100644 --- a/src/main/java/com/vinlanx/explosionoverhaul/Config.java +++ b/src/main/java/com/vinlanx/explosionoverhaul/Config.java @@ -84,6 +84,7 @@ public class Config { public final ModConfigSpec.EnumValue particleRenderMode; public final ModConfigSpec.DoubleValue particleSizeScale; public final ModConfigSpec.BooleanValue firstLaunchComplete; + public final ModConfigSpec.BooleanValue introSetupComplete; public final ModConfigSpec.BooleanValue enableGroundDustEffect; public final ModConfigSpec.DoubleValue groundDustQuality; public final ModConfigSpec.IntValue groundDustRaycastFrequency; @@ -124,6 +125,7 @@ public class Config { this.particleRenderMode = builder.comment(new String[]{"Particle rendering system mode:", "REALISTIC - Uses animated sprite sheets with complex textures (current system)", "VANILA - Vanilla-like simple textures with color phases (better performance)"}).defineEnum("particleRenderMode", (Enum)ParticleRenderMode.VANILA); this.particleSizeScale = builder.comment(new String[]{"Scales the size of all explosion particles across all render modes.", "1.0 = default size, 0.1 = 10% of default, 5.0 = 500% of default."}).defineInRange("particleSizeScale", 1.0, 0.1, 5.0); this.firstLaunchComplete = builder.comment("Internal flag: marks whether the first-time setup screen has been shown.").define("firstLaunchComplete", false); + this.introSetupComplete = builder.comment("Internal flag for the NeoForge port intro/setup flow.").define("introSetupComplete", false); builder.comment("\nCore explosion visual effects"); this.enableExplosionParticles = builder.comment("Enables the main fiery glow particles (glow, glow_2, sglow). Disabling this can significantly improve performance.").define("enableExplosionParticles", true); builder.comment("\nPlasma particle effects"); diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ServerExplosionHandler.java b/src/main/java/com/vinlanx/explosionoverhaul/ServerExplosionHandler.java index cd02226..6654177 100644 --- a/src/main/java/com/vinlanx/explosionoverhaul/ServerExplosionHandler.java +++ b/src/main/java/com/vinlanx/explosionoverhaul/ServerExplosionHandler.java @@ -6,8 +6,10 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; @@ -23,9 +25,11 @@ public class ServerExplosionHandler { } Vec3 center = explosion instanceof ExplosionAccessor accessor ? accessor.explosionoverhaul$getCenter() : Vec3.ZERO; int radius = Math.max(5, Math.min(18, Math.round(power * 2.0f * ((Double)Config.COMMON.craterSizeMultiplier.get()).floatValue()))); + ExplosionOverhaul.LOGGER.info("Explosion Overhaul handling explosion at {} with power {} and radius {}", center, power, radius); Set existing = new HashSet<>(affectedBlocks); BlockPos origin = BlockPos.containing(center); double radiusSq = radius * radius; + int directBlocksChanged = 0; for (BlockPos pos : BlockPos.betweenClosed(origin.offset(-radius, -radius, -radius), origin.offset(radius, radius, radius))) { double distanceSq = pos.distToCenterSqr(center); if (distanceSq > radiusSq) { @@ -39,7 +43,14 @@ public class ServerExplosionHandler { if (existing.add(immutable)) { affectedBlocks.add(immutable); } + if (directBlocksChanged < 2500) { + level.setBlock(immutable, Blocks.AIR.defaultBlockState(), 3); + ++directBlocksChanged; + } } + level.sendParticles(ParticleTypes.EXPLOSION_EMITTER, center.x(), center.y(), center.z(), Math.max(2, radius / 3), 0.5, 0.5, 0.5, 0.0); + level.sendParticles(ParticleTypes.LARGE_SMOKE, center.x(), center.y(), center.z(), radius * 8, radius * 0.35, radius * 0.25, radius * 0.35, 0.08); + level.sendParticles(ParticleTypes.FLAME, center.x(), center.y(), center.z(), radius * 4, radius * 0.25, radius * 0.2, radius * 0.25, 0.05); } public static void register() { diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/FirstTimeScreen.java b/src/main/java/com/vinlanx/explosionoverhaul/client/FirstTimeScreen.java index 795f04e..da15a63 100644 --- a/src/main/java/com/vinlanx/explosionoverhaul/client/FirstTimeScreen.java +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/FirstTimeScreen.java @@ -1,16 +1,102 @@ package com.vinlanx.explosionoverhaul.client; +import com.vinlanx.explosionoverhaul.Config; import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; public class FirstTimeScreen extends Screen { + private static final ResourceLocation REALISTIC = ResourceLocation.fromNamespaceAndPath("explosionoverhaul", "intro_gui/gui_screen_1.png"); + private static final ResourceLocation VANILLA = ResourceLocation.fromNamespaceAndPath("explosionoverhaul", "intro_gui/gui_screen_2.png"); + private static final ResourceLocation REALISTIC_2 = ResourceLocation.fromNamespaceAndPath("explosionoverhaul", "intro_gui/gui_screen_3.png"); + private static final ResourceLocation QUALITY_64 = ResourceLocation.fromNamespaceAndPath("explosionoverhaul", "intro_gui/gui_screen_4.png"); + + private Config.Client.ParticleRenderMode selectedMode = Config.Client.ParticleRenderMode.REALISTIC; + private Config.Client.GlowTextureQuality selectedQuality = Config.Client.GlowTextureQuality.QUALITY_256; + private boolean choosingQuality; + public FirstTimeScreen() { - super(Component.empty()); + super(Component.literal("Explosion Overhaul Setup")); + } + + @Override + protected void init() { + this.rebuildButtons(); + } + + private void rebuildButtons() { + this.clearWidgets(); + int cardW = Math.max(160, this.width / 5); + int cardH = 28; + int y = this.height - 86; + if (!this.choosingQuality) { + int gap = 12; + int startX = (this.width - cardW * 3 - gap * 2) / 2; + this.addRenderableWidget(Button.builder(Component.literal("Realistic"), button -> { + this.selectedMode = Config.Client.ParticleRenderMode.REALISTIC; + this.choosingQuality = true; + this.rebuildButtons(); + }).bounds(startX, y, cardW, cardH).build()); + this.addRenderableWidget(Button.builder(Component.literal("Vanilla Performance"), button -> { + this.selectedMode = Config.Client.ParticleRenderMode.VANILA; + this.choosingQuality = true; + this.rebuildButtons(); + }).bounds(startX + cardW + gap, y, cardW, cardH).build()); + this.addRenderableWidget(Button.builder(Component.literal("Realistic 2"), button -> { + this.selectedMode = Config.Client.ParticleRenderMode.REALISTIC_2; + this.choosingQuality = true; + this.rebuildButtons(); + }).bounds(startX + (cardW + gap) * 2, y, cardW, cardH).build()); + } else { + int gap = 16; + int startX = (this.width - cardW * 2 - gap) / 2; + this.addRenderableWidget(Button.builder(Component.literal("256p Quality"), button -> this.finish(Config.Client.GlowTextureQuality.QUALITY_256)).bounds(startX, y, cardW, cardH).build()); + this.addRenderableWidget(Button.builder(Component.literal("64p Performance"), button -> this.finish(Config.Client.GlowTextureQuality.QUALITY_64)).bounds(startX + cardW + gap, y, cardW, cardH).build()); + this.addRenderableWidget(Button.builder(Component.literal("Back"), button -> { + this.choosingQuality = false; + this.rebuildButtons(); + }).bounds(16, this.height - 40, 80, 24).build()); + } + } + + private void finish(Config.Client.GlowTextureQuality quality) { + this.selectedQuality = quality; + Config.CLIENT.particleRenderMode.set(this.selectedMode); + Config.CLIENT.glowTextureQuality.set(this.selectedQuality); + Config.CLIENT.firstLaunchComplete.set(true); + Config.CLIENT.introSetupComplete.set(true); + Config.CLIENT_SPEC.save(); + this.onClose(); } @Override public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) { + this.renderBackground(graphics, mouseX, mouseY, partialTick); + graphics.fill(0, 0, this.width, this.height, 0xE0101117); + graphics.drawCenteredString(this.font, Component.literal("Explosion Overhaul"), this.width / 2, 28, 0xFFFFFF); + graphics.drawCenteredString(this.font, this.choosingQuality ? Component.literal("Choose texture quality") : Component.literal("Choose explosion render mode"), this.width / 2, 48, 0xFFB35C); + + if (this.choosingQuality) { + this.drawPreview(graphics, REALISTIC, this.width / 2 - 270, 82, 250, 141, "256p Quality"); + this.drawPreview(graphics, QUALITY_64, this.width / 2 + 20, 82, 250, 141, "64p Performance"); + } else { + this.drawPreview(graphics, REALISTIC, this.width / 2 - 390, 82, 240, 135, "Realistic"); + this.drawPreview(graphics, VANILLA, this.width / 2 - 120, 82, 240, 135, "Vanilla Performance"); + this.drawPreview(graphics, REALISTIC_2, this.width / 2 + 150, 82, 240, 135, "Realistic 2"); + } super.render(graphics, mouseX, mouseY, partialTick); } + + private void drawPreview(GuiGraphics graphics, ResourceLocation texture, int x, int y, int w, int h, String label) { + graphics.fill(x - 2, y - 2, x + w + 2, y + h + 20, 0xAA000000); + graphics.blit(texture, x, y, 0.0f, 0.0f, w, h, 854, 480); + graphics.drawCenteredString(this.font, Component.literal(label), x + w / 2, y + h + 7, 0xFFFFFF); + } + + @Override + public boolean shouldCloseOnEsc() { + return false; + } } diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/FirstTimeSetupHandler.java b/src/main/java/com/vinlanx/explosionoverhaul/client/FirstTimeSetupHandler.java index aa3a700..d8538e5 100644 --- a/src/main/java/com/vinlanx/explosionoverhaul/client/FirstTimeSetupHandler.java +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/FirstTimeSetupHandler.java @@ -25,14 +25,13 @@ public class FirstTimeSetupHandler { Minecraft mc = Minecraft.getInstance(); if (!hasChecked && mc.screen instanceof TitleScreen) { hasChecked = true; - if (Config.isFirstLaunch()) { + if (!((Boolean)Config.CLIENT.introSetupComplete.get()).booleanValue()) { pendingShowIntro = true; } } if (pendingShowIntro && mc.screen instanceof TitleScreen) { pendingShowIntro = false; - mc.setScreen(new IntroSplashScreen()); - Config.markFirstLaunchComplete(); + mc.setScreen(new FirstTimeScreen()); } }