generated from MrSphay/codex-agent-repository-kit
Improve intro UI and basic explosion effects
All checks were successful
Build / build (push) Successful in 14m31s
All checks were successful
Build / build (push) Successful in 14m31s
This commit is contained in:
@@ -3,15 +3,37 @@ package com.vinlanx.explosionoverhaul;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
public class DripstoneEffects {
|
||||
public static void handleDripstoneFall(ServerLevel level, BlockPos center, int explosionPower, RandomSource random) {
|
||||
if (!((Boolean)Config.COMMON.enableDripstoneFalling.get()).booleanValue()) {
|
||||
return;
|
||||
}
|
||||
int radius = Math.min((Integer)Config.COMMON.dripstoneFallingSearchRadius.get(), Math.max(8, explosionPower * 4));
|
||||
int fallPercent = getFallPercent(explosionPower);
|
||||
int changed = 0;
|
||||
for (BlockPos pos : BlockPos.betweenClosed(center.offset(-radius, -radius, -radius), center.offset(radius, radius, radius))) {
|
||||
if (changed >= 400) {
|
||||
break;
|
||||
}
|
||||
BlockState state = level.getBlockState(pos);
|
||||
if (!state.is(Blocks.POINTED_DRIPSTONE) || random.nextInt(100) >= fallPercent) {
|
||||
continue;
|
||||
}
|
||||
BlockPos immutable = pos.immutable();
|
||||
level.levelEvent(2001, immutable, Block.getId(state));
|
||||
level.setBlock(immutable, Blocks.AIR.defaultBlockState(), 3);
|
||||
++changed;
|
||||
}
|
||||
}
|
||||
|
||||
public static void onServerTick(ServerLevel level) {
|
||||
}
|
||||
|
||||
public static int getFallPercent(int explosionPower) {
|
||||
return 0;
|
||||
return Math.max(10, Math.min(90, explosionPower * 7));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,29 @@
|
||||
package com.vinlanx.explosionoverhaul;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.item.PrimedTnt;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class ExplosionClusterHandler {
|
||||
public static float calculateClusteredPower(Level level, Vec3 pos, float initialPower) {
|
||||
return initialPower;
|
||||
if (!((Boolean)Config.COMMON.enableExplosionClustering.get()).booleanValue()) {
|
||||
return initialPower;
|
||||
}
|
||||
int nearbyExplosives = 0;
|
||||
BlockPos origin = BlockPos.containing(pos);
|
||||
for (BlockPos blockPos : BlockPos.betweenClosed(origin.offset(-3, -2, -3), origin.offset(3, 2, 3))) {
|
||||
if (level.getBlockState(blockPos).is(Blocks.TNT)) {
|
||||
++nearbyExplosives;
|
||||
}
|
||||
}
|
||||
nearbyExplosives += level.getEntitiesOfClass(PrimedTnt.class, new AABB(pos.x - 4.0, pos.y - 4.0, pos.z - 4.0, pos.x + 4.0, pos.y + 4.0, pos.z + 4.0)).size();
|
||||
if (nearbyExplosives <= 1) {
|
||||
return initialPower;
|
||||
}
|
||||
float clusteredPower = initialPower + (nearbyExplosives - 1) * 2.75f;
|
||||
return Math.min(clusteredPower, ((Integer)Config.COMMON.maxClusterPower.get()).floatValue());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,83 @@
|
||||
package com.vinlanx.explosionoverhaul;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class GlassBreakingEffects {
|
||||
public static void trigger(ServerLevel level, Vec3 explosionPos, float power) {
|
||||
if (!((Boolean)Config.COMMON.enableGlassBreaking.get()).booleanValue()) {
|
||||
return;
|
||||
}
|
||||
Random random = new Random(level.getSeed() ^ BlockPos.containing(explosionPos).asLong());
|
||||
double radius = calculateRadius(power);
|
||||
BlockPos origin = BlockPos.containing(explosionPos);
|
||||
int r = (int)Math.ceil(radius);
|
||||
int broken = 0;
|
||||
int maxBreak = Math.max(24, Math.min(700, (Integer)Config.COMMON.glassBlocksPerCycle.get() * 8));
|
||||
for (BlockPos pos : BlockPos.betweenClosed(origin.offset(-r, -r, -r), origin.offset(r, r, r))) {
|
||||
if (broken >= maxBreak) {
|
||||
break;
|
||||
}
|
||||
BlockState state = level.getBlockState(pos);
|
||||
if (!isGlass(state) || !shouldBreak(level, explosionPos, pos, power, random, radius)) {
|
||||
continue;
|
||||
}
|
||||
BlockPos immutable = pos.immutable();
|
||||
level.levelEvent(2001, immutable, Block.getId(state));
|
||||
level.setBlock(immutable, Blocks.AIR.defaultBlockState(), 3);
|
||||
++broken;
|
||||
}
|
||||
}
|
||||
|
||||
public static void onServerTick() {
|
||||
}
|
||||
|
||||
public static double calculateRadius(float power) {
|
||||
return Math.max(1.0, power);
|
||||
return Math.max(5.0, Math.min(72.0, power * 7.0 * calculateRadiusMultiplier(power)));
|
||||
}
|
||||
|
||||
public static float calculateRadiusMultiplier(float power) {
|
||||
return 1.0f;
|
||||
return power >= 16.0f ? 1.35f : 1.0f;
|
||||
}
|
||||
|
||||
public static boolean isGlass(BlockState state) {
|
||||
return false;
|
||||
ResourceLocation id = BuiltInRegistries.BLOCK.getKey(state.getBlock());
|
||||
return id != null && id.getPath().contains("glass");
|
||||
}
|
||||
|
||||
public static Set<BlockPos> findConnectedGlass(ServerLevel level, BlockPos pos, Set<BlockPos> processed) {
|
||||
return Collections.emptySet();
|
||||
if (processed.contains(pos) || !isGlass(level.getBlockState(pos))) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
Set<BlockPos> connected = new HashSet<>();
|
||||
connected.add(pos);
|
||||
processed.add(pos);
|
||||
for (BlockPos neighbor : new BlockPos[] { pos.north(), pos.south(), pos.east(), pos.west(), pos.above(), pos.below() }) {
|
||||
if (connected.size() > 64) {
|
||||
break;
|
||||
}
|
||||
connected.addAll(findConnectedGlass(level, neighbor, processed));
|
||||
}
|
||||
return connected;
|
||||
}
|
||||
|
||||
public static boolean shouldBreak(ServerLevel level, Vec3 explosionPos, BlockPos pos, float power, Random random, double radius) {
|
||||
return false;
|
||||
double distance = Math.sqrt(pos.distToCenterSqr(explosionPos));
|
||||
if (distance > radius) {
|
||||
return false;
|
||||
}
|
||||
double chance = 1.0 - distance / radius;
|
||||
chance = Math.max(0.12, chance * 1.35);
|
||||
return random.nextDouble() < chance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,43 @@
|
||||
package com.vinlanx.explosionoverhaul;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.RedstoneLampBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class RedstoneLampEffects {
|
||||
public static void triggerLampFlicker(ServerLevel level, ServerPlayer player, float power, long delayTicks, double distance) {
|
||||
triggerNearbyLamps(level, player.position(), power);
|
||||
}
|
||||
|
||||
public static void triggerNearbyLamps(ServerLevel level, Vec3 explosionPos, float power) {
|
||||
if (!((Boolean)Config.COMMON.enableLampFlicker.get()).booleanValue()) {
|
||||
return;
|
||||
}
|
||||
int radius = Math.min((Integer)Config.COMMON.lampFlickerSearchRadius.get(), Math.max(8, Math.round(power * 6.0f)));
|
||||
BlockPos origin = BlockPos.containing(explosionPos);
|
||||
int changed = 0;
|
||||
for (BlockPos pos : BlockPos.betweenClosed(origin.offset(-radius, -radius, -radius), origin.offset(radius, radius, radius))) {
|
||||
if (changed >= 96) {
|
||||
break;
|
||||
}
|
||||
BlockState state = level.getBlockState(pos);
|
||||
if (!state.is(Blocks.REDSTONE_LAMP) || !state.hasProperty(RedstoneLampBlock.LIT)) {
|
||||
continue;
|
||||
}
|
||||
BlockPos immutable = pos.immutable();
|
||||
boolean lit = state.getValue(RedstoneLampBlock.LIT);
|
||||
level.setBlock(immutable, state.setValue(RedstoneLampBlock.LIT, !lit), 3);
|
||||
level.playSound(null, immutable, ModSounds.LAMP_FLICKER_SPARK_1.get(), SoundSource.BLOCKS, 0.25f, 0.8f + level.random.nextFloat() * 0.4f);
|
||||
if (level.hasNeighborSignal(immutable)) {
|
||||
level.setBlock(immutable, state.setValue(RedstoneLampBlock.LIT, true), 3);
|
||||
}
|
||||
++changed;
|
||||
}
|
||||
}
|
||||
|
||||
public static void onServerTick() {
|
||||
|
||||
@@ -24,8 +24,12 @@ public class ServerExplosionHandler {
|
||||
power = Math.max(1.0f, explosionPower.getPower());
|
||||
}
|
||||
Vec3 center = explosion instanceof ExplosionAccessor accessor ? accessor.explosionoverhaul$getCenter() : Vec3.ZERO;
|
||||
power = ExplosionClusterHandler.calculateClusteredPower(level, center, power);
|
||||
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);
|
||||
GlassBreakingEffects.trigger(level, center, power);
|
||||
DripstoneEffects.handleDripstoneFall(level, BlockPos.containing(center), Math.round(power), level.random);
|
||||
RedstoneLampEffects.triggerNearbyLamps(level, center, power);
|
||||
Set<BlockPos> existing = new HashSet<>(affectedBlocks);
|
||||
BlockPos origin = BlockPos.containing(center);
|
||||
double radiusSq = radius * radius;
|
||||
|
||||
@@ -7,17 +7,17 @@ import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class FirstTimeScreen extends Screen {
|
||||
private static final int FRAME_WIDTH = 256;
|
||||
private static final int FRAME_HEIGHT = 144;
|
||||
private static final int FRAME_WIDTH = 768;
|
||||
private static final int FRAME_HEIGHT = 432;
|
||||
private static final int COLUMNS = 10;
|
||||
private static final int ROWS = 10;
|
||||
private static final int FRAME_COUNT = COLUMNS * ROWS;
|
||||
private static final int BORDER = 0xFFFF7A70;
|
||||
private static final int BORDER_HOVER = 0xFFFF9B91;
|
||||
private static final Choice[] CHOICES = new Choice[] {
|
||||
new Choice("gui_screen_1.png", 12, "REALISTIC", Config.Client.ParticleRenderMode.REALISTIC),
|
||||
new Choice("gui_screen_2.png", 28, "VANILLA-LIKE", Config.Client.ParticleRenderMode.VANILA),
|
||||
new Choice("gui_screen_3.png", 44, "REALISTIC 2", Config.Client.ParticleRenderMode.REALISTIC_2)
|
||||
new Choice("gui_screen_1.png", 7, 18, "REALISTIC", Config.Client.ParticleRenderMode.REALISTIC),
|
||||
new Choice("gui_screen_2.png", 7, 18, "VANILLA-LIKE", Config.Client.ParticleRenderMode.VANILA),
|
||||
new Choice("gui_screen_3.png", 20, 34, "REALISTIC 2", Config.Client.ParticleRenderMode.REALISTIC_2)
|
||||
};
|
||||
|
||||
private final Rect[] cardRects = new Rect[] { Rect.empty(), Rect.empty(), Rect.empty() };
|
||||
@@ -31,20 +31,20 @@ public class FirstTimeScreen extends Screen {
|
||||
graphics.fill(0, 0, this.width, this.height, 0xFF050506);
|
||||
this.drawAmbient(graphics);
|
||||
|
||||
int top = Math.max(28, this.height / 9);
|
||||
int top = Math.max(24, this.height / 12);
|
||||
graphics.drawCenteredString(this.font, Component.literal("Choose Your Explosion Style."), this.width / 2, top, 0xFFFF9900);
|
||||
graphics.drawCenteredString(this.font, Component.literal("You can change this anytime in the config"), this.width / 2, top + 25, 0xFFE5E5E5);
|
||||
graphics.drawCenteredString(this.font, Component.literal("The game may differ from the animations because compression has altered them."), this.width / 2, top + 48, 0xFF9C9C9C);
|
||||
|
||||
int availableCardH = Math.max(78, (this.height - top - 188) / 2);
|
||||
int cardW = Math.min(360, Math.max(150, (this.width - 170) / 2));
|
||||
int availableCardH = Math.max(76, (this.height - top - 188) / 2);
|
||||
int cardW = Math.min(320, Math.max(150, (this.width - 190) / 2));
|
||||
cardW = Math.min(cardW, availableCardH * FRAME_WIDTH / FRAME_HEIGHT);
|
||||
int cardH = cardW * FRAME_HEIGHT / FRAME_WIDTH;
|
||||
int gap = Math.max(34, this.width / 28);
|
||||
int firstX = this.width / 2 - cardW - gap / 2;
|
||||
int secondX = this.width / 2 + gap / 2;
|
||||
int firstRowY = top + 92;
|
||||
int secondRowY = firstRowY + cardH + 60;
|
||||
int firstRowY = top + 88;
|
||||
int secondRowY = firstRowY + cardH + 58;
|
||||
|
||||
this.cardRects[0] = new Rect(firstX, firstRowY, cardW, cardH + 58);
|
||||
this.cardRects[1] = new Rect(secondX, firstRowY, cardW, cardH + 58);
|
||||
@@ -83,7 +83,7 @@ public class FirstTimeScreen extends Screen {
|
||||
int imageW = rect.w;
|
||||
int imageH = rect.w * FRAME_HEIGHT / FRAME_WIDTH;
|
||||
graphics.fill(imageX - 6, imageY - 6, imageX + imageW + 6, imageY + imageH + 6, hovered ? BORDER_HOVER : BORDER);
|
||||
this.drawSheetFrame(graphics, choice.texture, (this.currentFrame(65L) + choice.frameOffset) % FRAME_COUNT, imageX, imageY, imageW, imageH);
|
||||
this.drawSheetFrame(graphics, choice.texture, choice.currentFrame(65L), imageX, imageY, imageW, imageH);
|
||||
graphics.drawCenteredString(this.font, Component.literal(choice.label), imageX + imageW / 2, imageY + imageH + 28, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
@@ -100,10 +100,6 @@ public class FirstTimeScreen extends Screen {
|
||||
graphics.pose().popPose();
|
||||
}
|
||||
|
||||
private int currentFrame(long frameTimeMillis) {
|
||||
return (int)((System.currentTimeMillis() / frameTimeMillis) % FRAME_COUNT);
|
||||
}
|
||||
|
||||
private void drawAmbient(GuiGraphics graphics) {
|
||||
for (int i = 0; i < 48; ++i) {
|
||||
int x = Math.floorMod(i * 173 + 19, Math.max(1, this.width));
|
||||
@@ -120,16 +116,23 @@ public class FirstTimeScreen extends Screen {
|
||||
|
||||
private static final class Choice {
|
||||
private final ResourceLocation texture;
|
||||
private final int frameOffset;
|
||||
private final int firstFrame;
|
||||
private final int lastFrameExclusive;
|
||||
private final String label;
|
||||
private final Config.Client.ParticleRenderMode mode;
|
||||
|
||||
private Choice(String fileName, int frameOffset, String label, Config.Client.ParticleRenderMode mode) {
|
||||
private Choice(String fileName, int firstFrame, int lastFrameExclusive, String label, Config.Client.ParticleRenderMode mode) {
|
||||
this.texture = ResourceLocation.fromNamespaceAndPath("explosionoverhaul", "intro_gui/preview/" + fileName);
|
||||
this.frameOffset = frameOffset;
|
||||
this.firstFrame = firstFrame;
|
||||
this.lastFrameExclusive = lastFrameExclusive;
|
||||
this.label = label;
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
private int currentFrame(long frameTimeMillis) {
|
||||
int span = Math.max(1, this.lastFrameExclusive - this.firstFrame);
|
||||
return this.firstFrame + (int)((System.currentTimeMillis() / frameTimeMillis) % span);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Rect {
|
||||
|
||||
@@ -8,10 +8,10 @@ import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.FormattedCharSequence;
|
||||
|
||||
public class GuideSlidesScreen extends Screen {
|
||||
private static final int FRAME_WIDTH = 256;
|
||||
private static final int FRAME_HEIGHT = 144;
|
||||
private static final int COLUMNS = 14;
|
||||
private static final int ROWS = 14;
|
||||
private static final int FRAME_WIDTH = 768;
|
||||
private static final int FRAME_HEIGHT = 432;
|
||||
private static final int COLUMNS = 10;
|
||||
private static final int ROWS = 18;
|
||||
private static final int FRAME_COUNT = COLUMNS * ROWS;
|
||||
private static final int ACCENT = 0xFFFF9F3A;
|
||||
private static final int RED = 0xFF561818;
|
||||
@@ -38,10 +38,10 @@ public class GuideSlidesScreen extends Screen {
|
||||
graphics.fill(0, 0, this.width, this.height, 0xFF070708);
|
||||
this.drawAmbient(graphics);
|
||||
|
||||
int imageW = Math.min(this.width - 220, 1080);
|
||||
int imageW = Math.min(this.width - 260, 980);
|
||||
int imageH = imageW * FRAME_HEIGHT / FRAME_WIDTH;
|
||||
int imageY = Math.max(28, this.height / 9);
|
||||
int maxImageH = Math.max(120, this.height - imageY - 220);
|
||||
int maxImageH = Math.max(110, this.height - imageY - 265);
|
||||
if (imageH > maxImageH) {
|
||||
imageH = Math.max(120, maxImageH);
|
||||
imageW = imageH * FRAME_WIDTH / FRAME_HEIGHT;
|
||||
@@ -53,9 +53,9 @@ public class GuideSlidesScreen extends Screen {
|
||||
Slide slide = SLIDES[this.slideIndex];
|
||||
this.drawSheetFrame(graphics, slide.texture, this.currentFrame(slide.frameCount, 55L), imageX, imageY, imageW, imageH);
|
||||
|
||||
int textWidth = Math.min(this.width - 240, 1040);
|
||||
int textY = imageY + imageH + 44;
|
||||
this.drawCenteredWrappedText(graphics, slide.text, this.width / 2, textY, textWidth, 0xFFFFFFFF);
|
||||
int textWidth = Math.min(this.width - 300, 920);
|
||||
int textY = imageY + imageH + 42;
|
||||
int textBottom = this.drawCenteredWrappedText(graphics, slide.text, this.width / 2, textY, textWidth, 0xFFFFFFFF);
|
||||
|
||||
int arrowSize = 74;
|
||||
int arrowY = imageY + imageH / 2 - arrowSize / 2;
|
||||
@@ -70,7 +70,8 @@ public class GuideSlidesScreen extends Screen {
|
||||
|
||||
int skipW = 142;
|
||||
int skipH = 38;
|
||||
this.skipButton = new Rect((this.width - skipW) / 2, this.height - 58, skipW, skipH);
|
||||
int skipY = Math.min(this.height - skipH - 12, textBottom + 18);
|
||||
this.skipButton = new Rect((this.width - skipW) / 2, skipY, skipW, skipH);
|
||||
this.drawFlatButton(graphics, this.skipButton, "Skip Guide", this.skipButton.contains(mouseX, mouseY));
|
||||
}
|
||||
|
||||
@@ -117,13 +118,14 @@ public class GuideSlidesScreen extends Screen {
|
||||
return (int)((System.currentTimeMillis() / frameTimeMillis) % maxFrame);
|
||||
}
|
||||
|
||||
private void drawCenteredWrappedText(GuiGraphics graphics, String text, int centerX, int y, int maxWidth, int color) {
|
||||
private int drawCenteredWrappedText(GuiGraphics graphics, String text, int centerX, int y, int maxWidth, int color) {
|
||||
List<FormattedCharSequence> lines = this.font.split(Component.literal(text), maxWidth);
|
||||
int lineY = y;
|
||||
for (FormattedCharSequence line : lines) {
|
||||
graphics.drawCenteredString(this.font, line, centerX, lineY, color);
|
||||
lineY += this.font.lineHeight + 5;
|
||||
}
|
||||
return lineY;
|
||||
}
|
||||
|
||||
private void drawArrow(GuiGraphics graphics, Rect rect, String text, boolean hovered) {
|
||||
|
||||
Reference in New Issue
Block a user