diff --git a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/mob/player/fem_hurt.ogg b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/mob/player/fem_hurt.ogg deleted file mode 100644 index 53408820b..000000000 Binary files a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/mob/player/fem_hurt.ogg and /dev/null differ diff --git a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/mob/player/masc_hurt.ogg b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/mob/player/masc_hurt.ogg deleted file mode 100644 index b4cbc12e5..000000000 Binary files a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/mob/player/masc_hurt.ogg and /dev/null differ diff --git a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/random/scrape.ogg b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/random/scrape.ogg new file mode 100644 index 000000000..8fa559342 Binary files /dev/null and b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/random/scrape.ogg differ diff --git a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/sounds.json b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/sounds.json index 1fcd6f301..f751a32b5 100644 --- a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/sounds.json +++ b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/sounds.json @@ -1,23 +1,53 @@ { - "mob.player.masculine.hurt": { - "replace": true, - "subtitle": "subtitles.mob.player.hurt", - "sounds": [ - "mob/player/masc_hurt.ogg" - ] - }, - "mob.player.feminine.hurt": { - "replace": true, - "subtitle": "subtitles.mob.player.hurt", - "sounds": [ - "mob/player/fem_hurt.ogg" - ] - }, - "mob.player.neutral.hurt": { - "replace": true, - "subtitle": "subtitles.mob.player.hurt", - "sounds": [ - "mob/player/neutral_hurt.ogg" - ] - } -} \ No newline at end of file + "tile.acidbubble": { + "subtitle": "subtitles.tile.acidbubble", + "sounds": [ + "tile/bubble_1.ogg", + "tile/bubble_2.ogg", + "tile/bubble_3.ogg", + "tile/bubble_4.ogg" + ] + }, + "step.crystal": { + "subtitle": "subtitles.step.crystal", + "sounds": [ + "step/crystal_1.ogg", + "step/crystal_2.ogg", + "step/crystal_3.ogg", + "step/crystal_4.ogg", + "step/crystal_5.ogg", + "step/crystal_6.ogg" + ] + }, + "tile.deep.boom": { + "subtitle": "subtitles.tile.deepboom", + "sounds": [ + "tile/deepboom.ogg" + ] + }, + "tile.deepquietboom": { + "subtitle": "subtitles.tile.deepquietboom", + "sounds": [ + "tile/deepquietboom.ogg" + ] + }, + "tile.crumble": { + "subtitle": "subtitles.crumble", + "sounds": [ + "tile/crumble_1.ogg", + "tile/crumble_2.ogg" + ] + }, + "tile.deepcrumble": { + "subtitle": "subtitles.deep.crumble", + "sounds": [ + "tile/deepcrumble.ogg" + ] + }, + "random.scrape": { + "subtitle": "subtitles.random.scrape", + "sounds": [ + "random/scrape.ogg" + ] + } +} diff --git a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/step/crystal_1.ogg b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/step/crystal_1.ogg new file mode 100644 index 000000000..995cc2916 Binary files /dev/null and b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/step/crystal_1.ogg differ diff --git a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/step/crystal_2.ogg b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/step/crystal_2.ogg new file mode 100644 index 000000000..f51006afe Binary files /dev/null and b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/step/crystal_2.ogg differ diff --git a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/step/crystal_3.ogg b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/step/crystal_3.ogg new file mode 100644 index 000000000..723f5ffa2 Binary files /dev/null and b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/step/crystal_3.ogg differ diff --git a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/step/crystal_4.ogg b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/step/crystal_4.ogg new file mode 100644 index 000000000..ec5761e33 Binary files /dev/null and b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/step/crystal_4.ogg differ diff --git a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/step/crystal_5.ogg b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/step/crystal_5.ogg new file mode 100644 index 000000000..9d7f41e57 Binary files /dev/null and b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/step/crystal_5.ogg differ diff --git a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/step/crystal_6.ogg b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/step/crystal_6.ogg new file mode 100644 index 000000000..e1921002b Binary files /dev/null and b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/step/crystal_6.ogg differ diff --git a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/bubble_1.ogg b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/bubble_1.ogg new file mode 100644 index 000000000..b39fabe86 Binary files /dev/null and b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/bubble_1.ogg differ diff --git a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/bubble_2.ogg b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/bubble_2.ogg new file mode 100644 index 000000000..6972fa491 Binary files /dev/null and b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/bubble_2.ogg differ diff --git a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/bubble_3.ogg b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/bubble_3.ogg new file mode 100644 index 000000000..05d29b468 Binary files /dev/null and b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/bubble_3.ogg differ diff --git a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/bubble_4.ogg b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/bubble_4.ogg new file mode 100644 index 000000000..8f7166ab2 Binary files /dev/null and b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/bubble_4.ogg differ diff --git a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/crumble_1.ogg b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/crumble_1.ogg new file mode 100644 index 000000000..bfa72fe8a Binary files /dev/null and b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/crumble_1.ogg differ diff --git a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/crumble_2.ogg b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/crumble_2.ogg new file mode 100644 index 000000000..7c58c5d8e Binary files /dev/null and b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/crumble_2.ogg differ diff --git a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/deepboom.ogg b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/deepboom.ogg new file mode 100644 index 000000000..abf6b6711 Binary files /dev/null and b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/deepboom.ogg differ diff --git a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/deepcrumble.ogg b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/deepcrumble.ogg new file mode 100644 index 000000000..b6bb0c261 Binary files /dev/null and b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/deepcrumble.ogg differ diff --git a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/deepquietboom.ogg b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/deepquietboom.ogg new file mode 100644 index 000000000..41b6290cf Binary files /dev/null and b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/tile/deepquietboom.ogg differ diff --git a/game/client/devPacks/inTestingSoundsPack/manifest.json b/game/client/devPacks/inTestingSoundsPack/manifest.json index ad1ee857f..7654d1b25 100644 --- a/game/client/devPacks/inTestingSoundsPack/manifest.json +++ b/game/client/devPacks/inTestingSoundsPack/manifest.json @@ -3,7 +3,7 @@ "name": "ยง5In Testing Sounds", "line1": "Sounds which we are considering adding", "line2": "but havent added to the sound server yet.", - "packVersion": "7.3", - "format": 1 + "packVersion": "7.4", + "format": 2 } } diff --git a/game/client/src/main/java/net/minecraft/client/Minecraft.java b/game/client/src/main/java/net/minecraft/client/Minecraft.java index 84665e3d8..b26feec9f 100644 --- a/game/client/src/main/java/net/minecraft/client/Minecraft.java +++ b/game/client/src/main/java/net/minecraft/client/Minecraft.java @@ -2266,7 +2266,13 @@ public class Minecraft int v = 0; while (this.currentWorld.updatingLighting()) { v++; - this.loadingScreen.progressStagePercentage((Math.min(v, count) * 100) / count); + + //safety check to prevent dividing by zero + if (count > 0) { + this.loadingScreen.progressStagePercentage((Math.min(v, count) * 100) / count); + } else { + this.loadingScreen.progressStagePercentage(100); + } if (v >= 10000) { LOGGER.error("Updating lights took to long panic skipping!"); diff --git a/game/client/src/main/java/net/minecraft/client/gui/TooltipElement.java b/game/client/src/main/java/net/minecraft/client/gui/TooltipElement.java index a8a760262..c639d33fe 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/TooltipElement.java +++ b/game/client/src/main/java/net/minecraft/client/gui/TooltipElement.java @@ -231,14 +231,14 @@ public class TooltipElement extends Gui { } } - if (itemStack.isItemStackDamageable() && !showDescription && GameSettings.SHOW_ITEM_DEBUG_INFO.value) { + if (itemStack.isItemStackDamageable() && GameSettings.SHOW_ITEM_DEBUG_INFO.value) { int durability = itemStack.getMaxDamage(); int remainingUses = durability - itemStack.getMetadata(); text.append('\n').append(TextFormatting.LIGHT_GRAY).append(remainingUses + 1).append(" / ").append(durability + 1); } - if (showDescription && !debug) { + if (showDescription) { text.append('\n').append(formatDescription(itemStack.getItemDescription())); } else if (!(slot instanceof SlotResult) && GameSettings.ITEM_DESCRIPTIONS.value != DescriptionPromptEnum.NEVER_PROMPT) { text.append('\n').append(formatDescription(trans.translateKeyAndFormat("gui.tooltip.prompt.description", GameSettings.KEY_DESCRIPTION.getKeyName()))); diff --git a/game/client/src/main/java/net/minecraft/client/gui/achievements/data/AchievementPages.java b/game/client/src/main/java/net/minecraft/client/gui/achievements/data/AchievementPages.java index bcbcff900..9d8b31348 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/achievements/data/AchievementPages.java +++ b/game/client/src/main/java/net/minecraft/client/gui/achievements/data/AchievementPages.java @@ -61,6 +61,8 @@ public class AchievementPages { // netherPage.addAchievement(Achievements.ENTER_WARRENS, 0, 5); netherPage.addAchievement(Achievements.MOST_WANTED, 0, -1); netherPage.addAchievement(Achievements.FAST_TRAVEL, 0, 1); + netherPage.addAchievement(Achievements.GET_STEEL_BLAST_FURNACE, 0, 4); + netherPage.addAchievement(Achievements.OBTAIN_STEEL, -2, 4); } static { init(); diff --git a/game/client/src/main/java/net/minecraft/client/gui/guidebook/mobs/MobInfoRegistry.java b/game/client/src/main/java/net/minecraft/client/gui/guidebook/mobs/MobInfoRegistry.java index d9e4ea1b1..c84a32a5d 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/guidebook/mobs/MobInfoRegistry.java +++ b/game/client/src/main/java/net/minecraft/client/gui/guidebook/mobs/MobInfoRegistry.java @@ -176,7 +176,7 @@ public abstract class MobInfoRegistry { 20, 1000, new MobDrop[] { - new MobDrop(new ItemStack(Items.GUNPOWDER), 0.66f, 1, 2) + new MobDrop(new ItemStack(Items.GUNPOWDER), 1f, 3, 16), } ); register(MobZombiePig.class, diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngame.java b/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngame.java index 221b99f5e..579acb765 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngame.java +++ b/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngame.java @@ -65,6 +65,11 @@ public class HudIngame extends Gui { private static final Logger LOGGER = LogUtils.getLogger(); public static final Direction[] directions = new Direction[]{Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST}; + private static final float ACID_OVERLAY_IMMERSION_RAMP_UP = 0.055F; + private static final float ACID_OVERLAY_IMMERSION_RAMP_DOWN = 0.22F; + private static final float ACID_OVERLAY_LERP_UP = 0.13F; + private static final float ACID_OVERLAY_LERP_DOWN = 0.038F; + private final @NotNull List<@NotNull ChatLine> chatMessageList = new ArrayList<>(); protected Minecraft mc; public int updateCounter = 0; @@ -73,6 +78,8 @@ public class HudIngame extends Gui { private boolean colorString = false; public float destroyProgress; float prevVignetteBrightness = 1.0f; + protected float acidOverlayAlpha; + protected float acidImmersionRamp; protected FontRenderer fontRenderer; public int chatScroll = 0; @@ -110,6 +117,8 @@ public class HudIngame extends Gui { renderPortalOverlay(portalIntensity, width, height); } + updateAcidOverlayForFrame(width, height, partialTicks); + for (final HudComponent component : HudComponents.INSTANCE.getComponents()) { if (component.isVisible()) { GLRenderer.pushFrame(); @@ -701,6 +710,63 @@ public class HudIngame extends Gui { GLRenderer.setColor4f(1.0F, 1.0F, 1.0F, 1.0F); } + protected void updateAcidOverlayForFrame(int width, int height, float partialTicks) { + final Player p = this.mc.thePlayer; + final boolean show = p.shouldShowAcidVisualEffects() && p.getGamemode().hasToolDurability() && GameSettings.THIRD_PERSON_VIEW.value == 0; + + if (p.isEffectiveInAcid() && show) { + this.acidImmersionRamp += (1.0F - this.acidImmersionRamp) * ACID_OVERLAY_IMMERSION_RAMP_UP; + } else { + this.acidImmersionRamp += (0.0F - this.acidImmersionRamp) * ACID_OVERLAY_IMMERSION_RAMP_DOWN; + } + if (!show) { + this.acidImmersionRamp = 0.0F; + } + + final float fillNorm = Player.ACID_CYCLE_MAX > 0 + ? MathHelper.clamp((float) p.getAcidHudBarFillTicks() / (float) Player.ACID_CYCLE_MAX, 0.0F, 1.0F) + : 0.0F; + + final float acidTargetAlpha; + if (!show) { + acidTargetAlpha = 0.0F; + } else if (p.isEffectiveInAcid()) { + acidTargetAlpha = Math.max(fillNorm, this.acidImmersionRamp); + } else { + // Outside acid: keep overlay at full strength for the whole post-exit drain, then fade once ticks hit 0. + acidTargetAlpha = fillNorm > 0.0F ? 1.0F : 0.0F; + } + + final float lerpK = acidTargetAlpha > this.acidOverlayAlpha ? ACID_OVERLAY_LERP_UP : ACID_OVERLAY_LERP_DOWN; + this.acidOverlayAlpha += (acidTargetAlpha - this.acidOverlayAlpha) * lerpK; + if (this.acidOverlayAlpha > 0.001F) { + renderAcidOverlay(width, height, partialTicks); + } + } + + protected void renderAcidOverlay(int xSize, int ySize, float partialTicks) { + GLRenderer.pushFrame(); + + GLRenderer.disableState(State.DEPTH_TEST); + GLRenderer.setDepthMask(false); + GLRenderer.enableState(State.BLEND); + GLRenderer.setBlendFunc(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA); + + // Animated acid overlay layer (vignette + drips) + GLRenderer.setShader(Shaders.ACID_OVERLAY); + GLRenderer.setColor4f(1.0F, 1.0F, 1.0F, this.acidOverlayAlpha); + + TessellatorGeneral tess = GLRenderer.getTessellator(); + tess.startDrawingQuads(); + tess.addVertexWithUV(0, ySize, -90D, 0D, 1D); + tess.addVertexWithUV(xSize, ySize, -90D, 1D, 1D); + tess.addVertexWithUV(xSize, 0, -90D, 1D, 0D); + tess.addVertexWithUV(0, 0, -90D, 0D, 0D); + tess.draw(); + + GLRenderer.popFrame(); + } + public void updateTick() { if (this.recordPlayingUpFor > 0) { this.recordPlayingUpFor--; diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngameDoom.java b/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngameDoom.java index 32c731878..85beb83ee 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngameDoom.java +++ b/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngameDoom.java @@ -57,6 +57,8 @@ public class HudIngameDoom renderPortalOverlay(portalIntensity, width, height); } + updateAcidOverlayForFrame(width, height, partialTicks); + drawBackground(); drawFace(); drawAmmo(); diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentAcidBar.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentAcidBar.java new file mode 100644 index 000000000..841b38716 --- /dev/null +++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentAcidBar.java @@ -0,0 +1,124 @@ +package net.minecraft.client.gui.hud.component; + +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.hud.HudIngame; +import net.minecraft.client.gui.hud.component.layout.Layout; +import net.minecraft.client.option.GameSettings; +import net.minecraft.client.render.renderer.GLRenderer; +import net.minecraft.client.render.renderer.State; +import net.minecraft.client.render.texture.stitcher.TextureRegistry; +import net.minecraft.core.entity.player.Player; + +public class HudComponentAcidBar extends HudComponentMovable { + + private static final int ACID_BAR_MAX_ICONS = 10; + + public HudComponentAcidBar(String key, Layout layout) { + super(key, 81, 9, layout); + } + + private boolean isVertical() { + return GameSettings.VERTICAL_ACID_BAR.value; + } + + private boolean isFlipped() { + return GameSettings.FLIP_ACID_BAR.value; + } + + @Override + public int getDisplayedXSize() { + return this.isVertical() ? super.getDisplayedYSize() : super.getDisplayedXSize(); + } + + @Override + public int getDisplayedYSize() { + return this.isVertical() ? super.getDisplayedXSize() : super.getDisplayedYSize(); + } + + @Override + public int getTrueXSize() { + return this.isVertical() ? super.getTrueYSize() : super.getTrueXSize(); + } + + @Override + public int getTrueYSize() { + return this.isVertical() ? super.getTrueXSize() : super.getTrueYSize(); + } + + @Override + public boolean isVisible() { + if (mc.thePlayer == null) { + return GameSettings.IMMERSIVE_MODE.drawHotbar(); + } + return GameSettings.IMMERSIVE_MODE.drawHotbar() && + !mc.thePlayer.getGamemode().hasInvulnerablePlayer() && + mc.thePlayer.getGamemode().hasToolDurability() && + mc.thePlayer.shouldShowAcidVisualEffects() && + !GameSettings.HIDE_ACID_BAR.value; + } + + @Override + public boolean isPreviewTranslucent() { + return GameSettings.HIDE_ACID_BAR.value; + } + + @Override + public void render(HudIngame hud, int xSizeScreen, int ySizeScreen, float partialTick) { + int x = this.getLayout().getComponentX(this, xSizeScreen); + int y = this.getLayout().getComponentY(this, ySizeScreen); + + GLRenderer.setColor4f(1.0f, 1.0f, 1.0f, 1.0f); + GLRenderer.enableState(State.BLEND); + + // One icon per acid buildup segment in fluid; after leaving fluid the bar eases down over about one second. + final int cycles = mc.thePlayer.getAcidHudBarFillTicks(); + final int iconCount = cycles <= 0 ? 0 : Math.min(ACID_BAR_MAX_ICONS, cycles); + + boolean isVertical = this.isVertical(); + boolean isFlipped = this.isFlipped(); + + for (int i = 0; i < iconCount; i++) { + int xIcon; + int yIcon; + + if (isVertical) { + xIcon = x; + yIcon = isFlipped ? (y + i * 8) : (y + (9 - i) * 8); + } else { + xIcon = isFlipped ? (x + (9 - i) * 8) : (x + i * 8); + yIcon = y; + } + + hud.drawGuiIcon(xIcon, yIcon, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/acid")); + } + } + + @Override + public void renderPreview(Gui gui, Layout layout, int xSizeScreen, int ySizeScreen) { + int x = layout.getComponentX(this, xSizeScreen); + int y = layout.getComponentY(this, ySizeScreen); + + GLRenderer.setColor4f(1.0f, 1.0f, 1.0f, 1.0f); + renderTranslucency(); + GLRenderer.enableState(State.BLEND); + + boolean isVertical = this.isVertical(); + boolean isFlipped = this.isFlipped(); + + int iconCount = 6; + for (int i = 0; i < iconCount; i++) { + int xIcon; + int yIcon; + + if (isVertical) { + xIcon = x; + yIcon = isFlipped ? (y + i * 8) : (y + (9 - i) * 8); + } else { + xIcon = isFlipped ? (x + (9 - i) * 8) : (x + i * 8); + yIcon = y; + } + + gui.drawGuiIcon(xIcon, yIcon, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/acid")); + } + } +} diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentArmorBar.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentArmorBar.java index e0cb5f672..881f9afa0 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentArmorBar.java +++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentArmorBar.java @@ -197,8 +197,9 @@ public class HudComponentArmorBar extends HudComponentMovable { int iconY = y; - if (piece.maxDurability() > 0 && (piece.currentDurability() / piece.maxDurability()) <= 0.15 && piece.state() != ArmorState.EMPTY) { - this.random.setSeed(hud.updateCounter * 0x4c627L); + boolean inAcidWarning = mc.thePlayer != null && mc.thePlayer.shouldShowAcidVisualEffects() && mc.thePlayer.getGamemode().hasToolDurability(); + if (piece.maxDurability() > 0 && ((piece.currentDurability() / piece.maxDurability()) <= 0.15 || inAcidWarning) && piece.state() != ArmorState.EMPTY) { + this.random.setSeed(hud.updateCounter * 0x4c627L + (long) this.targetShape.getSlotIndex() * 0x9e3779b9L); iconY += this.random.nextInt(2); } @@ -208,7 +209,7 @@ public class HudComponentArmorBar extends HudComponentMovable { boolean isFlipped = this.isFlipped(); hud.drawGuiIcon(x, iconY, 9, 9, getIconForState(piece, isFlipped)); - drawDurabilityBar(hud, x, y, piece.state(), piece.currentDurability(), piece.maxDurability(), 0xFF, isFlipped); + drawDurabilityBar(hud, x, y, piece.state(), piece.currentDurability(), piece.maxDurability(), 0xFF, isFlipped, inAcidWarning); GLRenderer.disableState(State.BLEND); } @@ -237,12 +238,12 @@ public class HudComponentArmorBar extends HudComponentMovable { boolean isFlipped = this.isFlipped(); gui.drawGuiIcon(x, y, 9, 9, getIconForState(previewPiece, isFlipped)); - drawDurabilityBar(gui, x, y, previewPiece.state(), previewPiece.currentDurability(), previewPiece.maxDurability(), alpha, isFlipped); + drawDurabilityBar(gui, x, y, previewPiece.state(), previewPiece.currentDurability(), previewPiece.maxDurability(), alpha, isFlipped, false); GLRenderer.disableState(State.BLEND); } - private void drawDurabilityBar(Gui gui, int x, int y, ArmorState state, double currentDurability, double maxDurability, int alpha, boolean isFlipped) { + private void drawDurabilityBar(Gui gui, int x, int y, ArmorState state, double currentDurability, double maxDurability, int alpha, boolean isFlipped, boolean acidWarning) { int barMaxWidth = 9; int barY = y + 10; @@ -261,8 +262,16 @@ public class HudComponentArmorBar extends HudComponentMovable { int barWidth = (int) Math.round((currentDurability / maxDurability) * barMaxWidth); int progress = (int) Math.round((currentDurability / maxDurability) * 255D); - int colorFG = java.awt.Color.HSBtoRGB(progress / 255F / 3F, 1f, 1f); - int colorBG = ((0xFF - progress) / 4) << 16 | 0x3f00; + int colorFG; + int colorBG; + if (acidWarning) { + float t = progress / 255F; + colorFG = java.awt.Color.HSBtoRGB(0.11F + t * 0.06F, 1f, 1f); + colorBG = java.awt.Color.HSBtoRGB(0.11F, 1f, 0.35f); + } else { + colorFG = java.awt.Color.HSBtoRGB(progress / 255F / 3F, 1f, 1f); + colorBG = ((0xFF - progress) / 4) << 16 | 0x3f00; + } colorFG = (colorFG & 0x00FFFFFF) | a; colorBG = (colorBG & 0x00FFFFFF) | a; diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentArmorDurability.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentArmorDurability.java index d6526d6fd..61b62f7dc 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentArmorDurability.java +++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentArmorDurability.java @@ -12,6 +12,8 @@ import net.minecraft.core.item.ItemStack; import net.minecraft.core.item.Items; import net.minecraft.core.util.helper.LightIndexHelper; +import java.awt.*; + public class HudComponentArmorDurability extends HudComponentMovable { private static final ItemStack[] PREVIEW_STACKS = new ItemStack[]{ @@ -53,7 +55,10 @@ public class HudComponentArmorDurability float durability = (stack.getMaxDamage() - stack.getMetadata()) / (float) stack.getMaxDamage(); int l = (int) (durability * 255); - final int i1 = 255 - l << 16 | l << 8; + final boolean inAcidWarning = mc.thePlayer != null && mc.thePlayer.shouldShowAcidVisualEffects() && mc.thePlayer.getGamemode().hasToolDurability(); + final int i1 = inAcidWarning + ? Color.HSBtoRGB(0.11F + (durability * 0.06F), 1f, 1f) + : (255 - l << 16 | l << 8); mc.font.render(String.valueOf((stack.getMaxDamage() - stack.getMetadata()) + 1), xx + 20, yy + 4).setShadow().setColor(i1).call(); } diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponents.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponents.java index 6dbdda565..7e410dbd0 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponents.java +++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponents.java @@ -104,6 +104,12 @@ public class HudComponents { .addAttachedOption(GameSettings.VERTICAL_FIRE_BAR, () -> new BooleanOptionComponent(GameSettings.VERTICAL_FIRE_BAR)) .addAttachedOption(GameSettings.FLIP_FIRE_BAR, () -> new BooleanOptionComponent(GameSettings.FLIP_FIRE_BAR)) ); + public static final @NotNull HudComponentAcidBar ACID_BAR = register( + new HudComponentAcidBar("acid_bar", new LayoutSnap(FIRE_BAR, ComponentAnchor.TOP_LEFT, ComponentAnchor.BOTTOM_LEFT, 0, -1)) + .addAttachedOption(GameSettings.HIDE_ACID_BAR, () -> new BooleanOptionComponent(GameSettings.HIDE_ACID_BAR)) + .addAttachedOption(GameSettings.VERTICAL_ACID_BAR, () -> new BooleanOptionComponent(GameSettings.VERTICAL_ACID_BAR)) + .addAttachedOption(GameSettings.FLIP_ACID_BAR, () -> new BooleanOptionComponent(GameSettings.FLIP_ACID_BAR)) + ); public static final @NotNull HudComponentRotationLock ROTATION_LOCK = register( new HudComponentRotationLock("rotation_lock", new LayoutSnap(CROSSHAIR, ComponentAnchor.CENTER_RIGHT, ComponentAnchor.CENTER_LEFT)) .addAttachedKeyBinding(GameSettings.KEY_LOCK_ROTATION, () -> new KeyBindingComponent(GameSettings.KEY_LOCK_ROTATION)) diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java b/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java index 601296ecc..0b24fbbc7 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java +++ b/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java @@ -181,7 +181,7 @@ public abstract class OptionsPages { .withComponent(new ToggleableOptionComponent<>(GameSettings.LEAVES_QUALITY).applyOnRelease()) .withComponent(new ToggleableOptionComponent<>(GameSettings.PARTICLES_QUALITY)) .withComponent(new ToggleableOptionComponent<>(GameSettings.PARTICLES_CAP)) - .withComponent(new FloatOptionComponent(GameSettings.PARTICLE_RENDER_DISTANCE, 0.1f, 3f)) + .withComponent(new ToggleableOptionComponent<>(GameSettings.PARTICLE_RENDER_DISTANCE)) .withComponent(new FloatOptionComponent(GameSettings.ENTITY_RENDER_DISTANCE, 0.1f, 3f)) .withComponent(new BooleanOptionComponent(GameSettings.ENTITY_SHADOWS)) .withComponent(new ToggleableOptionComponent<>(GameSettings.CLOUD_QUALITY)) diff --git a/game/client/src/main/java/net/minecraft/client/option/GameSettings.java b/game/client/src/main/java/net/minecraft/client/option/GameSettings.java index c1a723abd..7710c043e 100644 --- a/game/client/src/main/java/net/minecraft/client/option/GameSettings.java +++ b/game/client/src/main/java/net/minecraft/client/option/GameSettings.java @@ -132,14 +132,13 @@ public final class GameSettings { public static final @NotNull OptionBoolean VIEW_BOBBING = register(new OptionBoolean("bobView", true)); public static final @NotNull OptionBoolean TRANSPARENCY_DEPTH_CHECK = register(new OptionBoolean("transparencyDepthCheck", true)); public static final @NotNull OptionEnum PARTICLES_QUALITY = register(new OptionEnum<>("particleQuality", ParticlesQuality.class, ParticlesQuality.ALL)); - public static final @NotNull OptionRange PARTICLES_CAP = register(new OptionRange("particleCap", 4000, 500, 15000)); - public static final @NotNull OptionFloat PARTICLE_RENDER_DISTANCE = register(new OptionFloat("particleRenderDistance", 1f) - .withDisplayStringProvider((mc, i18n, option) -> { - int percent = MathHelper.round(option.value * 100.0f); - if (percent == 100) { - return i18n.translateKey("options.particleRenderDistance.default"); + public static final @NotNull OptionRange PARTICLES_CAP = register(new OptionRange("particleCap", 50000, 1000, 100000)); + public static final @NotNull OptionRange PARTICLE_RENDER_DISTANCE = register(new OptionRange("particleRenderDistance", 12, 1, 24) + .addOnChangeCallback((mc, option) -> { + if (mc.currentScreen instanceof ScreenOptions) { + ScreenOptions.queueReload = true; } else { - return percent + "%"; + mc.renderGlobal.allChanged(); } })); public static final @NotNull OptionRange CHUNK_REBUILDS_PER_FRAME = register(new OptionRange("chunkRebuilds", 6, 2, 12)); @@ -472,6 +471,7 @@ public final class GameSettings { public static final @NotNull OptionBoolean HIDE_HEALTH_BAR = register(new OptionBoolean("hideHealthBar", false)); public static final @NotNull OptionBoolean HIDE_OXYGEN_BAR = register(new OptionBoolean("hideOxygenBar", false)); public static final @NotNull OptionBoolean HIDE_FIRE_BAR = register(new OptionBoolean("hideFireBar", false)); + public static final @NotNull OptionBoolean HIDE_ACID_BAR = register(new OptionBoolean("hideAcidBar", false)); public static final @NotNull OptionBoolean HIDE_VEHICLE_BAR = register(new OptionBoolean("hideVehicleBar", false)); public static final @NotNull OptionBoolean HIDE_DYNAMIC_TOOLTIP = register(new OptionBoolean("hideDynamicTooltip", false)); public static final @NotNull OptionBoolean HIDE_HELD_ITEM_COUNT = register(new OptionBoolean("hideHeldItemCount", true)); @@ -499,6 +499,7 @@ public final class GameSettings { public static final @NotNull OptionBoolean VERTICAL_OXYGEN_BAR = register(new OptionBoolean("verticalOxygenBar", false)); public static final @NotNull OptionBoolean VERTICAL_VEHICLE_BAR = register(new OptionBoolean("verticalVehicleBar", false)); public static final @NotNull OptionBoolean VERTICAL_FIRE_BAR = register(new OptionBoolean("verticalFireBar", false)); + public static final @NotNull OptionBoolean VERTICAL_ACID_BAR = register(new OptionBoolean("verticalAcidBar", false)); public static final @NotNull OptionBoolean FLIP_HELD_ITEM_COUNT = register(new OptionBoolean("flipHeldItemCount", false)); public static final @NotNull OptionBoolean FLIP_HELMET_BAR = register(new OptionBoolean("flipHelmetBar", false)); @@ -509,6 +510,7 @@ public final class GameSettings { public static final @NotNull OptionBoolean FLIP_OXYGEN_BAR = register(new OptionBoolean("flipOxygenBar", false)); public static final @NotNull OptionBoolean FLIP_VEHICLE_BAR = register(new OptionBoolean("flipVehicleBar", false)); public static final @NotNull OptionBoolean FLIP_FIRE_BAR = register(new OptionBoolean("flipFireBar", false)); + public static final @NotNull OptionBoolean FLIP_ACID_BAR = register(new OptionBoolean("flipAcidBar", false)); public static final @NotNull OptionEnum HORIZONTAL_INFO_TEXT_ALIGNMENT = register( new OptionEnum<>("horizontalInfoTextAlignment", HorizontalTextAlignment.class, HorizontalTextAlignment.LEFT) @@ -693,7 +695,11 @@ public final class GameSettings { Option option = getOption(key); if (option != null) { - option.fromOptionsString(value); + try { + option.fromOptionsString(value); + } catch (Exception e) { + LOGGER.error("Failed to load option '{}'", option.id, e); + } continue; } diff --git a/game/client/src/main/java/net/minecraft/client/player/controller/PlayerController.java b/game/client/src/main/java/net/minecraft/client/player/controller/PlayerController.java index 118ad0166..a9a0ac06d 100644 --- a/game/client/src/main/java/net/minecraft/client/player/controller/PlayerController.java +++ b/game/client/src/main/java/net/minecraft/client/player/controller/PlayerController.java @@ -8,8 +8,6 @@ import net.minecraft.core.InventoryAction; import net.minecraft.core.block.Block; import net.minecraft.core.block.BlockLogic; import net.minecraft.core.block.BlockLogicDoor; -import net.minecraft.core.block.BlockLogicFenceGate; -import net.minecraft.core.block.BlockLogicTrapDoor; import net.minecraft.core.block.Blocks; import net.minecraft.core.block.entity.TileEntity; import net.minecraft.core.entity.Entity; diff --git a/game/client/src/main/java/net/minecraft/client/render/ClientFireOverlayHelper.java b/game/client/src/main/java/net/minecraft/client/render/ClientFireOverlayHelper.java new file mode 100644 index 000000000..ee6f726ce --- /dev/null +++ b/game/client/src/main/java/net/minecraft/client/render/ClientFireOverlayHelper.java @@ -0,0 +1,25 @@ +package net.minecraft.client.render; + +import net.minecraft.core.entity.Entity; +import net.minecraft.core.block.Blocks; +import net.minecraft.core.block.tag.BlockTags; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public final class ClientFireOverlayHelper { + private ClientFireOverlayHelper() { + } + + public static @NotNull String getFireOverlayTexture(final @Nullable Entity entity) { + if (entity == null || entity.activeFireBlock == null) { + return "minecraft:block/fire"; + } + + if (entity.activeFireBlock == Blocks.FIRE_SULFURIC || + entity.activeFireBlock.hasTag(BlockTags.SULFURIC_FIRE_OVERLAY_SOURCE)) { + return "minecraft:block/fire_sulfuric"; + } + + return "minecraft:block/fire"; + } +} \ No newline at end of file diff --git a/game/client/src/main/java/net/minecraft/client/render/FogManager.java b/game/client/src/main/java/net/minecraft/client/render/FogManager.java index f179204db..f18de7261 100644 --- a/game/client/src/main/java/net/minecraft/client/render/FogManager.java +++ b/game/client/src/main/java/net/minecraft/client/render/FogManager.java @@ -17,7 +17,6 @@ import net.minecraft.client.gui.modelviewer.ScreenModelViewer; import net.minecraft.client.render.camera.CameraUtil; import net.minecraft.client.render.colorizer.Colorizers; import net.minecraft.core.util.helper.MathHelper; -import net.minecraft.core.world.Dimension; import org.lwjgl.opengl.GL41; public class FogManager { @@ -32,6 +31,7 @@ public class FogManager { public float fogBrightnessOld; public float fogBrightness; + private float oldWorldFogTransition = 0.0f; public FogManager(@NotNull Minecraft mc) { this.mc = mc; @@ -60,6 +60,8 @@ public class FogManager { cameraState = 1; } else if (CameraUtil.isUnderLiquid(this.mc.activeCamera, this.mc.currentWorld, Materials.LAVA, partialTick)) { cameraState = 2; + } else if (CameraUtil.isUnderLiquid(this.mc.activeCamera, this.mc.currentWorld, Materials.ACID, partialTick)) { + cameraState = 3; } else { cameraState = 0; } @@ -79,6 +81,13 @@ public class FogManager { dest.fogDensity = 2.0f; break; } + case 3: { + dest.fogMode = FogState.Mode.EXP; + dest.fogDensity = 1.2F; + dest.fogStart = 0.0f; + dest.fogEnd = 0.1f; + break; + } default: { float fogDistance = farPlaneDistance; float maxFogDistance = GameSettings.RENDER_DISTANCE.highest * 16; @@ -105,6 +114,23 @@ public class FogManager { } } } + + TilePos cameraTile = this.mc.activeCamera.getTilePos(); + float fogTransitionSpeed = 0.0005f; + + if (this.mc.currentWorld.getBlockBiome(cameraTile) == net.minecraft.core.world.biome.Biomes.NETHER_OLD_WORLD) { + oldWorldFogTransition += fogTransitionSpeed; + } else { + oldWorldFogTransition -= fogTransitionSpeed; + } + + oldWorldFogTransition = MathHelper.clamp(oldWorldFogTransition, 0.0f, 1.0f); + + if (oldWorldFogTransition > 0.0f) { + dest.fogStart = dest.fogStart + (farPlaneDistance * 0.15F - dest.fogStart) * oldWorldFogTransition; + dest.fogEnd = dest.fogEnd + (farPlaneDistance * 0.45F - dest.fogEnd) * oldWorldFogTransition; + } + return dest; } @@ -167,6 +193,10 @@ public class FogManager { this.fogRed = 0.6F; this.fogGreen = 0.1F; this.fogBlue = 0.0F; + } else if (CameraUtil.isUnderLiquid(this.mc.activeCamera, world, Materials.ACID, partialTick)) { + this.fogRed = 0.2F; + this.fogGreen = 0.2F; + this.fogBlue = 0.1F; } float brightness = this.fogBrightnessOld + (this.fogBrightness - this.fogBrightnessOld) * partialTick; diff --git a/game/client/src/main/java/net/minecraft/client/render/ItemRenderer.java b/game/client/src/main/java/net/minecraft/client/render/ItemRenderer.java index c6d75ba27..98ec47006 100644 --- a/game/client/src/main/java/net/minecraft/client/render/ItemRenderer.java +++ b/game/client/src/main/java/net/minecraft/client/render/ItemRenderer.java @@ -20,6 +20,7 @@ import net.minecraft.client.render.tessellator.TessellatorGeneral; import net.minecraft.core.block.Block; import net.minecraft.core.entity.Entity; import net.minecraft.core.item.ItemStack; +import net.minecraft.core.util.helper.LightIndexHelper; import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.world.pos.TilePos; import org.joml.Math; @@ -142,7 +143,6 @@ public class ItemRenderer { GLRenderer.disableState(State.DEPTH_TEST); if (this.mc.thePlayer.isOnFire()) { - TextureRegistry.worldAtlas.bind(); renderFireInFirstPerson(partialTicks); } @@ -242,35 +242,49 @@ public class ItemRenderer { GLRenderer.popFrame(); } - private void renderFireInFirstPerson(float f) { - TessellatorGeneral tessellator = GLRenderer.getTessellator(); + private void renderFireInFirstPerson(float partialTick) { + final TessellatorGeneral tessellator = GLRenderer.getTessellator(); + + final String texturePath = ClientFireOverlayHelper.getFireOverlayTexture(this.mc.thePlayer); + final IconCoordinate texture = TextureRegistry.getTexture(texturePath); + + texture.parentAtlas.bind(); + GLRenderer.setColor4f(1.0F, 1.0F, 1.0F, 0.85F); GLRenderer.enableState(State.BLEND); GLRenderer.setBlendFunc(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA); - float scale = 1.5f; + + final boolean lightingWasOn = GLRenderer.globalGetLightEnabled(); + GLRenderer.globalSetLightEnabled(false); + final byte restoreLightmap = this.mc.thePlayer.getLightIndex(partialTick); + GLRenderer.setLightmapCoord1i(LightIndexHelper.lightIndex2i(15, 15)); + + final float scale = 1.5f; for (int i = 0; i < 2; i++) { GLRenderer.pushFrame(); - IconCoordinate texture = TextureRegistry.getTexture("minecraft:block/fire"); - float uMin = (float) texture.getIconUMin(); - float uMax = (float) texture.getIconUMax(); - float vMin = (float) texture.getIconVMin(); - float vMax = (float) texture.getIconVMax(); - float xMin = (0.0F - scale) / 2.0F; - float xMax = xMin + scale; - float yMin = 0.0F - scale / 2.0F; - float yMax = yMin + scale; - float f10 = -0.5F; + final float uMin = (float) texture.getIconUMin(); + final float uMax = (float) texture.getIconUMax(); + final float vMin = (float) texture.getIconVMin(); + final float vMax = (float) texture.getIconVMax(); + final float xMin = (0.0F - scale) / 2.0F; + final float xMax = xMin + scale; + final float yMin = 0.0F - scale / 2.0F; + final float yMax = yMin + scale; + final float zPlane = -0.5F; GLRenderer.modelM4f().translate((float) (-(i * 2 - 1)) * 0.4F, -0.3F, 0.0F); GLRenderer.modelM4f().rotateY(Math.toRadians((float) (i * 2 - 1) * 10F)); tessellator.startDrawingQuads(); - tessellator.addVertexWithUV(xMin, yMin - 0.5, f10, uMax, vMax); - tessellator.addVertexWithUV(xMax, yMin - 0.5, f10, uMin, vMax); - tessellator.addVertexWithUV(xMax, yMax, f10, uMin, vMin); - tessellator.addVertexWithUV(xMin, yMax, f10, uMax, vMin); + tessellator.addVertexWithUV(xMin, yMin - 0.5, zPlane, uMax, vMax); + tessellator.addVertexWithUV(xMax, yMin - 0.5, zPlane, uMin, vMax); + tessellator.addVertexWithUV(xMax, yMax, zPlane, uMin, vMin); + tessellator.addVertexWithUV(xMin, yMax, zPlane, uMax, vMin); tessellator.draw(); GLRenderer.popFrame(); } + GLRenderer.setLightmapCoord1i(restoreLightmap); + GLRenderer.globalSetLightEnabled(lightingWasOn); + GLRenderer.setColor4f(1.0F, 1.0F, 1.0F, 1.0F); GLRenderer.disableState(State.BLEND); } diff --git a/game/client/src/main/java/net/minecraft/client/render/ParticleEngine.java b/game/client/src/main/java/net/minecraft/client/render/ParticleEngine.java index 3158261e4..79a2c9bfa 100644 --- a/game/client/src/main/java/net/minecraft/client/render/ParticleEngine.java +++ b/game/client/src/main/java/net/minecraft/client/render/ParticleEngine.java @@ -1,11 +1,13 @@ package net.minecraft.client.render; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.client.Minecraft; import net.minecraft.client.option.GameSettings; import net.minecraft.client.option.enums.ParticlesQuality; import net.minecraft.client.render.camera.ICamera; import net.minecraft.client.render.particle.Particle; import net.minecraft.client.render.particle.ParticleBlockBreaking; +import net.minecraft.client.render.particle.ParticleFlame; import net.minecraft.client.render.renderer.BlendFactor; import net.minecraft.client.render.renderer.CompareFunc; import net.minecraft.client.render.renderer.GLRenderer; @@ -16,15 +18,20 @@ import net.minecraft.client.render.tessellator.TessellatorParticle; import net.minecraft.client.render.tessellator.TessellatorParticleShader; import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.core.block.Block; +import net.minecraft.core.block.BlockLogicFire; import net.minecraft.core.block.Blocks; +import net.minecraft.core.entity.player.Player; import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.World; import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; +import org.joml.primitives.AABBd; import org.joml.primitives.AABBdc; import org.lwjgl.opengl.GL41; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Random; /** @@ -40,6 +47,11 @@ public final class ParticleEngine { private final List[] particles; private final Random rand; + private final Map, ObjectArrayList> particlePools = new HashMap<>(); + private final AABBd cullingAABB = new AABBd(); + private int globalTick = 0; + private double lastCamX, lastCamY, lastCamZ; + public ParticleEngine(World world) { this.particles = new ObjectArrayList[TEXTURE_COUNT]; this.rand = new Random(); @@ -54,27 +66,76 @@ public final class ParticleEngine { /** * Adds a new particle to the engine. * - * @param p The particle to add. + * @param particle The particle to add. */ - public void add(Particle p) { - int t = p.getParticleTexture(); + public void add(@NotNull Particle particle) { + int t = particle.getParticleTexture(); + if (this.particles[t].size() >= GameSettings.PARTICLES_CAP.value) { - this.particles[t].remove(0); + // Find the furthest particle to delete instead of just the oldest + int indexToRemove = getIndexToRemove(t); + + // Return the furthest particle to the Object Pool + Particle removed = this.particles[t].remove(indexToRemove); + ObjectArrayList pool = this.particlePools.computeIfAbsent(removed.getClass(), k -> new ObjectArrayList<>()); + if (pool.size() < GameSettings.PARTICLES_CAP.value) { + pool.add(removed); + } + } + + this.particles[t].add(particle); + particle.init(); + } + + private int getIndexToRemove(int t) { + int indexToRemove = 0; + double maxDistSq = -1; + + // Only scan a handful of particles to avoid CPU lag when overflowing + int scanLimit = Math.min(50, this.particles[t].size()); + + for (int i = 0; i < scanLimit; i++) { + Particle check = this.particles[t].get(i); + double distSq = (check.x - lastCamX)*(check.x - lastCamX) + + (check.y - lastCamY)*(check.y - lastCamY) + + (check.z - lastCamZ)*(check.z - lastCamZ); + + if (distSq > maxDistSq) { + maxDistSq = distSq; + indexToRemove = i; + } } - this.particles[t].add(p); - p.init(); + return indexToRemove; } /** * Ticks all the particles in the engine. */ public void tick() { + this.globalTick++; + + Player localPlayer = this.world.players.isEmpty() ? null : this.world.players.get(0); + if (localPlayer != null) { + this.world.particleEmitters.tick(this.world, localPlayer, GameSettings.PARTICLE_RENDER_DISTANCE.value); + } + for (int tt = 0; tt < this.particles.length; tt++) { for (int i = 0; i < this.particles[tt].size(); i++) { Particle p = this.particles[tt].get(i); + p.tick(); if (p.removed) { this.particles[tt].remove(i--); + + Class c = p.getClass(); + ObjectArrayList pl = this.particlePools.get(c); + if (pl == null) { + pl = new ObjectArrayList<>(); + this.particlePools.put(c, pl); + } + if (pl.size() < GameSettings.PARTICLES_CAP.value) { + pl.add(p); + } } } } @@ -107,14 +168,40 @@ public final class ParticleEngine { double yOff = camera.getY(partialTick); double zOff = camera.getZ(partialTick); - for (int tt = 0; tt <= WORLD_TEXTURE; tt++) { - if (this.particles[tt].isEmpty()) { - continue; - } + this.lastCamX = xOff; + this.lastCamY = yOff; + this.lastCamZ = zOff; + + double maxDist = GameSettings.PARTICLE_RENDER_DISTANCE.value * 16.0; + double maxRenderDistSq = maxDist * maxDist; + boolean frustumCull = GameSettings.FRUSTUM_CULLING.value; + + for (int tt = 0; tt == WORLD_TEXTURE; tt++) { + if (this.particles[tt].isEmpty()) continue; + tessellator.setTranslation(-xOff, -yOff, -zOff); tessellator.startDrawingParticles(); + for (int i = 0; i < this.particles[tt].size(); i++) { Particle p = this.particles[tt].get(i); + + double distSq = (p.x - xOff)*(p.x - xOff) + (p.y - yOff)*(p.y - yOff) + (p.z - zOff)*(p.z - zOff); + if (distSq > maxRenderDistSq) continue; + + if (frustumCull) { + double lerpX = net.minecraft.core.util.helper.MathHelper.lerp(p.xo, p.x, partialTick); + double lerpY = net.minecraft.core.util.helper.MathHelper.lerp(p.yo, p.y, partialTick); + double lerpZ = net.minecraft.core.util.helper.MathHelper.lerp(p.zo, p.z, partialTick); + double r = p.size * 0.1; + + this.cullingAABB.setMin(lerpX - r, lerpY - r, lerpZ - r); + this.cullingAABB.setMax(lerpX + r, lerpY + r, lerpZ + r); + + if (!camera.getFrustum().isVisible(this.cullingAABB, partialTick)) { + continue; + } + } + p.render(tessellator, partialTick); } tessellator.drawParticles(); @@ -123,6 +210,15 @@ public final class ParticleEngine { GLRenderer.popFrame(); } + @SuppressWarnings("unchecked") + private T getPooledParticle(Class type) { + ObjectArrayList pool = this.particlePools.computeIfAbsent(type, k -> new ObjectArrayList<>()); + if (!pool.isEmpty()) { + return (T) pool.remove(pool.size() - 1); + } + return null; + } + /** * Renders all the particles in the engine whose texture type is ENTITY_PARTICLE_TEXTURE. * These particles are drawn using OpenGL normal-based lighting, unlike the other particles, @@ -139,17 +235,14 @@ public final class ParticleEngine { double xOff = camera.getX(partialTick); double yOff = camera.getY(partialTick); double zOff = camera.getZ(partialTick); - TessellatorGeneral tessellator = GLRenderer.getTessellator(); for (int i = 0; i < this.particles[tt].size(); i++) { Particle p = this.particles[tt].get(i); p.renderLit(partialTick, xOff, yOff, zOff); } - } /** * Sets the world used to contain any managed particles. - * * @param world The world to use. */ public void setWorld(World world) { @@ -169,19 +262,41 @@ public final class ParticleEngine { public void destroy(@NotNull TilePosc blockPos, int id, int data) { if (GameSettings.PARTICLES_QUALITY.value == ParticlesQuality.NONE) return; Block block = Blocks.blocksList[id]; - if (block == null) return; + if (block == null || block.getLogic() instanceof BlockLogicFire) return; int amount = GameSettings.PARTICLES_QUALITY.value == ParticlesQuality.REDUCED ? 2 : 4; - if (block == Blocks.FIRE) { - return; - } + + AABBdc bounds = block.getLogic().getBoundsFromState(this.world, blockPos); + + double centerX = (bounds.minX() + bounds.maxX()) / 2.0D; + double centerY = (bounds.minY() + bounds.maxY()) / 2.0D; + double centerZ = (bounds.minZ() + bounds.maxZ()) / 2.0D; + for (int xx = 0; xx < amount; xx++) { for (int yy = 0; yy < amount; yy++) { for (int zz = 0; zz < amount; zz++) { - double xp = blockPos.x() + (xx + 0.5D) / amount; - double yp = blockPos.y() + (yy + 0.5D) / amount; - double zp = blockPos.z() + (zz + 0.5D) / amount; + + double percentX = (xx + 0.5D) / amount; + double percentY = (yy + 0.5D) / amount; + double percentZ = (zz + 0.5D) / amount; + + double xp = blockPos.x() + bounds.minX() + (bounds.maxX() - bounds.minX()) * percentX; + double yp = blockPos.y() + bounds.minY() + (bounds.maxY() - bounds.minY()) * percentY; + double zp = blockPos.z() + bounds.minZ() + (bounds.maxZ() - bounds.minZ()) * percentZ; + Side side = Side.fromId(this.rand.nextInt(6)); - add((new ParticleBlockBreaking(this.world, xp, yp, zp, xp - blockPos.x() - 0.5D, yp - blockPos.y() - 0.5D, zp - blockPos.z() - 0.5D, block, side, data)).init(blockPos)); + + double velX = xp - blockPos.x() - centerX; + double velY = yp - blockPos.y() - centerY; + double velZ = zp - blockPos.z() - centerZ; + + ParticleBlockBreaking particle = getPooledParticle(ParticleBlockBreaking.class); + if (particle == null) { + particle = new ParticleBlockBreaking(this.world, xp, yp, zp, velX, velY, velZ, block, side, data); + } else { + particle.reset(this.world, xp, yp, zp, velX, velY, velZ, block, side, data); + } + + add(particle.init(blockPos)); } } } @@ -199,7 +314,9 @@ public final class ParticleEngine { if (block == Blocks.AIR) { return; } - AABBdc bounds = block.getBounds(); + + AABBdc bounds = block.getLogic().getBoundsFromState(this.world, blockPos); + float r = 0.1F; double xp = blockPos.x() + this.rand.nextDouble() * (bounds.maxX() - bounds.minX() - (r * 2.0F)) + r + bounds.minX(); double yp = blockPos.y() + this.rand.nextDouble() * (bounds.maxY() - bounds.minY() - (r * 2.0F)) + r + bounds.minY(); @@ -217,10 +334,26 @@ public final class ParticleEngine { } else if (side == Side.EAST) { xp = blockPos.x() + bounds.maxX() + r; } - add((new ParticleBlockBreaking(this.world, xp, yp, zp, 0.0D, 0.0D, 0.0D, block, side, this.world.getBlockData(blockPos))).init(blockPos).setPower(0.2F).setScale(0.6F)); + + ParticleBlockBreaking p = getPooledParticle(ParticleBlockBreaking.class); + if (p == null) { + p = new ParticleBlockBreaking(this.world, xp, yp, zp, 0.0D, 0.0D, 0.0D, block, side, this.world.getBlockData(blockPos)); + } else { + p.reset(this.world, xp, yp, zp, 0.0D, 0.0D, 0.0D, block, side, this.world.getBlockData(blockPos)); + } + + add(p.init(blockPos).setPower(0.2F).setScale(0.6F)); } public int countParticles() { return this.particles[WORLD_TEXTURE].size() + this.particles[ENTITY_PARTICLE_TEXTURE].size(); } + + public int getGlobalTick() { + return globalTick; + } + + public void setGlobalTick(int globalTick) { + this.globalTick = globalTick; + } } diff --git a/game/client/src/main/java/net/minecraft/client/render/RenderGlobal.java b/game/client/src/main/java/net/minecraft/client/render/RenderGlobal.java index 42dd596ca..0dae10083 100644 --- a/game/client/src/main/java/net/minecraft/client/render/RenderGlobal.java +++ b/game/client/src/main/java/net/minecraft/client/render/RenderGlobal.java @@ -1995,6 +1995,19 @@ public class RenderGlobal } break; + + case EVENT_ACID_SPREAD: + this.world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, (double) x + 0.5D, (double) y + 0.5D, (double) z + 0.5D, "tile.acidbubble", 0.75F, 1.0F); + this.world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, (double) x + 0.5D, (double) y + 0.5D, (double) z + 0.5D, "random.fizz", 0.5F, 2.6F + (random.nextFloat() - random.nextFloat()) * 0.8F); + + for (int i = 0; i < 10; i++) { + double fx = (double) x + random.nextFloat(); + double fy = (double) y + random.nextFloat() * 0.5D; + double fz = (double) z + random.nextFloat(); + + addParticle("acidBoiling", fx, fy + 0.15, fz, 0.0D, 0.0D, 0.0D, 0, false); + } + break; default: break; } diff --git a/game/client/src/main/java/net/minecraft/client/render/TextureManager.java b/game/client/src/main/java/net/minecraft/client/render/TextureManager.java index 46f862f48..9bb97417d 100644 --- a/game/client/src/main/java/net/minecraft/client/render/TextureManager.java +++ b/game/client/src/main/java/net/minecraft/client/render/TextureManager.java @@ -25,18 +25,7 @@ import net.minecraft.client.option.GameSettings; import net.minecraft.client.option.enums.TextureAnimation; import net.minecraft.client.render.colorizer.Colorizers; import net.minecraft.client.render.customatlas.CustomAtlasHandler; -import net.minecraft.client.render.dynamictexture.DynamicTexture; -import net.minecraft.client.render.dynamictexture.DynamicTextureCalendar; -import net.minecraft.client.render.dynamictexture.DynamicTextureClock; -import net.minecraft.client.render.dynamictexture.DynamicTextureCompass; -import net.minecraft.client.render.dynamictexture.DynamicTextureCustom; -import net.minecraft.client.render.dynamictexture.DynamicTextureFire; -import net.minecraft.client.render.dynamictexture.DynamicTextureFireflyJar; -import net.minecraft.client.render.dynamictexture.DynamicTextureLavaFlowing; -import net.minecraft.client.render.dynamictexture.DynamicTextureLavaStill; -import net.minecraft.client.render.dynamictexture.DynamicTextureTrommel; -import net.minecraft.client.render.dynamictexture.DynamicTextureWaterFlow; -import net.minecraft.client.render.dynamictexture.DynamicTextureWaterStill; +import net.minecraft.client.render.dynamictexture.*; import net.minecraft.client.render.font.Fonts; import net.minecraft.client.render.texture.meta.AnimationProperties; import net.minecraft.client.render.texture.stitcher.AtlasStitcher; @@ -108,12 +97,13 @@ public class TextureManager { } protected void addNativeDynamicTextures(@NotNull TextureAnimation state) { - if (state != TextureAnimation.OFF) {addDynamicTexture(new DynamicTextureWaterStill(TextureRegistry.getTexture("minecraft:block/water_still"), TextureRegistry.getTexture("minecraft:block/water_overlay_boiling"))); - addDynamicTexture(new DynamicTextureWaterFlow(TextureRegistry.getTexture("minecraft:block/water_flowing"))); - addDynamicTexture(new DynamicTextureLavaStill(TextureRegistry.getTexture("minecraft:block/lava_still"))); - addDynamicTexture(new DynamicTextureLavaFlowing(TextureRegistry.getTexture("minecraft:block/lava_flowing"))); - addDynamicTexture(new DynamicTextureFire(TextureRegistry.getTexture("minecraft:block/fire"), false)); - addDynamicTexture(new DynamicTextureFire(TextureRegistry.getTexture("minecraft:block/fire_cold"), true)); + if (state != TextureAnimation.OFF) {addDynamicTexture(new DynamicTextureWaterStill(TextureRegistry.getTexture("minecraft:block/fluid/water/still"), TextureRegistry.getTexture("minecraft:block/fluid/water/overlay_boiling"))); + addDynamicTexture(new DynamicTextureWaterFlow(TextureRegistry.getTexture("minecraft:block/fluid/water/flowing"))); + addDynamicTexture(new DynamicTextureLavaStill(TextureRegistry.getTexture("minecraft:block/fluid/lava/still"))); + addDynamicTexture(new DynamicTextureLavaFlowing(TextureRegistry.getTexture("minecraft:block/fluid/lava/flowing"))); + addDynamicTexture(new DynamicTextureFire(TextureRegistry.getTexture("minecraft:block/fire"), false, false)); + addDynamicTexture(new DynamicTextureFire(TextureRegistry.getTexture("minecraft:block/fire_cold"), true, false)); + addDynamicTexture(new DynamicTextureFire(TextureRegistry.getTexture("minecraft:block/fire_sulfuric"), false, true)); final String[] fireflyColors = {"blue", "orange", "green", "red"}; for (final String color : fireflyColors) { diff --git a/game/client/src/main/java/net/minecraft/client/render/WorldRenderer.java b/game/client/src/main/java/net/minecraft/client/render/WorldRenderer.java index fed8bba1c..cc17ccdd1 100644 --- a/game/client/src/main/java/net/minecraft/client/render/WorldRenderer.java +++ b/game/client/src/main/java/net/minecraft/client/render/WorldRenderer.java @@ -111,6 +111,7 @@ public class WorldRenderer { this.tick++; this.itemRenderer.updateEquippedItem(); addRainParticles(); + this.lightmapHelper.tick(); } diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java index 92e9a6ad9..d2da4d3e4 100644 --- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java +++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java @@ -171,6 +171,7 @@ public final class BlockModelDispatcher addDispatch(new BlockModelGenericSlab<>(Blocks.SLAB_BRICK_SANDSTONE, loadDataModel("minecraft:block/slab/brick_sandstone/lower"), loadDataModel("minecraft:block/slab/brick_sandstone/upper"), loadDataModel("minecraft:block/slab/brick_sandstone/full"))); addDispatch(new BlockModelGenericSlab<>(Blocks.SLAB_BRICK_PERMAFROST, loadDataModel("minecraft:block/slab/brick_permafrost/lower"), loadDataModel("minecraft:block/slab/brick_permafrost/upper"), loadDataModel("minecraft:block/slab/brick_permafrost/full"))); + addDispatch(new BlockModelGenericSlab<>(Blocks.SLAB_BRICK_RUBYGLASS, loadDataModel("minecraft:block/rubyglass/slab/brick/lower"), loadDataModel("minecraft:block/rubyglass/slab/brick/upper"), loadDataModel("minecraft:block/rubyglass/slab/brick/full"))); addDispatch(new BlockModelGenericSlab<>(Blocks.SLAB_BRICK_DIAMOND, loadDataModel("minecraft:block/slab/brick_diamond/lower"), loadDataModel("minecraft:block/slab/brick_diamond/upper"), loadDataModel("minecraft:block/slab/brick_diamond/full"))); addDispatch(new BlockModelGenericSlab<>(Blocks.SLAB_BRICK_IRON, loadDataModel("minecraft:block/slab/brick_iron/lower"), loadDataModel("minecraft:block/slab/brick_iron/upper"), loadDataModel("minecraft:block/slab/brick_iron/full"))); addDispatch(new BlockModelGenericSlab<>(Blocks.SLAB_BRICK_GOLD, loadDataModel("minecraft:block/slab/brick_gold/lower"), loadDataModel("minecraft:block/slab/brick_gold/upper"), loadDataModel("minecraft:block/slab/brick_gold/full"))); @@ -198,6 +199,7 @@ public final class BlockModelDispatcher addDispatch(new BlockModelGenericStairs<>(Blocks.STAIRS_BRICK_SANDSTONE, loadDataModel("minecraft:block/stairs/brick_sandstone"))); addDispatch(new BlockModelGenericStairs<>(Blocks.STAIRS_BRICK_PERMAFROST, loadDataModel("minecraft:block/stairs/brick_permafrost"))); + addDispatch(new BlockModelGenericStairs<>(Blocks.STAIRS_BRICK_RUBYGLASS, loadDataModel("minecraft:block/rubyglass/stairs/brick"))); addDispatch(new BlockModelGenericStairs<>(Blocks.STAIRS_BRICK_DIAMOND, loadDataModel("minecraft:block/stairs/brick_diamond"))); addDispatch(new BlockModelGenericStairs<>(Blocks.STAIRS_BRICK_IRON, loadDataModel("minecraft:block/stairs/brick_iron"))); addDispatch(new BlockModelGenericStairs<>(Blocks.STAIRS_BRICK_GOLD, loadDataModel("minecraft:block/stairs/brick_gold"))); @@ -242,12 +244,12 @@ public final class BlockModelDispatcher addDispatch(new BlockModelGenericFullyRotatable<>(Blocks.BONESHALE, loadDataModel("minecraft:block/bone_shale"))); - addDispatch(new BlockModelFluid<>(Blocks.FLUID_WATER_FLOWING, "minecraft:block/water_still", "minecraft:block/water_flowing") + addDispatch(new BlockModelFluid<>(Blocks.FLUID_WATER_FLOWING, "minecraft:block/fluid/water/still", "minecraft:block/fluid/water/flowing") .onRenderLayer(1)); - addDispatch(new BlockModelFluid<>(Blocks.FLUID_WATER_STILL, "minecraft:block/water_still", "minecraft:block/water_flowing") + addDispatch(new BlockModelFluid<>(Blocks.FLUID_WATER_STILL, "minecraft:block/fluid/water/still", "minecraft:block/fluid/water/flowing") .onRenderLayer(1)); - addDispatch(new BlockModelFluid<>(Blocks.FLUID_LAVA_FLOWING, "minecraft:block/lava_still", "minecraft:block/lava_flowing")); - addDispatch(new BlockModelFluid<>(Blocks.FLUID_LAVA_STILL, "minecraft:block/lava_still", "minecraft:block/lava_flowing")); + addDispatch(new BlockModelFluid<>(Blocks.FLUID_LAVA_FLOWING, "minecraft:block/fluid/lava/still", "minecraft:block/fluid/lava/flowing")); + addDispatch(new BlockModelFluid<>(Blocks.FLUID_LAVA_STILL, "minecraft:block/fluid/lava/still", "minecraft:block/fluid/lava/flowing")); addDispatch(new BlockModelGenericAxis<>(Blocks.LOG_OAK, loadDataModel("minecraft:block/log/oak"))); addDispatch(new BlockModelGenericAxis<>(Blocks.LOG_PINE, loadDataModel("minecraft:block/log/pine"))); @@ -289,7 +291,7 @@ public final class BlockModelDispatcher addDispatch(new BlockModelGeneric<>(Blocks.ALGAE, loadDataModel("minecraft:block/algae")).render3D(false)); addDispatch(new BlockModelGeneric<>(Blocks.BONE_PILE, loadDataModel("minecraft:block/bone_pile")).render3D(false)); - addDispatch(new BlockModelGeneric<>(Blocks.SOULCATCHER, loadDataModel("minecraft:block/soul_catcher")).render3D(false)); + addDispatch(new BlockModelGeneric<>(Blocks.SOUL_CATCHER, loadDataModel("minecraft:block/soul_catcher")).render3D(false)); addDispatch(new BlockModelGenericFlowerStackable<>(Blocks.FLOWER_YELLOW, "minecraft:block/flower_yellow/").render3D(false)); addDispatch(new BlockModelGenericFlowerStackable<>(Blocks.FLOWER_RED, "minecraft:block/flower_red/").render3D(false)); @@ -344,10 +346,12 @@ public final class BlockModelDispatcher addDispatch(new BlockModelGeneric<>(Blocks.ORE_DIAMOND_PERMAFROST, loadDataModel("minecraft:block/ore/diamond/permafrost"))); addDispatch(new BlockModelGeneric<>(Blocks.RUBYGLASS_COLUMN, loadDataModel("minecraft:block/rubyglass/column"))); - addDispatch(new BlockModelGeneric<>(Blocks.RUBYGLASS_NODE, loadDataModel("minecraft:block/rubyglass/node"))); + addDispatch(new BlockModelGeneric<>(Blocks.RUBYGLASS_NODE, loadDataModel("minecraft:block/rubyglass/node")).forceCullSelf(true)); + addDispatch(new BlockModelGeneric<>(Blocks.BRICK_RUBYGLASS, loadDataModel("minecraft:block/rubyglass/brick"))); addDispatch(new BlockModelGeneric<>(Blocks.BLOCK_RUBYGLASS, loadDataModel("minecraft:block/rubyglass/block")).forceCullSelf(true)); - addDispatch(new BlockModelCrystalBud<>(Blocks.RUBYGLASS_SPROUT, loadDataModel("minecraft:block/rubyglass/sprout")).render3D(false)); - addDispatch(new BlockModelConduit<>(Blocks.CONDUIT)); + addDispatch(new BlockModelConduit<>(Blocks.CONDUIT).forceCullSelf(true)); + addDispatch(new BlockModelGenericRubyglassCrystal<>(Blocks.RUBYGLASS_CRYSTAL, loadDataModel("minecraft:block/rubyglass/crystal/0")).forceCullSelf(true)); + addDispatch(new BlockModelGenericRubyglassGrowth<>(Blocks.RUBYGLASS_GROWTH)); addDispatch(new BlockModelGeneric<>(Blocks.ORE_NETHERCOAL_NETHERRACK, loadDataModel("minecraft:block/ore/nethercoal/netherrack"))); addDispatch(new BlockModelGeneric<>(Blocks.ORE_NETHERCOAL_BASALT, loadDataModel("minecraft:block/ore/nethercoal/basalt"))); @@ -425,7 +429,7 @@ public final class BlockModelDispatcher addDispatch(new BlockModelGenericSpikes<>(Blocks.SPIKES).render3D(false)); addDispatch(new BlockModelGenericVeryRotatable<>(Blocks.DISPENSER_COBBLE_STONE, loadDataModel("minecraft:block/dispenser"))); - addDispatch(new BlockModelGenericActivator<>(Blocks.ACTIVATOR_COBBLE_NETHERRACK)); + addDispatch(new BlockModelGenericActivator<>(Blocks.ACTIVATOR)); addDispatch(new BlockModelGenericTrapdoor<>(Blocks.TRAPDOOR_PLANKS_OAK, "minecraft:block/trapdoor/planks/oak")); addDispatch(new BlockModelGenericTrapdoor<>(Blocks.TRAPDOOR_IRON, "minecraft:block/trapdoor/iron")); @@ -457,6 +461,7 @@ public final class BlockModelDispatcher addDispatch(new BlockModelGeneric<>(Blocks.BRAZIER_INACTIVE, loadDataModel("minecraft:block/brazier"))); addDispatch(new BlockModelGenericBrazier<>(Blocks.BRAZIER_ACTIVE, loadDataModel("minecraft:block/brazier"))); addDispatch(new BlockModelFire<>(Blocks.FIRE_COLD).setAllTextures("minecraft:block/fire_cold")); + addDispatch(new BlockModelFire<>(Blocks.FIRE_SULFURIC).setAllTextures("minecraft:block/fire_sulfuric")); addDispatch(new BlockModelGeneric<>(Blocks.MOBSPAWNER, loadDataModel("minecraft:block/mobspawner"))); addDispatch(new BlockModelGeneric<>(Blocks.MOBSPAWNER_DEACTIVATED, loadDataModel("minecraft:block/mobspawner_deactivated"))); @@ -490,7 +495,7 @@ public final class BlockModelDispatcher addDispatch(new BlockModelGenericLayer<>(Blocks.LAYER_SNOW, "minecraft:block/layer/snow")); addDispatch(new BlockModelGenericLayer<>(Blocks.LAYER_LEAVES_OAK, "minecraft:block/layer/leaves_oak")); addDispatch(new BlockModelGenericLayer<>(Blocks.LAYER_SLATE, "minecraft:block/layer/slate")); - addDispatch(new BlockModelGenericLayer<>(Blocks.LAYER_ASH, "minecraft:block/layer/ash")); + addDispatch(new BlockModelGenericLayerAsh<>(Blocks.LAYER_ASH)); addDispatch(new BlockModelGeneric<>(Blocks.ICE, loadDataModel("minecraft:block/ice")).forceCullSelf(true)); addDispatch(new BlockModelGeneric<>(Blocks.PERMAICE, loadDataModel("minecraft:block/permaice"))); @@ -588,7 +593,39 @@ public final class BlockModelDispatcher addDispatch(new BlockModelGenericStairs<>(Blocks.STAIRS_COBBLE_GLOOMSTONE, loadDataModel("minecraft:block/stairs/cobbled_gloomstone"))); addDispatch(new BlockModelGenericStairs<>(Blocks.STAIRS_BRICK_GLOOMSTONE, loadDataModel("minecraft:block/stairs/brick_gloomstone"))); - addDispatch(new BlockModelGenericFlowstone<>(Blocks.FLOWSTONE, "minecraft:block/flowstone")); + addDispatch(new BlockModelGeneric<>(Blocks.BOULDER_MAGMATIC, loadDataModel("minecraft:block/boulder_magmatic")).render3D(false)); + addDispatch(new BlockModelGeneric<>(Blocks.BOULDER_SULFURIC, loadDataModel("minecraft:block/boulder_sulfuric")).render3D(false)); + addDispatch(new BlockModelGeneric<>(Blocks.SULFUR, loadDataModel("minecraft:block/sulfur"))); + addDispatch(new BlockModelGeneric<>(Blocks.SULFUR_HARDENED, loadDataModel("minecraft:block/sulfur_hardened"))); + addDispatch(new BlockModelGeneric<>(Blocks.EMBER, loadDataModel("minecraft:block/ember"))); + addDispatch(new BlockModelGeneric<>(Blocks.SLATE_CARVED, loadDataModel("minecraft:block/carved_slate"))); + addDispatch(new BlockModelGeneric<>(Blocks.BRIMSTONE, loadDataModel("minecraft:block/brimstone"))); + addDispatch(new BlockModelGeneric<>(Blocks.BRIMTHAW, loadDataModel("minecraft:block/brimthaw"))); + addDispatch(new BlockModelGeneric<>(Blocks.BRICK_BRIMSTONE, loadDataModel("minecraft:block/brick_brimstone"))); + + addDispatch(new BlockModelGenericAxis<>(Blocks.LOG_SCORCHED, loadDataModel("minecraft:block/log/scorched"))); + + addDispatch(new BlockModelGenericSlab<>(Blocks.SLAB_BRIMSTONE, loadDataModel("minecraft:block/slab/brimstone/lower"), loadDataModel("minecraft:block/slab/brimstone/upper"), loadDataModel("minecraft:block/slab/brimstone/full"))); + addDispatch(new BlockModelGenericStairs<>(Blocks.STAIRS_BRIMSTONE, loadDataModel("minecraft:block/stairs/brimstone"))); + + addDispatch(new BlockModelGenericSlab<>(Blocks.SLAB_BRICK_BRIMSTONE, loadDataModel("minecraft:block/slab/brick_brimstone/lower"), loadDataModel("minecraft:block/slab/brick_brimstone/upper"), loadDataModel("minecraft:block/slab/brick_brimstone/full"))); + addDispatch(new BlockModelGenericStairs<>(Blocks.STAIRS_BRICK_BRIMSTONE, loadDataModel("minecraft:block/stairs/brick_brimstone"))); + + addDispatch(new BlockModelGenericSlab<>(Blocks.SLAB_SLATE_POLISHED, loadDataModel("minecraft:block/slab/polished_slate/lower"), loadDataModel("minecraft:block/slab/polished_slate/upper"), loadDataModel("minecraft:block/slab/polished_slate/full"))); + + addDispatch(new BlockModelFluid<>(Blocks.FLUID_ACID_FLOWING, "minecraft:block/fluid/acid/still", "minecraft:block/fluid/acid/flowing").onRenderLayer(1)); + addDispatch(new BlockModelFluid<>(Blocks.FLUID_ACID_STILL, "minecraft:block/fluid/acid/still", "minecraft:block/fluid/acid/flowing").onRenderLayer(1)); + + addDispatch(new BlockModelEmpty<>(Blocks.STATUE_SLATE_LOWER).setAllTextures("minecraft:block/slate_side")); + addDispatch(new BlockModelEmpty<>(Blocks.STATUE_SLATE_UPPER).setAllTextures("minecraft:block/slate_side")); + addDispatch(new BlockModelEmpty<>(Blocks.STATUE_PERMAFROST_LOWER).setAllTextures("minecraft:block/permafrost")); + addDispatch(new BlockModelEmpty<>(Blocks.STATUE_PERMAFROST_UPPER).setAllTextures("minecraft:block/permafrost")); + addDispatch(new BlockModelEmpty<>(Blocks.STATUE_NETHERRACK_LOWER).setAllTextures("minecraft:block/netherrack")); + addDispatch(new BlockModelEmpty<>(Blocks.STATUE_NETHERRACK_UPPER).setAllTextures("minecraft:block/netherrack")); + addDispatch(new BlockModelEmpty<>(Blocks.STATUE_GLOOMSTONE_LOWER).setAllTextures("minecraft:block/gloomstone")); + addDispatch(new BlockModelEmpty<>(Blocks.STATUE_GLOOMSTONE_UPPER).setAllTextures("minecraft:block/gloomstone")); + + } } diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFluid.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFluid.java index 5e9a2d954..1dba8e7f7 100644 --- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFluid.java +++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFluid.java @@ -36,7 +36,7 @@ public class BlockModelFluid extends BlockModelStanda super(block); this.still = TextureRegistry.getTexture(still); this.flowing = TextureRegistry.getTexture(flowing); - this.bubbles = TextureRegistry.getTexture("minecraft:block/water_overlay_boiling"); + this.bubbles = TextureRegistry.getTexture("minecraft:block/fluid/water/overlay_boiling"); if (block.getLogic() instanceof BlockLogicFluidFlowing) { setAllTextures(this.flowing); @@ -94,10 +94,12 @@ public class BlockModelFluid extends BlockModelStanda } else { rotation = 0.0F; } - byte light = this.block.getLightIndex(worldSource, tilePos); - byte lightUp = this.block.getLightIndex(worldSource, tilePos.up(queryPos)); - tessellator.setLightmapCoord1i(LightIndexHelper.max(light, lightUp)); + byte lightNW = getFluidVertexLight(worldSource, (TilePos) tilePos, -1, -1, queryPos); + byte lightSW = getFluidVertexLight(worldSource, (TilePos) tilePos, -1, 1, queryPos); + byte lightSE = getFluidVertexLight(worldSource, (TilePos) tilePos, 1, 1, queryPos); + byte lightNE = getFluidVertexLight(worldSource, (TilePos) tilePos, 1, -1, queryPos); + if (tex == this.flowing) { float cos = Math.cos(-rotation + Math.PI_OVER_2_f); float sin = Math.sin(-rotation + Math.PI_OVER_2_f); @@ -112,27 +114,43 @@ public class BlockModelFluid extends BlockModelStanda this.b.cross(this.a, this.norm).normalize(); tessellator.setNormal(this.norm); + + tessellator.setLightmapCoord1i(lightNW); tessellator.addVertexWithUV(x, (float) y + h, z, tex.getSubIconU(((-0.25) * cos - (-0.25) * sin) + 0.5), tex.getSubIconV(((-0.25) * sin + (-0.25) * cos) + 0.5) ); + + tessellator.setLightmapCoord1i(lightSW); tessellator.addVertexWithUV(x, (float) y + hs, z + 1, tex.getSubIconU(((-0.25) * cos - (0.25) * sin) + 0.5), tex.getSubIconV(((-0.25) * sin + (0.25) * cos) + 0.5) ); + + tessellator.setLightmapCoord1i(lightSE); tessellator.addVertexWithUV(x + 1, (float) y + hes, z + 1, tex.getSubIconU(((0.25) * cos - (0.25) * sin) + 0.5), tex.getSubIconV(((0.25) * sin + (0.25) * cos) + 0.5) ); + + tessellator.setLightmapCoord1i(lightNE); tessellator.addVertexWithUV(x + 1, (float) y + he, z, tex.getSubIconU(((0.25) * cos - (-0.25) * sin) + 0.5), tex.getSubIconV(((0.25) * sin + (-0.25) * cos) + 0.5) ); } else { tessellator.setNormal(0, 1, 0); + + tessellator.setLightmapCoord1i(lightNW); tessellator.addVertexWithUV(x, (float) y + h, z, tex.getIconUMin(), tex.getIconVMax()); + + tessellator.setLightmapCoord1i(lightSW); tessellator.addVertexWithUV(x, (float) y + hs, z + 1, tex.getIconUMax(), tex.getIconVMax()); + + tessellator.setLightmapCoord1i(lightSE); tessellator.addVertexWithUV(x + 1, (float) y + hes, z + 1, tex.getIconUMax(), tex.getIconVMin()); + + tessellator.setLightmapCoord1i(lightNE); tessellator.addVertexWithUV(x + 1, (float) y + he, z, tex.getIconUMin(), tex.getIconVMin()); if (worldSource.getWorldType().hasTag(WorldTypeTags.NETHER) && this.block.getLogic().fluid instanceof FluidWater) { @@ -288,4 +306,15 @@ public class BlockModelFluid extends BlockModelStanda return super.shouldSideBeRendered(source, bounds, tilePos, side); } } + + private byte getFluidVertexLight(WorldSource world, TilePos center, int dx, int dz, TilePos queryPos) { + byte l1 = this.block.getLightIndex(world, center.up(queryPos)); + byte l2 = this.block.getLightIndex(world, center.add(dx, 1, 0, queryPos)); + byte l3 = this.block.getLightIndex(world, center.add(0, 1, dz, queryPos)); + byte l4 = this.block.getLightIndex(world, center.add(dx, 1, dz, queryPos)); + + byte max1 = LightIndexHelper.max(l1, l2); + byte max2 = LightIndexHelper.max(l3, l4); + return LightIndexHelper.max(max1, max2); + } } diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGeneric.java b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGeneric.java index 16fac720f..a5be6ed64 100644 --- a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGeneric.java +++ b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGeneric.java @@ -6,6 +6,7 @@ import net.minecraft.client.render.tessellator.TessellatorGeneral; import net.minecraft.client.render.texture.stitcher.IconCoordinate; import net.minecraft.core.block.Block; import net.minecraft.core.block.BlockLogic; +import net.minecraft.core.block.BlockLogicPumpkin; import net.minecraft.core.util.helper.Direction; import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.WorldSource; @@ -48,7 +49,7 @@ public class BlockModelGeneric extends BlockModel { } @Override - public final boolean render(final @NotNull TessellatorGeneral tessellator, @NotNull final WorldSource worldSource, @NotNull TilePosc tilePos) { + public boolean render(final @NotNull TessellatorGeneral tessellator, @NotNull final WorldSource worldSource, @NotNull TilePosc tilePos) { return renderAttached(tessellator, worldSource, tilePos, true, null); } diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericFlowstone.java b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericFlowstone.java deleted file mode 100644 index b9b41076c..000000000 --- a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericFlowstone.java +++ /dev/null @@ -1,36 +0,0 @@ -package net.minecraft.client.render.block.model.generic; - -import net.minecraft.client.render.block.model.BlockModelDispatcher; -import net.minecraft.client.render.tessellator.TessellatorGeneral; -import net.minecraft.client.render.texture.stitcher.IconCoordinate; -import net.minecraft.core.block.Block; -import net.minecraft.core.block.BlockLogicFlowstone; -import net.minecraft.core.world.WorldSource; -import net.minecraft.core.world.pos.TilePosc; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.useless.dragonfly.models.block.StaticBlockModel; - -public class BlockModelGenericFlowstone extends BlockModelGeneric { - public final @NotNull StaticBlockModel[] sizes; - - public BlockModelGenericFlowstone(final @NotNull Block block, final @NotNull String baseKey) { - super(block, BlockModelDispatcher.loadDataModel(baseKey + "/16")); - - this.sizes = new StaticBlockModel[] { - BlockModelDispatcher.loadDataModel(baseKey + "/16").asModel(), - BlockModelDispatcher.loadDataModel(baseKey + "/12").asModel(), - BlockModelDispatcher.loadDataModel(baseKey + "/8").asModel(), - BlockModelDispatcher.loadDataModel(baseKey + "/4").asModel(), - }; - } - - @Override - public @NotNull StaticBlockModel getModelFromData(final int data) { - if (data < this.sizes.length) { - return this.sizes[data]; - } else { - return this.sizes[0]; - } - } -} diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericLayerAsh.java b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericLayerAsh.java new file mode 100644 index 000000000..11258d9a0 --- /dev/null +++ b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericLayerAsh.java @@ -0,0 +1,28 @@ +package net.minecraft.client.render.block.model.generic; + +import net.minecraft.client.render.tessellator.TessellatorGeneral; +import net.minecraft.core.block.Block; +import net.minecraft.core.block.BlockLogic; +import net.minecraft.core.block.Blocks; +import net.minecraft.core.world.WorldSource; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; + +public class BlockModelGenericLayerAsh extends BlockModelGenericLayer { + + public final BlockModelGenericLayer emberModel; + + public BlockModelGenericLayerAsh(@NotNull Block block) { + super(block, "minecraft:block/ash"); + this.emberModel = new BlockModelGenericLayer<>(block, "minecraft:block/ash_ember"); + } + + @Override + public boolean render(@NotNull TessellatorGeneral tessellator, @NotNull WorldSource worldSource, @NotNull TilePosc tilePos) { + if (worldSource.getBlockId(tilePos.x(), tilePos.y() - 1, tilePos.z()) == Blocks.EMBER.id()) { + return this.emberModel.render(tessellator, worldSource, tilePos); + } + + return super.render(tessellator, worldSource, tilePos); + } +} \ No newline at end of file diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericRocks.java b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericRocks.java new file mode 100644 index 000000000..832e3b8f5 --- /dev/null +++ b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericRocks.java @@ -0,0 +1,25 @@ +package net.minecraft.client.render.block.model.generic; + +import net.minecraft.client.render.block.model.BlockModelDispatcher; +import net.minecraft.core.block.Block; +import net.minecraft.core.block.BlockLogic; +import org.jetbrains.annotations.NotNull; +import org.useless.dragonfly.models.block.StaticBlockModel; + +public class BlockModelGenericRocks extends BlockModelGeneric { + public final @NotNull StaticBlockModel[] models = new StaticBlockModel[3]; + + public BlockModelGenericRocks(@NotNull Block block) { + super(block, BlockModelDispatcher.loadDataModel("minecraft:block/rocks/0")); + + for(int i = 0; i < 3; ++i) { + this.models[i] = BlockModelDispatcher.loadDataModel("minecraft:block/rocks/" + i).asModel(); + } + + } + + @Override + public @NotNull StaticBlockModel getModelFromData(int data) { + return this.models[data % 3]; + } +} diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericRubyglassBud.java b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericRubyglassBud.java deleted file mode 100644 index e8ab93388..000000000 --- a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericRubyglassBud.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.minecraft.client.render.block.model.generic; - -import net.minecraft.client.render.block.model.BlockModelDispatcher; -import net.minecraft.core.block.Block; -import net.minecraft.core.block.BlockLogic; -import net.minecraft.core.block.BlockLogicRubyglassCrop; -import org.jetbrains.annotations.NotNull; -import org.useless.dragonfly.models.block.StaticBlockModel; - -public class BlockModelGenericRubyglassBud extends BlockModelGeneric { - public final StaticBlockModel[] models = new StaticBlockModel[BlockLogicRubyglassCrop.MAX_GROWTH_STATE + 1]; - public BlockModelGenericRubyglassBud(@NotNull Block block) { - super(block, BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass_bud/stage0")); - for (int i = 0; i < this.models.length; i++) { - this.models[i] = BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass_bud/stage" + i).asModel(); - } - } - - @Override - public @NotNull StaticBlockModel getModelFromData(int data) { - return this.models[data % this.models.length]; - } -} diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericRubyglassCrystal.java b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericRubyglassCrystal.java new file mode 100644 index 000000000..0a5e7a394 --- /dev/null +++ b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericRubyglassCrystal.java @@ -0,0 +1,33 @@ +package net.minecraft.client.render.block.model.generic; + +import net.minecraft.client.render.block.model.BlockModelDispatcher; +import net.minecraft.core.block.Block; +import net.minecraft.core.block.BlockLogic; +import org.jetbrains.annotations.NotNull; +import org.useless.dragonfly.data.block.BlockModelData; +import org.useless.dragonfly.models.block.StaticBlockModel; + +public class BlockModelGenericRubyglassCrystal extends BlockModelGeneric { + public final StaticBlockModel[] models = new StaticBlockModel[4]; + + public BlockModelGenericRubyglassCrystal(@NotNull Block block, @NotNull StaticBlockModel staticModel) { + super(block, staticModel); + loadModels(); + } + + public BlockModelGenericRubyglassCrystal(@NotNull Block block, @NotNull BlockModelData staticModel) { + super(block, staticModel); + loadModels(); + } + + private void loadModels() { + for (int i = 0; i < 4; i++) { + this.models[i] = BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass/crystal/" + i).asModel(); + } + } + + @Override + public @NotNull StaticBlockModel getModelFromData(int data) { + return this.models[data & 3]; + } +} diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericRubyglassGrowth.java b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericRubyglassGrowth.java new file mode 100644 index 000000000..f0488a930 --- /dev/null +++ b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericRubyglassGrowth.java @@ -0,0 +1,85 @@ +package net.minecraft.client.render.block.model.generic; + +import net.minecraft.client.render.block.model.BlockModel; +import net.minecraft.client.render.block.model.BlockModelDispatcher; +import net.minecraft.client.render.tessellator.TessellatorGeneral; +import net.minecraft.client.render.texture.stitcher.IconCoordinate; +import net.minecraft.core.block.Block; +import net.minecraft.core.block.BlockLogic; +import net.minecraft.core.util.helper.Side; +import net.minecraft.core.world.WorldSource; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.useless.dragonfly.DisplayPos; + +import static net.minecraft.core.block.BlockLogicGrowthRubyglass.*; + +public class BlockModelGenericRubyglassGrowth extends BlockModel { + + public final BlockModelGenericFullyRotatable budModel; + public final BlockModelGenericFullyRotatable bottomModel; + public final BlockModelGenericFullyRotatable topModel; + + public BlockModelGenericRubyglassGrowth(@NotNull Block block) { + super(block); + this.budModel = new BlockModelGenericFullyRotatable<>(block, BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass/growth/bud")); + this.bottomModel = new BlockModelGenericFullyRotatable<>(block, BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass/growth/bottom")); + this.topModel = new BlockModelGenericFullyRotatable<>(block, BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass/growth/top")); + } + + @Override + public boolean render(@NotNull TessellatorGeneral tessellator, @NotNull WorldSource worldSource, @NotNull TilePosc tilePos) { + int data = worldSource.getBlockData(tilePos); + + int shape = data & SHAPE_MASK; + + if (shape == STATE_TOP) { + return this.topModel.render(tessellator, worldSource, tilePos); + } else if (shape == STATE_BOTTOM) { + return this.bottomModel.render(tessellator, worldSource, tilePos); + } else { + return this.budModel.render(tessellator, worldSource, tilePos); + } + } + + @Override + public boolean renderNoCulling(@NotNull TessellatorGeneral tessellator, @NotNull WorldSource worldSource, @NotNull TilePosc tilePos) { + return false; + } + + @Override + public boolean renderWithOverrideTexture(@NotNull TessellatorGeneral tessellator, @NotNull WorldSource worldSource, @NotNull TilePosc tilePos, IconCoordinate overrideTexture) { + return false; + } + + @Override + public void renderStandalone(@NotNull TessellatorGeneral tessellator, int metadata, byte lightIndex) { + this.budModel.renderStandalone(tessellator, metadata, lightIndex); + } + + @Override + public boolean shouldItemRender3d() { + return false; + } + + @Override + public @NotNull DisplayPos getItemDisplayPos(@NotNull String id) { + return this.budModel.getItemDisplayPos(id); + } + + @Override + public @Nullable IconCoordinate getParticleTexture(@NotNull Side side, int meta) { + return this.budModel.getParticleTexture(side, meta); + } + + @Override + public @Nullable IconCoordinate getOverlayTexture(int meta) { + return this.budModel.getOverlayTexture(meta); + } + + @Override + public int particleColorIndex(@NotNull WorldSource worldSource, @NotNull TilePosc tilePos, @NotNull Side side, int meta) { + return this.budModel.particleColorIndex(worldSource, tilePos, side, meta); + } +} \ No newline at end of file diff --git a/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureFire.java b/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureFire.java index 034c2746f..92bd27c87 100644 --- a/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureFire.java +++ b/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureFire.java @@ -10,11 +10,13 @@ public class DynamicTextureFire extends DynamicTexture{ private int height; private float scaleFactor; + private final boolean sulfuric; private final boolean cold; - public DynamicTextureFire(@NotNull IconCoordinate targetTexture, boolean cold) { + public DynamicTextureFire(@NotNull IconCoordinate targetTexture, boolean cold, boolean sulfuric) { super(targetTexture); + this.sulfuric = sulfuric; this.cold = cold; } @@ -73,6 +75,10 @@ public class DynamicTextureFire extends DynamicTexture{ r = (int)(l * 155.0F + 100.0F); g = (int)(l * 155.0F + 100.0F); b = (int)(l * 155.0F + 100.0F); + } else if (this.sulfuric) { + r = (int)(l * 200.0F + 55.0F); + g = (int)(l * 155.0F + 100.0F); + b = (int)(l * l * l * l * l * l * l * l * l * l * 255.0F); } else { r = (int)(l * 155.0F + 100.0F); g = (int)(l * l * 255.0F); diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRenderer.java b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRenderer.java index 865195a21..28ea1fa62 100644 --- a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRenderer.java +++ b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRenderer.java @@ -15,6 +15,7 @@ import org.jetbrains.annotations.NotNull; import org.joml.Math; import org.joml.primitives.AABBdc; +import net.minecraft.client.render.ClientFireOverlayHelper; import net.minecraft.client.render.EntityRendererDispatcher; import net.minecraft.client.render.ImageParser; import net.minecraft.client.render.TextureManager; @@ -103,7 +104,8 @@ public abstract class EntityRenderer { private void renderFire(final @NotNull TessellatorGeneral tessellator, final @NotNull T entity, final double x, final double y, final double z, final float partialTick) { GLRenderer.globalSetLightEnabled(false); - final IconCoordinate texture = TextureRegistry.getTexture("minecraft:block/fire"); + final String texturePath = ClientFireOverlayHelper.getFireOverlayTexture(entity); + final IconCoordinate texture = TextureRegistry.getTexture(texturePath); texture.parentAtlas.bind(); GLRenderer.pushFrame(); GLRenderer.modelM4f().translate((float) x, (float) y, (float) z); @@ -118,6 +120,7 @@ public abstract class EntityRenderer { GLRenderer.setColor4f(1.0F, 1.0F, 1.0F, 1.0F); byte lightIndex = entity.getLightIndex(partialTick); lightIndex = LightIndexHelper.setBlockLight(lightIndex, 15); + lightIndex = LightIndexHelper.setSkyLight(lightIndex, 15); GLRenderer.setLightmapCoord1i(lightIndex); float f14 = 0.0F; int l = 0; diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java index a7c79b435..20241c95e 100644 --- a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java +++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java @@ -269,6 +269,7 @@ public class ItemModelDispatcher extends Dispatcher { .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_ROD_THIRD_PERSON_RIGHT_HAND) .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_ROD_THIRD_PERSON_LEFT_HAND)); addDispatch(new ItemModelStandard(Items.TOOL_CLOCK, "minecraft")); + addDispatch(new ItemModelBlock((ItemBlock) Blocks.GLOWSTONE.asItem()).setFullBright()); addDispatch(new ItemModelStandard(Items.DUST_GLOWSTONE, "minecraft").setFullBright()); addDispatch(new ItemModelStandard(Items.FOOD_FISH_RAW, "minecraft")); addDispatch(new ItemModelStandard(Items.FOOD_FISH_COOKED, "minecraft")); @@ -358,6 +359,11 @@ public class ItemModelDispatcher extends Dispatcher { addDispatch(new ItemModelStandard(Items.LANTERN_FIREFLY_ORANGE, "minecraft").setFullBright()); addDispatch(new ItemModelStandard(Items.LANTERN_FIREFLY_RED, "minecraft").setFullBright()); + addDispatch(new ItemModelBlock((ItemBlock) Blocks.LAMP_ACTIVE.asItem()).setFullBright()); + addDispatch(new ItemModelBlock((ItemBlock) Blocks.LAMP_IDLE.asItem()).setFullBright()); + addDispatch(new ItemModelBlock((ItemBlock) Blocks.LAMP_INVERTED_ACTIVE.asItem()).setFullBright()); + addDispatch(new ItemModelBlock((ItemBlock) Blocks.LAMP_INVERTED_IDLE.asItem()).setFullBright()); + addDispatch(new ItemModelStandard(Items.BASKET, "minecraft")); addDispatch(new ItemModelStandard(Items.FLAG, "minecraft") .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND) @@ -427,8 +433,15 @@ public class ItemModelDispatcher extends Dispatcher { addDispatch(new ItemModelStandard(Items.FOOD_VENISON_RAW, "minecraft")); addDispatch(new ItemModelStandard(Items.FOOD_VENISON_COOKED, "minecraft")); -// addDispatch(new ItemModelStandard(Items.RUBYGLASS_DUST, "minecraft")); - addDispatch(new ItemModelStandard(Items.RUBYGLASS_CRYSTAL, "minecraft")); + + addDispatch(new ItemModelStandard(Items.RUBYGLASS, "minecraft").setFullBright()); + addDispatch(new ItemModelBlock((ItemBlock) Blocks.RUBYGLASS_COLUMN.asItem()).setFullBright()); + addDispatch(new ItemModelBlock((ItemBlock) Blocks.BLOCK_RUBYGLASS.asItem()).setFullBright()); + addDispatch(new ItemModelBlock((ItemBlock) Blocks.RUBYGLASS_GROWTH.asItem()).setFullBright()); + addDispatch(new ItemModelBlock((ItemBlock) Blocks.RUBYGLASS_CRYSTAL.asItem()).setFullBright()); + + addDispatch(new ItemModelBlock((ItemBlock) Blocks.BOULDER_MAGMATIC.asItem())); + addDispatch(new ItemModelBlock((ItemBlock) Blocks.BOULDER_SULFURIC.asItem())); addDispatch(new ItemModelStandard(Items.DOUGH, "minecraft")); @@ -439,6 +452,15 @@ public class ItemModelDispatcher extends Dispatcher { addDispatch(new ItemModelStandard(Items.ARMOR_WOLF_GOLD, "minecraft")); addDispatch(new ItemModelStandard(Items.ARMOR_WOLF_STEEL, "minecraft")); + addDispatch(new ItemModelStandard(Items.AMMO_ARROW_FLAMING, "minecraft")); + + addDispatch(new ItemModelStandard(Items.SULFUR, "minecraft")); + + addDispatch(new ItemModelStandard(Items.STATUE_GLOOMSTONE, "minecraft")); + addDispatch(new ItemModelStandard(Items.STATUE_NETHERRACK, "minecraft")); + addDispatch(new ItemModelStandard(Items.STATUE_PERMAFROST, "minecraft")); + addDispatch(new ItemModelStandard(Items.STATUE_SLATE, "minecraft")); + for (int i = 0; i < Blocks.blocksList.length; i++) { if (Blocks.blocksList[i] == null) continue; Item item = Blocks.blocksList[i].asItem(); diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelStandard.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelStandard.java index bc60db4a4..7789cc5ab 100644 --- a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelStandard.java +++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelStandard.java @@ -1,5 +1,6 @@ package net.minecraft.client.render.item.model; +import net.minecraft.client.Minecraft; import net.minecraft.client.render.TextureManager; import net.minecraft.client.render.font.FontRenderer; import net.minecraft.client.render.renderer.BlendFactor; @@ -216,8 +217,20 @@ public class ItemModelStandard extends ItemModel{ GLRenderer.pushFrame(); GLRenderer.disableState(State.DEPTH_TEST); GLRenderer.setShader(Shaders.COLOR); - final int colorFG = Color.HSBtoRGB(progress / 255F / 3F, 1f, 1f); - final int colorBG = (0xFF - progress) / 4 << 16 | 0x3f00; + + final Minecraft mc = Minecraft.getMinecraft(); + final boolean isAcidic = mc.thePlayer != null && mc.thePlayer.shouldShowAcidVisualEffects() && mc.thePlayer.getGamemode().hasToolDurability(); + final int colorFG; + final int colorBG; + if (isAcidic) { + final float t = progress / 255F; + colorFG = Color.HSBtoRGB(0.11F + t * 0.06F, 1f, 1f); + colorBG = Color.HSBtoRGB(0.11F, 1f, 0.35f); + } else { + colorFG = Color.HSBtoRGB(progress / 255F / 3F, 1f, 1f); + colorBG = (0xFF - progress) / 4 << 16 | 0x3f00; + } + tessellator.startDrawingQuads(); renderColoredQuad(tessellator, x + 2, y + 13, 13, 2, 0, a); renderColoredQuad(tessellator, x + 2, y + 13, 12, 1, colorBG, a); diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/Particle.java b/game/client/src/main/java/net/minecraft/client/render/particle/Particle.java index 66f7294e6..4410a5f79 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/Particle.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/Particle.java @@ -1,28 +1,20 @@ package net.minecraft.client.render.particle; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.client.render.ParticleEngine; import net.minecraft.client.render.tessellator.TessellatorParticle; import net.minecraft.client.render.texture.stitcher.IconCoordinate; import net.minecraft.core.Global; import net.minecraft.core.block.Block; -import net.minecraft.core.block.BlockLogicMesh; -import net.minecraft.core.util.helper.Direction; import net.minecraft.core.util.helper.LightIndexHelper; import net.minecraft.core.util.helper.MathHelper; -import net.minecraft.core.util.phys.HitResult; import net.minecraft.core.world.World; import net.minecraft.core.world.pos.TilePos; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Random; -import org.joml.Vector2d; -import org.joml.Vector3d; -import org.joml.primitives.AABBd; import org.joml.primitives.AABBdc; -import org.joml.primitives.Rayd; -import java.util.List; +import java.util.concurrent.ThreadLocalRandom; /** * Displays a small, temporary texture in the world, used as a visual effect. Managed by {@link ParticleEngine}. @@ -34,7 +26,7 @@ public class Particle { protected float vo; protected int age; protected int lifetime; - protected float size; + public float size; protected float gravity; protected float rCol; protected float gCol; @@ -51,11 +43,17 @@ public class Particle { public double yd = 0; public double zd = 0; + protected int bX = Integer.MAX_VALUE; + protected int bY = Integer.MAX_VALUE; + protected int bZ = Integer.MAX_VALUE; + public boolean noPhysics = false; public boolean onGround = false; public boolean removed = false; - public final @NotNull World world; + private final TilePos qPos = new TilePos(); + + public @NotNull World world; /** * Creates a new Particle. @@ -74,10 +72,33 @@ public class Particle { this.y = y; this.z = z; this.rCol = this.gCol = this.bCol = 1.0F; - this.xd = xa + (float) (Math.random() * 2D - 1.0D) * 0.4F; - this.yd = ya + (float) (Math.random() * 2D - 1.0D) * 0.4F; - this.zd = za + (float) (Math.random() * 2D - 1.0D) * 0.4F; - float speed = (float) (Math.random() + Math.random() + 1.0D) * 0.15F; + ThreadLocalRandom tlr = ThreadLocalRandom.current(); + this.xd = xa + (float) (tlr.nextDouble() * 2D - 1.0D) * 0.4F; + this.yd = ya + (float) (tlr.nextDouble() * 2D - 1.0D) * 0.4F; + this.zd = za + (float) (tlr.nextDouble() * 2D - 1.0D) * 0.4F; + float speed = (float) (tlr.nextDouble() + tlr.nextDouble() + 1.0D) * 0.15F; + float dd = MathHelper.sqrt(this.xd * this.xd + this.yd * this.yd + this.zd * this.zd); + this.xd = (this.xd / dd) * speed * 0.4D; + this.yd = (this.yd / dd) * speed * 0.4D + 0.1D; + this.zd = (this.zd / dd) * speed * 0.4D; + this.uo = random.nextFloat() * 3F; + this.vo = random.nextFloat() * 3F; + this.size = (random.nextFloat() * 0.5F + 0.5F) * 2.0F; + this.lifetime = (int) (4F / (random.nextFloat() * 0.9F + 0.1F)); + this.age = 0; + } + + public Particle resetBase(@NotNull World world, double x, double y, double z, double xa, double ya, double za) { + this.world = world; + this.x = x; + this.y = y; + this.z = z; + this.rCol = this.gCol = this.bCol = 1.0F; + ThreadLocalRandom tlr = ThreadLocalRandom.current(); + this.xd = xa + (float) (tlr.nextDouble() * 2D - 1.0D) * 0.4F; + this.yd = ya + (float) (tlr.nextDouble() * 2D - 1.0D) * 0.4F; + this.zd = za + (float) (tlr.nextDouble() * 2D - 1.0D) * 0.4F; + float speed = (float) (tlr.nextDouble() + tlr.nextDouble() + 1.0D) * 0.15F; float dd = MathHelper.sqrt(this.xd * this.xd + this.yd * this.yd + this.zd * this.zd); this.xd = (this.xd / dd) * speed * 0.4D; this.yd = (this.yd / dd) * speed * 0.4D + 0.1D; @@ -87,6 +108,11 @@ public class Particle { this.size = (random.nextFloat() * 0.5F + 0.5F) * 2.0F; this.lifetime = (int) (4F / (random.nextFloat() * 0.9F + 0.1F)); this.age = 0; + + this.removed = false; + this.noPhysics = false; + this.onGround = false; + return this; } public void init() { @@ -119,169 +145,146 @@ public class Particle { } public void tick() { - this.cachedLightmapCoord = calcLightIndex(1f); + int cX = MathHelper.floor(this.x); + int cY = MathHelper.floor(this.y); + int cZ = MathHelper.floor(this.z); + + if (cX != this.bX || cY != this.bY || cZ != this.bZ) { + this.bX = cX; + this.bY = cY; + this.bZ = cZ; + this.cachedLightmapCoord = calcLightIndex(1f); + } + this.xo = this.x; this.yo = this.y; this.zo = this.z; + if (this.age++ >= this.lifetime) { remove(); } + this.yd -= 0.04D * this.gravity; + move(this.xd, this.yd, this.zd); + this.xd *= 0.98D; this.yd *= 0.98D; this.zd *= 0.98D; - if (this.onGround) { - this.xd *= 0.7D; - this.zd *= 0.7D; - } } - public void move(double xd, double yd, double zd) { + public void move(double dx, double dy, double dz) { if (this.noPhysics) { - this.onGround = false; - this.x += xd; - this.y += yd; - this.z += zd; + this.x += dx; + this.y += dy; + this.z += dz; return; } - HitResult hitResult = raycastBlocks(this.x, this.y, this.z, xd, yd, zd); - if (hitResult instanceof HitResult.Tile hitTile) { - switch (hitTile.side) { - case EAST: - case WEST: { - this.x = hitTile.location.x() + hitTile.side.offsetX() * 0.1d * this.size; - this.y += yd; - this.z += zd; - this.xd = 0; - break; - } - case TOP: + + double buffer = 0.001D; + + // Y-Axis + if (dy != 0) { + this.qPos.set(MathHelper.floor(this.x), MathHelper.floor(this.y + dy), MathHelper.floor(this.z)); + AABBdc bb = getCollisionBox(this.qPos); + + boolean collided = false; + if (bb != null && this.x >= bb.minX() && this.x <= bb.maxX() && this.z >= bb.minZ() && this.z <= bb.maxZ()) { + if (dy < 0 && this.y >= bb.maxY() && this.y + dy <= bb.maxY()) { this.onGround = true; - case BOTTOM: { - this.x += xd; - this.y = hitTile.location.y() + hitTile.side.offsetY() * 0.1d * this.size; - this.z += zd; + this.y = bb.maxY() + buffer; + this.xd = 0; + this.zd = 0; this.yd = 0; - break; + collided = true; } - case SOUTH: - case NORTH: { - this.x += xd; - this.y += yd; - this.z = hitTile.location.z() + hitTile.side.offsetZ() * 0.1d * this.size; - this.zd = 0; - break; + else if (dy > 0 && this.y <= bb.minY() && this.y + dy >= bb.minY()) { + this.y = bb.minY() - buffer; + this.yd = 0; + collided = true; } } - } else { - this.x += xd; - this.y += yd; - this.z += zd; + + if (!collided) { + this.y += dy; + if (dy < 0) this.onGround = false; + } } - } - private final Vector2d __r = new Vector2d(); - private final Rayd __ray = new Rayd(); - private final List aabbs = new ObjectArrayList<>(); - private final AABBd refAABB = new AABBd(); - - public @Nullable HitResult raycastBlocks(final double ox, final double oy, final double oz, final double xd, final double yd, final double zd) { - this.__ray.oX = ox; - this.__ray.oY = oy; - this.__ray.oZ = oz; - double length = org.joml.Math.sqrt(xd * xd + yd * yd + zd * zd); - if (length <= 0) return null; - this.__ray.dX = (xd / length); - this.__ray.dY = (yd / length); - this.__ray.dZ = (zd / length); - Rayd ray = this.__ray; - - final double maxT = length; // how many 1 block steps - final double dDistX = ray.dX == 0 ? Double.MAX_VALUE : org.joml.Math.abs(1 / ray.dX); - final double dDistY = ray.dY == 0 ? Double.MAX_VALUE : org.joml.Math.abs(1 / ray.dY); - final double dDistZ = ray.dZ == 0 ? Double.MAX_VALUE : org.joml.Math.abs(1 / ray.dZ); - - final int signX = (int) org.joml.Math.signum(ray.dX); - final int signY = (int) org.joml.Math.signum(ray.dY); - final int signZ = (int) org.joml.Math.signum(ray.dZ); - - TilePos qPos = new TilePos(); - TilePos tilePos = new TilePos(ray.oX, ray.oY, ray.oZ); - - double sideDistX = -(ray.oX - (tilePos.x + 0.5)) * (1 / ray.dX) + 0.5 * dDistX; - double sideDistY = -(ray.oY - (tilePos.y + 0.5)) * (1 / ray.dY) + 0.5 * dDistY; - double sideDistZ = -(ray.oZ - (tilePos.z + 0.5)) * (1 / ray.dZ) + 0.5 * dDistZ; - - double dx = 0.0; - double dy = 0.0; - double dz = 0.0; - - Direction direction = Direction.NONE; - while (dx * dx + dy * dy + dz * dz < length * length + 4) { - this.aabbs.clear(); - for (int _x = -1; _x <= 1; _x++) { - for (int _y = -1; _y <= 1; _y++) { - for (int _z = -1; _z <= 1; _z++) { - Block block = this.world.getBlockType(tilePos.add(_x, _y, _z, qPos)); - if (collidesWithBlock(block, this.world.getBlockData(qPos))) { - block.getCollisionAABBs(this.world, qPos, this.refAABB.setMin(qPos.x, qPos.y, qPos.z).setMax(qPos.x + 1, qPos.y + 1, qPos.z + 1), this.aabbs); - } - } + // X-Axis + if (dx != 0) { + this.qPos.set(MathHelper.floor(this.x + dx), MathHelper.floor(this.y), MathHelper.floor(this.z)); + AABBdc bb = getCollisionBox(this.qPos); + + boolean collided = false; + if (bb != null && this.y >= bb.minY() && this.y <= bb.maxY() && this.z >= bb.minZ() && this.z <= bb.maxZ()) { + if (dx < 0 && this.x >= bb.maxX() && this.x + dx <= bb.maxX()) { + this.x = bb.maxX() + buffer; + this.xd *= -0.3D; + collided = true; + } else if (dx > 0 && this.x <= bb.minX() && this.x + dx >= bb.minX()) { + this.x = bb.minX() - buffer; + this.xd *= -0.3D; + collided = true; } } - if (!this.aabbs.isEmpty()) { - double tMin = Double.MAX_VALUE; - for (int i = 0, aabbsSize = this.aabbs.size(); i < aabbsSize; i++) { - if (this.aabbs.get(i).intersectsRay(ray, this.__r)) { - tMin = org.joml.Math.min(this.__r.x, tMin); - } - } - if (tMin < maxT) { - return new HitResult.Tile( - tilePos, - direction.side(), - new Vector3d(ray.oX + tMin * ray.dX, ray.oY + tMin * ray.dY, ray.oZ + tMin * ray.dZ)); + + if (!collided) { + this.x += dx; + } + } + + // Z-Axis + if (dz != 0) { + this.qPos.set(MathHelper.floor(this.x), MathHelper.floor(this.y), MathHelper.floor(this.z + dz)); + AABBdc bb = getCollisionBox(this.qPos); + + boolean collided = false; + if (bb != null && this.x >= bb.minX() && this.x <= bb.maxX() && this.y >= bb.minY() && this.y <= bb.maxY()) { + if (dz < 0 && this.z >= bb.maxZ() && this.z + dz <= bb.maxZ()) { + this.z = bb.maxZ() + buffer; + this.zd *= -0.3D; + collided = true; + } else if (dz > 0 && this.z <= bb.minZ() && this.z + dz >= bb.minZ()) { + this.z = bb.minZ() - buffer; + this.zd *= -0.3D; + collided = true; } } - if (Double.isFinite(sideDistX) && sideDistX < sideDistY && sideDistX < sideDistZ) { - tilePos.x += signX; - dx = tilePos.x - ray.oX; - sideDistX += dDistX; - direction = signX > 0 ? Direction.WEST : Direction.EAST; - } else if (Double.isFinite(sideDistY) && sideDistY < sideDistZ) { - tilePos.y += signY; - dy = tilePos.y - ray.oY; - sideDistY += dDistY; - direction = signY > 0 ? Direction.DOWN : Direction.UP; - } else if (Double.isFinite(sideDistZ)) { - tilePos.z += signZ; - dz = tilePos.z - ray.oZ; - sideDistZ += dDistZ; - direction = signZ > 0 ? Direction.NORTH : Direction.SOUTH; - } else { - return null; + if (!collided) { + this.z += dz; } } - return null; } - public boolean collidesWithBlock(@NotNull Block block, int data) { - return !Block.hasLogicClass(block, BlockLogicMesh.class); + protected @Nullable AABBdc getCollisionBox(TilePos pos) { + if (this.world.isAirBlock(pos)) return null; + + Block blk = this.world.getBlockType(pos); + if (!blk.getMaterial().blocksMotion()) { + return null; + } + + AABBdc bb = blk.getLogic().getCollisionAABB(this.world, pos); + if (bb != null && bb.isValid()) { + return bb; + } + + return null; } /** * Renders the particle in the world. * - * @param t The tessellator to use to draw the particle. + * @param tessellatorParticle The tessellator to use to draw the particle. * @param partialTick The time since the last tick. */ - public void render(@NotNull TessellatorParticle t, float partialTick) { + public void render(@NotNull TessellatorParticle tessellatorParticle, float partialTick) { if (this.tex == null) return; - t.setLightmapCoord1i(getLightIndex(partialTick)); - t.setColorOpaque3f(this.rCol, this.gCol, this.bCol); - t.addParticle( + tessellatorParticle.setLightmapCoord1i(getLightIndex(partialTick)); + tessellatorParticle.setColorOpaque3f(this.rCol, this.gCol, this.bCol); + tessellatorParticle.addParticle( MathHelper.lerp(this.xo, this.x, partialTick), MathHelper.lerp(this.yo, this.y, partialTick), MathHelper.lerp(this.zo, this.z, partialTick), @@ -298,16 +301,19 @@ public class Particle { return ParticleEngine.WORLD_TEXTURE; } - public float calcBrightness(float partialTick) { + public float calcBrightness(float pt) { if (Global.accessor.isFullbrightEnabled()) { return 1.0f; } - TilePos pos = new TilePos( - MathHelper.lerp(this.xo, this.x, partialTick), - MathHelper.lerp(this.yo, this.y, partialTick), - MathHelper.lerp(this.zo, this.z, partialTick)); - if (this.world.areBlocksLoaded(pos, pos)) { - return this.world.getLightBrightness(pos); + + this.qPos.set( + MathHelper.floor(MathHelper.lerp(this.xo, this.x, pt)), + MathHelper.floor(MathHelper.lerp(this.yo, this.y, pt)), + MathHelper.floor(MathHelper.lerp(this.zo, this.z, pt)) + ); + + if (this.world.areBlocksLoaded(this.qPos, this.qPos)) { + return this.world.getLightBrightness(this.qPos); } return 0; } @@ -316,27 +322,24 @@ public class Particle { return calcBrightness(partialTick); } - public byte calcLightIndex(float partialTick) { + public byte calcLightIndex(float pt) { if (Global.accessor.isFullbrightEnabled()) return LightIndexHelper.lightIndex2i(15, 15); - TilePos blockPos = new TilePos( - MathHelper.lerp(this.xo, this.x, partialTick), - MathHelper.lerp(this.yo, this.y, partialTick), - MathHelper.lerp(this.zo, this.z, partialTick)); - - byte lightIndex = 0; - if (this.world.getBlockLitInteriorSurface(blockPos)) { - TilePos queryPos = new TilePos(); - - lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.up(queryPos))); - lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.west(queryPos))); - lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.east(queryPos))); - lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.south(queryPos))); - lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.north(queryPos))); - } else { - lightIndex = this.world.getSavedLightIndex(blockPos); + + int bX = MathHelper.floor(MathHelper.lerp(this.xo, this.x, pt)); + int bY = MathHelper.floor(MathHelper.lerp(this.yo, this.y, pt)); + int bZ = MathHelper.floor(MathHelper.lerp(this.zo, this.z, pt)); + + if (this.world.getBlockLitInteriorSurface(this.qPos.set(bX, bY, bZ))) { + byte lIdx = 0; + lIdx = LightIndexHelper.max(lIdx, this.world.getSavedLightIndex(this.qPos.set(bX, bY + 1, bZ))); + lIdx = LightIndexHelper.max(lIdx, this.world.getSavedLightIndex(this.qPos.set(bX - 1, bY, bZ))); + lIdx = LightIndexHelper.max(lIdx, this.world.getSavedLightIndex(this.qPos.set(bX + 1, bY, bZ))); + lIdx = LightIndexHelper.max(lIdx, this.world.getSavedLightIndex(this.qPos.set(bX, bY, bZ + 1))); + lIdx = LightIndexHelper.max(lIdx, this.world.getSavedLightIndex(this.qPos.set(bX, bY, bZ - 1))); + return lIdx; } - return lightIndex; + return this.world.getSavedLightIndex(this.qPos.set(bX, bY, bZ)); } public byte getLightIndex(float partialTick) { diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleAcidBoiling.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleAcidBoiling.java new file mode 100644 index 000000000..131c3a8a2 --- /dev/null +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleAcidBoiling.java @@ -0,0 +1,72 @@ +package net.minecraft.client.render.particle; + +import net.minecraft.client.render.texture.stitcher.IconCoordinate; +import net.minecraft.client.render.texture.stitcher.TextureRegistry; +import net.minecraft.core.block.material.Materials; +import net.minecraft.core.util.helper.MathHelper; +import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; +import org.jetbrains.annotations.NotNull; + +public class ParticleAcidBoiling extends Particle { + + private float sinTimer = 0.0F; + private final boolean isReversed; + private final boolean needsWater; + private final TilePos qpos = new TilePos(); + private final @NotNull IconCoordinate popping = TextureRegistry.getTexture("minecraft:particle/acid_boiling_pop"); + + public ParticleAcidBoiling(World world, double x, double y, double z, double xa, double ya, double za, boolean needsWater) { + super(world, x, y, z, xa, ya, za); + this.needsWater = needsWater; + this.rCol = 1.0F; + this.gCol = 1.0F; + this.bCol = 1.0F; + this.tex = TextureRegistry.getTexture("minecraft:particle/acid_boiling"); + this.size *= random.nextFloat() * 0.7F + 0.3F; + this.xd = xa * 0.2 + (Math.random() * (double) 2.0F - (double) 1.0F) * (double) 0.02F; + this.yd = ya * 0.2 + (Math.random() * (double) 2.0F - (double) 1.0F) * (double) 0.02F; + this.zd = za * 0.2 + (Math.random() * (double) 2.0F - (double) 1.0F) * (double) 0.02F; + this.lifetime = (int) ((double) 16.0F / (Math.random() * 0.4 + 0.1)); + this.isReversed = random.nextInt(2) == 0; + } + + @Override + public void tick() { + ++this.sinTimer; + if (this.sinTimer > 100.0F) { + this.sinTimer = 0.0F; + } + + this.cachedLightmapCoord = this.calcLightIndex(1.0F); + this.xo = this.x; + this.yo = this.y; + this.zo = this.z; + double expand = 0.05; + boolean inWater = this.world.getBlockMaterial(this.qpos.set((int) this.x, (int) this.y, (int) this.z)) == Materials.ACID; + if (inWater) { + this.yd = 0.2; + this.xd = MathHelper.sin(this.sinTimer * 0.95F) / 30.0F * (float) (this.isReversed ? -1 : 1); + this.zd = MathHelper.cos(this.sinTimer * 0.95F) / 30.0F * (float) (this.isReversed ? -1 : 1); + } else { + this.yd = MathHelper.clamp(this.yd, -expand, expand); + } + + this.move(this.xd, this.yd, this.zd); + this.xd *= 0.85; + this.yd *= 0.85; + this.zd *= 0.85; + if (this.needsWater && !inWater) { + this.lifetime = MathHelper.clamp(this.lifetime, 0, 8); + } + + if (this.lifetime == 6) { + this.tex = this.popping; + this.world.spawnParticle("arrowtrail", this.x, this.y, this.z, 0.0F, 0.0F, 0.0F, 1, false); + } else if (this.lifetime <= 0) { + this.remove(); + } + + --this.lifetime; + } +} diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleArrowGolden.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleArrowGolden.java index 7c01c1ae3..dc1c3086e 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleArrowGolden.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleArrowGolden.java @@ -31,7 +31,7 @@ public class ParticleArrowGolden extends Particle { } @Override - public void render(@NotNull TessellatorParticle t, float partialTick) { + public void render(@NotNull TessellatorParticle tessellatorParticle, float partialTick) { float l = ((this.age + partialTick) / this.lifetime) * 32F; if (l < 0.0F) { l = 0.0F; @@ -40,7 +40,7 @@ public class ParticleArrowGolden extends Particle { l = 1.0F; } this.size = this.oSize * l; - super.render(t, partialTick); + super.render(tessellatorParticle, partialTick); } @Override diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBlockBreaking.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBlockBreaking.java index e03155d13..7c2fc09f4 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBlockBreaking.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBlockBreaking.java @@ -15,18 +15,24 @@ import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; public class ParticleBlockBreaking extends Particle { - private final Block block; - private final Side side; + private Block block; + private Side side; private final @NotNull TilePos initPos = new TilePos(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE); public ParticleBlockBreaking(World world, double x, double y, double z, double xa, double ya, double za, Block block, Side side, int meta) { super(world, x, y, z, xa, ya, za); + this.reset(world, x, y, z, xa, ya, za, block, side, meta); + } + + public ParticleBlockBreaking reset(World world, double x, double y, double z, double xa, double ya, double za, Block block, Side side, int meta) { + super.resetBase(world, x, y, z, xa, ya, za); this.side = side; this.block = block; this.tex = BlockModelDispatcher.getInstance().getDispatch(block).getParticleTexture(this.side, meta); this.gravity = block.blockParticleGravity; this.rCol = this.gCol = this.bCol = 0.6F; this.size /= 2.0F; + return this; } public ParticleBlockBreaking init(@NotNull TilePosc tilePos) { @@ -44,11 +50,11 @@ public class ParticleBlockBreaking extends Particle { } @Override - public void render(@NotNull TessellatorParticle t, float partialTick) { + public void render(@NotNull TessellatorParticle tessellatorParticle, float partialTick) { if (this.tex == null) return; - t.setLightmapCoord1i(getLightIndex(partialTick)); - t.setColorOpaque3f(this.rCol, this.gCol, this.bCol); - t.addParticle( + tessellatorParticle.setLightmapCoord1i(getLightIndex(partialTick)); + tessellatorParticle.setColorOpaque3f(this.rCol, this.gCol, this.bCol); + tessellatorParticle.addParticle( MathHelper.lerp(this.xo, this.x, partialTick), MathHelper.lerp(this.yo, this.y, partialTick), MathHelper.lerp(this.zo, this.z, partialTick), this.size * 0.1f, @@ -78,4 +84,4 @@ public class ParticleBlockBreaking extends Particle { return lightIndex; } -} +} \ No newline at end of file diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleDispatcher.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleDispatcher.java index d1a1dbea5..f30ce7554 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleDispatcher.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleDispatcher.java @@ -225,13 +225,13 @@ public final class ParticleDispatcher extends Dispatcher @Override public Particle newParticle(@NotNull World world, double x, double y, double z, double motionX, double motionY, double motionZ, int data) { int color = BlockColorDispatcher.getInstance().getDispatch(Blocks.FLUID_WATER_STILL).getWorldColor(world, new TilePos(x, y, z), 0); - return new ParticleFluidDrip(world, x, y, z, color, TextureRegistry.getTexture("minecraft:block/water_flowing")); + return new ParticleFluidDrip(world, x, y, z, color, TextureRegistry.getTexture("minecraft:block/fluid/water/flowing")); } }); addDispatch("dripLava", new ParticleEntry() { @Override public Particle newParticle(@NotNull World world, double x, double y, double z, double motionX, double motionY, double motionZ, int data) { - return new ParticleFluidDrip(world, x, y, z, 0xFFFFFF, TextureRegistry.getTexture("minecraft:block/lava_flowing")).setFullBright(); + return new ParticleFluidDrip(world, x, y, z, 0xFFFFFF, TextureRegistry.getTexture("minecraft:block/fluid/lava/flowing")).setFullBright(); } }); addDispatch("ashmote", new ParticleEntry() { @@ -282,5 +282,12 @@ public final class ParticleDispatcher extends Dispatcher return new ParticleRubyglassLightning(world, x, y, z, pitch, yaw); } }); + + addDispatch("acidBoiling", new ParticleEntry() { + @Override + public Particle newParticle(@NotNull World world, double x, double y, double z, double motionX, double motionY, double motionZ, int data) { + return new ParticleAcidBoiling(world, x, y, z, motionX, motionY, motionZ, true); + } + }); } } diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFirefly.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFirefly.java index aef5fb994..53bcb7bef 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFirefly.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFirefly.java @@ -83,7 +83,7 @@ public class ParticleFirefly extends Particle { } @Override - public void render(@NotNull TessellatorParticle t, float partialTick) { + public void render(@NotNull TessellatorParticle tessellatorParticle, float partialTick) { float ibr = getInternalBrightness(partialTick); if (ibr < 0.5f) { this.rCol = MathHelper.lerp(this.minR, this.midR, ibr * 2); @@ -99,7 +99,7 @@ public class ParticleFirefly extends Particle { this.gCol += this.oG; this.bCol += this.oB; - super.render(t, partialTick); + super.render(tessellatorParticle, partialTick); } public void renderParticleInGui(TessellatorGeneral t, float partialTick) { diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFlame.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFlame.java index a2fc5df57..a95fe7539 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFlame.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFlame.java @@ -28,10 +28,10 @@ public class ParticleFlame extends Particle { } @Override - public void render(@NotNull TessellatorParticle t, float partialTick) { + public void render(@NotNull TessellatorParticle tessellatorParticle, float partialTick) { float s = ((float) this.age + partialTick) / (float) this.lifetime; this.size = this.oSize * (1.0F - s * s * 0.5F); - super.render(t, partialTick); + super.render(tessellatorParticle, partialTick); } @Override diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFluidDrip.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFluidDrip.java index a319b1db4..b5b6b997b 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFluidDrip.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFluidDrip.java @@ -59,11 +59,11 @@ public class ParticleFluidDrip extends Particle { } @Override - public void render(@NotNull TessellatorParticle t, float partialTick) { + public void render(@NotNull TessellatorParticle tessellatorParticle, float partialTick) { if (this.tex == null) return; - t.setLightmapCoord1i(getLightIndex(partialTick)); - t.setColorOpaque3f(this.rCol, this.gCol, this.bCol); - t.addParticle( + tessellatorParticle.setLightmapCoord1i(getLightIndex(partialTick)); + tessellatorParticle.setColorOpaque3f(this.rCol, this.gCol, this.bCol); + tessellatorParticle.addParticle( MathHelper.lerp(this.xo, this.x, partialTick), MathHelper.lerp(this.yo, this.y, partialTick), MathHelper.lerp(this.zo, this.z, partialTick), this.size * 0.1f, diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleHeart.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleHeart.java index 3e3255b48..b7af7e7af 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleHeart.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleHeart.java @@ -27,7 +27,7 @@ public class ParticleHeart extends Particle { } @Override - public void render(@NotNull TessellatorParticle t, float partialTick) { + public void render(@NotNull TessellatorParticle tessellatorParticle, float partialTick) { float l = ((this.age + partialTick) / this.lifetime) * 32F; if (l < 0.0F) { l = 0.0F; @@ -36,7 +36,7 @@ public class ParticleHeart extends Particle { l = 1.0F; } this.size = this.oSize * l; - super.render(t, partialTick); + super.render(tessellatorParticle, partialTick); } @Override diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleItemBreaking.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleItemBreaking.java index 7125f5740..53fa14750 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleItemBreaking.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleItemBreaking.java @@ -18,11 +18,11 @@ public class ParticleItemBreaking extends Particle { } @Override - public void render(@NotNull TessellatorParticle t, float partialTick) { + public void render(@NotNull TessellatorParticle tessellatorParticle, float partialTick) { if (this.tex == null) return; - t.setLightmapCoord1i(getLightIndex(partialTick)); - t.setColorOpaque3f(this.rCol, this.gCol, this.bCol); - t.addParticle(MathHelper.lerp(this.xo, this.x, partialTick), + tessellatorParticle.setLightmapCoord1i(getLightIndex(partialTick)); + tessellatorParticle.setColorOpaque3f(this.rCol, this.gCol, this.bCol); + tessellatorParticle.addParticle(MathHelper.lerp(this.xo, this.x, partialTick), MathHelper.lerp(this.yo, this.y, partialTick), MathHelper.lerp(this.zo, this.z, partialTick), this.size * 0.1f, this.tex.getIconUMin() + (this.tex.getIconUSize() * this.uo / 4F), this.tex.getIconVMin() + (this.tex.getIconVSize() * this.uo / 4F), this.tex.getIconUSize() * 0.25f, this.tex.getIconVSize() * 0.25f); diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLava.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLava.java index 79c11ed13..cda09824a 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLava.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLava.java @@ -28,10 +28,10 @@ public class ParticleLava extends Particle { } @Override - public void render(@NotNull TessellatorParticle t, float partialTick) { + public void render(@NotNull TessellatorParticle tessellatorParticle, float partialTick) { float l = (this.age + partialTick) / this.lifetime; this.size = this.oSize * (1.0F - l * l); - super.render(t, partialTick); + super.render(tessellatorParticle, partialTick); } @Override diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLeaf.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLeaf.java index 7a768d0f6..c06799116 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLeaf.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLeaf.java @@ -9,6 +9,8 @@ import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.world.World; import net.minecraft.core.world.pos.TilePos; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.joml.primitives.AABBdc; public class ParticleLeaf extends Particle { public ParticleLeaf(World world, double x, double y, double z, double xa, double ya, double za) { @@ -23,8 +25,14 @@ public class ParticleLeaf extends Particle { } @Override - public boolean collidesWithBlock(@NotNull Block block, int data) { - return !Block.hasLogicClass(block, BlockLogicLeavesBase.class); + protected @Nullable AABBdc getCollisionBox(TilePos pos) { + Block block = this.world.getBlockType(pos); + + if (Block.hasLogicClass(block, BlockLogicLeavesBase.class)) { + return null; + } + + return super.getCollisionBox(pos); } public ParticleLeaf init(@NotNull TilePos tilePos) { @@ -52,26 +60,40 @@ public class ParticleLeaf extends Particle { this.xo = this.x; this.yo = this.y; this.zo = this.z; + if (this.age++ >= this.lifetime) { this.remove(); } + this.yd -= 0.04D * this.gravity; + if (this.onGround) { this.xd *= 0.0D; this.zd *= 0.0D; } + this.move(this.xd, this.yd, this.zd); + + this.xd *= 0.98D; + this.yd *= 0.98D; + this.zd *= 0.98D; } @Override - public void render(@NotNull TessellatorParticle t, float partialTick) { + public void render(@NotNull TessellatorParticle tessellatorParticle, float partialTick) { if (this.tex == null) return; - t.setLightmapCoord1i(getLightIndex(partialTick)); - t.setColorOpaque3f(this.rCol, this.gCol, this.bCol); - t.addParticle( + tessellatorParticle.setLightmapCoord1i(getLightIndex(partialTick)); + tessellatorParticle.setColorOpaque3f(this.rCol, this.gCol, this.bCol); + + tessellatorParticle.addParticle( MathHelper.lerp(this.xo, this.x, partialTick), MathHelper.lerp(this.yo, this.y, partialTick), - MathHelper.lerp(this.zo, this.z, partialTick), this.size * 0.1f, - this.tex.getIconUMin() + (this.tex.getIconUSize() * this.uo / 4F), this.tex.getIconVMin() + (this.tex.getIconVSize() * this.uo / 4F), this.tex.getIconUSize() * 0.25f, this.tex.getIconVSize() * 0.25f); + MathHelper.lerp(this.zo, this.z, partialTick), + this.size * 0.1f, + this.tex.getIconUMin() + (this.tex.getIconUSize() * this.uo / 4F), + this.tex.getIconVMin() + (this.tex.getIconVSize() * this.vo / 4F), + this.tex.getIconUSize() * 0.25f, + this.tex.getIconVSize() * 0.25f + ); } } diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleNote.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleNote.java index 15338e4c7..3f44568c7 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleNote.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleNote.java @@ -32,7 +32,7 @@ public class ParticleNote extends Particle { } @Override - public void render(@NotNull TessellatorParticle t, float partialTick) { + public void render(@NotNull TessellatorParticle tessellatorParticle, float partialTick) { float l = ((this.age + partialTick) / this.lifetime) * 32F; if (l < 0.0F) { l = 0.0F; @@ -41,7 +41,7 @@ public class ParticleNote extends Particle { l = 1.0F; } this.size = this.oSize * l; - super.render(t, partialTick); + super.render(tessellatorParticle, partialTick); } @Override diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePortal.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePortal.java index eaaa968d6..f063bd052 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePortal.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePortal.java @@ -34,13 +34,13 @@ public class ParticlePortal extends Particle { } @Override - public void render(@NotNull TessellatorParticle t, float partialTick) { + public void render(@NotNull TessellatorParticle tessellatorParticle, float partialTick) { float s = (this.age + partialTick) / this.lifetime; s = 1.0F - s; s *= s; s = 1.0F - s; this.size = this.oSize * s; - super.render(t, partialTick); + super.render(tessellatorParticle, partialTick); } @Override diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePuffRGB.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePuffRGB.java index a0adf6a45..aed803848 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePuffRGB.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePuffRGB.java @@ -38,7 +38,7 @@ public class ParticlePuffRGB extends Particle { } @Override - public void render(@NotNull TessellatorParticle t, float partialTick) { + public void render(@NotNull TessellatorParticle tessellatorParticle, float partialTick) { float l = ((this.age + partialTick) / this.lifetime) * 32F; if (l < 0.0F) { l = 0.0F; @@ -57,9 +57,9 @@ public class ParticlePuffRGB extends Particle { } else { lmc = getLightIndex(partialTick); } - t.setLightmapCoord1i(lmc); - t.setColorOpaque3f(this.rCol, this.gCol, this.bCol); - t.addParticle( + tessellatorParticle.setLightmapCoord1i(lmc); + tessellatorParticle.setColorOpaque3f(this.rCol, this.gCol, this.bCol); + tessellatorParticle.addParticle( MathHelper.lerp(this.xo, this.x, partialTick), MathHelper.lerp(this.yo, this.y, partialTick), MathHelper.lerp(this.zo, this.z, partialTick), this.size * 0.1f, diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleRedstoneDust.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleRedstoneDust.java index d3f35182f..2ba5837e9 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleRedstoneDust.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleRedstoneDust.java @@ -47,7 +47,7 @@ public class ParticleRedstoneDust extends Particle { } @Override - public void render(@NotNull TessellatorParticle t, float partialTick) { + public void render(@NotNull TessellatorParticle tessellatorParticle, float partialTick) { if (this.tex == null) return; float l = ((this.age + partialTick) / this.lifetime) * 32F; if (l < 0.0F) { @@ -66,9 +66,9 @@ public class ParticleRedstoneDust extends Particle { } else { lmc = getLightIndex(partialTick); } - t.setLightmapCoord1i(lmc); - t.setColorOpaque3f(this.rCol, this.gCol, this.bCol); - t.addParticle( + tessellatorParticle.setLightmapCoord1i(lmc); + tessellatorParticle.setColorOpaque3f(this.rCol, this.gCol, this.bCol); + tessellatorParticle.addParticle( MathHelper.lerp(this.xo, this.x, partialTick), MathHelper.lerp(this.yo, this.y, partialTick), MathHelper.lerp(this.zo, this.z, partialTick), diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSlimeChunk.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSlimeChunk.java index d83182881..9ae87306d 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSlimeChunk.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSlimeChunk.java @@ -18,12 +18,12 @@ public class ParticleSlimeChunk extends Particle { } @Override - public void render(@NotNull TessellatorParticle t, float partialTick) { + public void render(@NotNull TessellatorParticle tessellatorParticle, float partialTick) { if (this.tex == null) return; float br = 1.0f; - t.setLightmapCoord1i(getLightIndex(partialTick)); - t.setColorOpaque3f(this.rCol * br, this.gCol * br, this.bCol * br); - t.addParticle(MathHelper.lerp(this.xo, this.x, partialTick), + tessellatorParticle.setLightmapCoord1i(getLightIndex(partialTick)); + tessellatorParticle.setColorOpaque3f(this.rCol * br, this.gCol * br, this.bCol * br); + tessellatorParticle.addParticle(MathHelper.lerp(this.xo, this.x, partialTick), MathHelper.lerp(this.yo, this.y, partialTick), MathHelper.lerp(this.zo, this.z, partialTick), this.size * 0.1f, diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSmoke.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSmoke.java index 1c15b7412..0e0ab3ff5 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSmoke.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSmoke.java @@ -30,7 +30,7 @@ public class ParticleSmoke extends Particle { } @Override - public void render(@NotNull TessellatorParticle t, float partialTick) { + public void render(@NotNull TessellatorParticle tessellatorParticle, float partialTick) { float l = ((this.age + partialTick) / this.lifetime) * 32F; if (l < 0.0F) { l = 0.0F; @@ -39,7 +39,7 @@ public class ParticleSmoke extends Particle { l = 1.0F; } this.size = this.oSize * l; - super.render(t, partialTick); + super.render(tessellatorParticle, partialTick); } @Override diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSnowShovel.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSnowShovel.java index e89fe76f4..20a4154d8 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSnowShovel.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSnowShovel.java @@ -31,7 +31,7 @@ public class ParticleSnowShovel extends Particle { } @Override - public void render(@NotNull TessellatorParticle t, float partialTick) { + public void render(@NotNull TessellatorParticle tessellatorParticle, float partialTick) { float l = ((this.age + partialTick) / this.lifetime) * 32F; if(l < 0.0F) { l = 0.0F; @@ -40,7 +40,7 @@ public class ParticleSnowShovel extends Particle { l = 1.0F; } this.size = this.oSize * l; - super.render(t, partialTick); + super.render(tessellatorParticle, partialTick); } @Override diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleVentSmoke.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleVentSmoke.java index 05518fc88..5d0b75f4d 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleVentSmoke.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleVentSmoke.java @@ -30,7 +30,7 @@ public class ParticleVentSmoke extends Particle { } @Override - public void render(@NotNull TessellatorParticle t, float partialTick) { + public void render(@NotNull TessellatorParticle tessellatorParticle, float partialTick) { float size = ((this.age + partialTick) / this.lifetime) * 32F; if (size < 0.0F) { size = 0.0F; @@ -39,7 +39,7 @@ public class ParticleVentSmoke extends Particle { size = 1.0F; } this.size = this.oSize * size; - super.render(t, partialTick); + super.render(tessellatorParticle, partialTick); } @Override diff --git a/game/client/src/main/java/net/minecraft/client/render/renderer/GLRenderer.java b/game/client/src/main/java/net/minecraft/client/render/renderer/GLRenderer.java index 78e748be1..0cbf0a55f 100644 --- a/game/client/src/main/java/net/minecraft/client/render/renderer/GLRenderer.java +++ b/game/client/src/main/java/net/minecraft/client/render/renderer/GLRenderer.java @@ -49,6 +49,10 @@ public class GLRenderer { LIGHT_ENABLED = flag; } + public static boolean globalGetLightEnabled() { + return LIGHT_ENABLED; + } + public static @NotNull Vector4f globalGetLightModelAmbient() { return LIGHT_MODEL_AMBIENT; } diff --git a/game/client/src/main/java/net/minecraft/client/render/renderer/Shaders.java b/game/client/src/main/java/net/minecraft/client/render/renderer/Shaders.java index e7f023344..9f17936e6 100644 --- a/game/client/src/main/java/net/minecraft/client/render/renderer/Shaders.java +++ b/game/client/src/main/java/net/minecraft/client/render/renderer/Shaders.java @@ -29,10 +29,11 @@ public final class Shaders { public static final @NotNull Shader ITEM = register("item", new Shader()); public static final @NotNull Shader INTERFACE = register("interface", new Shader()); public static final @NotNull Shader COLOR = register("color", new Shader()); + public static final @NotNull Shader ACID_OVERLAY = register("acid_overlay", new Shader()); public static final @NotNull Shader COLOR_WORLD = register("color_world", new Shader()); public static final @NotNull Shader CLOUDS = register("clouds", new Shader()); - public static final @NotNull ShaderGeometry PARTICLE = register("particle", new ShaderGeometry()); - public static final @NotNull ShaderGeometry FONT = register("font", new ShaderGeometry()); + public static final @NotNull Shader PARTICLE = register("particle", new Shader()); + public static final @NotNull Shader FONT = register("font", new Shader()); public static final @NotNull ShaderGeometry LINES = register("lines", new ShaderGeometry()); public static final @NotNull ShaderGeometry LOD = register("lod", new ShaderGeometry()); diff --git a/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRendererMultiDraw.java b/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRendererMultiDraw.java index 7b02ffd9b..a49744192 100644 --- a/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRendererMultiDraw.java +++ b/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRendererMultiDraw.java @@ -2,7 +2,6 @@ package net.minecraft.client.render.terrain; import java.util.HashSet; import java.util.List; -import java.util.Objects; import java.util.Set; import net.minecraft.client.render.TileEntityRenderDispatcher; @@ -10,7 +9,6 @@ import net.minecraft.client.render.block.model.BlockModel; import net.minecraft.client.render.block.model.BlockModelDispatcher; import net.minecraft.client.render.culling.CameraFrustum; import net.minecraft.client.render.terrain.VertexBuffer.Entry; -import net.minecraft.client.render.tessellator.TessellatorGeneral; import net.minecraft.client.render.tessellator.TessellatorTerrainImpl; import net.minecraft.core.block.Block; import net.minecraft.core.block.entity.TileEntity; @@ -18,6 +16,7 @@ import net.minecraft.core.world.World; import net.minecraft.core.world.WorldSource; import net.minecraft.core.world.chunk.Chunk; import net.minecraft.core.world.chunk.ChunkCache; +import net.minecraft.core.world.particle.ParticleEmitterRange; import net.minecraft.core.world.pos.TilePos; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -83,6 +82,15 @@ public class ChunkRendererMultiDraw extends ChunkRenderer { for (pos.z = this.min.z; pos.z < this.max.z; pos.z++) { for (pos.x = this.min.x; pos.x < this.max.x; pos.x++) { final @NotNull Block block = chunkCache.getBlockType(pos); + + if (renderPass == 0) { + ParticleEmitterRange type = block.getLogic().getParticleEmitterRange(); + + if (type != null) { + this.getWorld().particleEmitters.add(new TilePos(pos), type); + } + } + if (!hasStartedDrawing) { hasStartedDrawing = true; TESSELLATOR.startDrawingQuads(); diff --git a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorFont.java b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorFont.java index f2ca1c8a2..a5a6a24dc 100644 --- a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorFont.java +++ b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorFont.java @@ -25,6 +25,7 @@ public class TessellatorFont { private final int vao; private final int vbo; + private final int vboMesh; private final @NotNull String name; private ByteBuffer data; @@ -37,24 +38,39 @@ public class TessellatorFont { this.vao = GL41.glGenVertexArrays(); this.vbo = GL41.glGenBuffers(); + this.vboMesh = GL41.glGenBuffers(); GL41.glBindVertexArray(this.vao); + + GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, this.vboMesh); + float[] mesh = { + 0, 1, + 1, 1, + 0, 0, + 1, 0, + }; + GL41.glBufferData(GL41.GL_ARRAY_BUFFER, mesh, GL41.GL_STATIC_DRAW); + GL41.glVertexAttribPointer(0, 2, GL41.GL_FLOAT, false, 0, 0); + GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, this.vbo); - int vertSize = 2 * Float.BYTES + 9; - int offset = 0; - GL41.glVertexAttribPointer(0, 2, GL41.GL_FLOAT, false, vertSize, offset); offset += Float.BYTES * 2; // Pos XY - GL41.glVertexAttribPointer(1, 2, GL41.GL_UNSIGNED_BYTE, false, vertSize, offset); offset += 2; // Width Height - GL41.glVertexAttribPointer(2, 4, GL41.GL_UNSIGNED_BYTE, true, vertSize, offset); offset += 4; // Color - GL41.glVertexAttribPointer(3, 2, GL41.GL_UNSIGNED_BYTE, false, vertSize, offset); offset += 2; // UV - GL41.glVertexAttribPointer(4, 1, GL41.GL_UNSIGNED_BYTE, false, vertSize, offset); offset += 1; // Config - GL41.glVertexAttrib1f(5, LightIndexHelper.lightIndex2i(15, 15)); + setAttribOffset(0); + GL41.glVertexAttrib1f(6, LightIndexHelper.lightIndex2i(15, 15)); GL41.glEnableVertexAttribArray(0); GL41.glEnableVertexAttribArray(1); GL41.glEnableVertexAttribArray(2); GL41.glEnableVertexAttribArray(3); GL41.glEnableVertexAttribArray(4); + GL41.glEnableVertexAttribArray(5); + + GL41.glVertexAttribDivisor(0, 0); // Vertices, always reuse the same 4 vertices + GL41.glVertexAttribDivisor(1, 1); // Data, one per quad + GL41.glVertexAttribDivisor(2, 1); // Data, one per quad + GL41.glVertexAttribDivisor(3, 1); // Data, one per quad + GL41.glVertexAttribDivisor(4, 1); // Data, one per quad + GL41.glVertexAttribDivisor(5, 1); // Data, one per quad + GL41.glBindVertexArray(0); } @@ -122,12 +138,14 @@ public class TessellatorFont { int start = this.renderRanges.getInt(i + 1); int count = this.renderRanges.getInt(i + 2); GL41.glBindTexture(GL41.GL_TEXTURE_2D, texture); - GL41.glDrawArrays(DrawMode.POINTS.cap, start, count); + setAttribOffset(start); + GL41.glDrawArraysInstanced(DrawMode.TRIANGLE_STRIP.cap, 0, 4, count); } if (this.texture != -1) { GL41.glBindTexture(GL41.GL_TEXTURE_2D, this.texture); - GL41.glDrawArrays(DrawMode.POINTS.cap, this.start, this.vertexCount); + setAttribOffset(this.start); + GL41.glDrawArraysInstanced(DrawMode.TRIANGLE_STRIP.cap, 0, 4, this.vertexCount); } GL41.glBindVertexArray(0); @@ -216,6 +234,16 @@ public class TessellatorFont { } } + private void setAttribOffset(int offset) { + int vertSize = 2 * Float.BYTES + 9; + int _offset = offset * vertSize; + GL41.glVertexAttribPointer(1, 2, GL41.GL_FLOAT, false, vertSize, _offset); _offset += Float.BYTES * 2; // Pos XY + GL41.glVertexAttribPointer(2, 2, GL41.GL_UNSIGNED_BYTE, false, vertSize, _offset); _offset += 2; // Width Height + GL41.glVertexAttribPointer(3, 4, GL41.GL_UNSIGNED_BYTE, true, vertSize, _offset); _offset += 4; // Color + GL41.glVertexAttribPointer(4, 2, GL41.GL_UNSIGNED_BYTE, false, vertSize, _offset); _offset += 2; // UV + GL41.glVertexAttribPointer(5, 1, GL41.GL_UNSIGNED_BYTE, false, vertSize, _offset); _offset += 1; // Config + } + public record FontRenderBuffer(int vao, int vbo, int[] metadata) { public void delete() { GL41.glDeleteVertexArrays(this.vao); @@ -236,7 +264,7 @@ public class TessellatorFont { int start = this.metadata[i + 1]; int count = this.metadata[i + 2]; GL41.glBindTexture(GL41.GL_TEXTURE_2D, texture); - GL41.glDrawArrays(DrawMode.POINTS.cap, start, count); + GL41.glDrawArraysInstanced(DrawMode.TRIANGLE_STRIP.cap, start, 4, count); } diff --git a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorParticleShader.java b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorParticleShader.java index 1f5dd4dba..6f7866d07 100644 --- a/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorParticleShader.java +++ b/game/client/src/main/java/net/minecraft/client/render/tessellator/TessellatorParticleShader.java @@ -22,6 +22,7 @@ public class TessellatorParticleShader implements TessellatorParticle { private int count = 0; private final int vao; private final int vbo; + private final int vboMesh; private int color; private byte lightIndex; @@ -34,18 +35,29 @@ public class TessellatorParticleShader implements TessellatorParticle { this.buffer = BufferUtils.createByteBuffer(size); this.vao = GL41.glGenVertexArrays(); this.vbo = GL41.glGenBuffers(); + this.vboMesh = GL41.glGenBuffers(); GL41.glBindVertexArray(this.vao); + GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, this.vboMesh); + float[] mesh = { + -1, 1, + -1, -1, + 1, 1, + 1, -1, + }; + GL41.glBufferData(GL41.GL_ARRAY_BUFFER, mesh, GL41.GL_STATIC_DRAW); + GL41.glVertexAttribPointer(0, 2, GL41.GL_FLOAT, false, 0, 0); + GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, this.vbo); int offset = 0; int vertexSize = 37; - GL41.glVertexAttribPointer(0, 3, GL41.GL_FLOAT, false, vertexSize, offset); offset += 3 * Float.BYTES; // Pos - GL41.glVertexAttribPointer(1, 1, GL41.GL_FLOAT, false, vertexSize, offset); offset += Float.BYTES; // Scale - GL41.glVertexAttribPointer(2, 4, GL41.GL_UNSIGNED_BYTE, true, vertexSize, offset); offset += 4; // Color - GL41.glVertexAttribPointer(3, 2, GL41.GL_FLOAT, false, vertexSize, offset); offset += 2 * Float.BYTES; // UV - GL41.glVertexAttribPointer(4, 2, GL41.GL_FLOAT, false, vertexSize, offset); offset += 2 * Float.BYTES; // UVSizes - GL41.glVertexAttribPointer(5, 1, GL41.GL_UNSIGNED_BYTE, false, vertexSize, offset); offset += 1; // Lightmap + GL41.glVertexAttribPointer(1, 3, GL41.GL_FLOAT, false, vertexSize, offset); offset += 3 * Float.BYTES; // Pos + GL41.glVertexAttribPointer(2, 1, GL41.GL_FLOAT, false, vertexSize, offset); offset += Float.BYTES; // Scale + GL41.glVertexAttribPointer(3, 4, GL41.GL_UNSIGNED_BYTE, true, vertexSize, offset); offset += 4; // Color + GL41.glVertexAttribPointer(4, 2, GL41.GL_FLOAT, false, vertexSize, offset); offset += 2 * Float.BYTES; // UV + GL41.glVertexAttribPointer(5, 2, GL41.GL_FLOAT, false, vertexSize, offset); offset += 2 * Float.BYTES; // UVSizes + GL41.glVertexAttribPointer(6, 1, GL41.GL_UNSIGNED_BYTE, false, vertexSize, offset); offset += 1; // Lightmap GL41.glEnableVertexAttribArray(0); GL41.glEnableVertexAttribArray(1); @@ -53,6 +65,15 @@ public class TessellatorParticleShader implements TessellatorParticle { GL41.glEnableVertexAttribArray(3); GL41.glEnableVertexAttribArray(4); GL41.glEnableVertexAttribArray(5); + GL41.glEnableVertexAttribArray(6); + + GL41.glVertexAttribDivisor(0, 0); // Vertices, always reuse the same 4 vertices + GL41.glVertexAttribDivisor(1, 1); // Data, one per quad + GL41.glVertexAttribDivisor(2, 1); // Data, one per quad + GL41.glVertexAttribDivisor(3, 1); // Data, one per quad + GL41.glVertexAttribDivisor(4, 1); // Data, one per quad + GL41.glVertexAttribDivisor(5, 1); // Data, one per quad + GL41.glVertexAttribDivisor(6, 1); // Data, one per quad GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, 0); GL41.glBindVertexArray(0); @@ -108,7 +129,13 @@ public class TessellatorParticleShader implements TessellatorParticle { GL41.glBindBuffer(GL41.GL_ARRAY_BUFFER, this.vbo); GL41.glBufferData(GL41.GL_ARRAY_BUFFER, this.buffer.flip(), GL41.GL_STREAM_DRAW); - GLRenderer.render(this.vao, this.vbo, 0, this.count, DrawMode.POINTS); + GLRenderer.getShader().bind(); + GLRenderer.globalSetUniforms(GLRenderer.getShader()); + + GL41.glDrawArraysInstanced(DrawMode.TRIANGLE_STRIP.cap, 0, 4, this.count); + + GL41.glUseProgram(0); + GL41.glBindVertexArray(0); } public void checkIsDrawing() { diff --git a/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererStatue.java b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererStatue.java index 3fb385560..40d2af336 100644 --- a/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererStatue.java +++ b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererStatue.java @@ -39,6 +39,10 @@ public class TileEntityRendererStatue extends TileEntityRenderer 0.0 && t < 1.0) { + float distX = abs(localX); + float w = 0.0; + + if (t > 0.25 && t < 0.75) { + w = 0.3; + + core = step(distX, 0.15); + } else if (t > 0.1 && t <= 0.9) { + w = 0.15; + } + drop = step(distX, w); + } + + // Colors + vec3 baseColor = vec3(0.85, 1.0, 0.25); + vec3 dripOuter = vec3(0.65, 0.85, 0.15); + vec3 dripInner = vec3(0.95, 1.0, 0.25); + vec3 dropCol = mix(dripOuter, dripInner, core); + vec3 col = mix(baseColor, dropCol, drop); + float distSq = dot(centerCoords, centerCoords); + float dripAlpha = 0.08 * drop * (1.0 + distSq * 2.0); + float finalAlpha = uColor.a * (vignetteAlpha + dripAlpha); + FragColor = vec4(col, finalAlpha); +} \ No newline at end of file diff --git a/game/client/src/main/resources/shaders/acid_overlay.vsh b/game/client/src/main/resources/shaders/acid_overlay.vsh new file mode 100644 index 000000000..775ecf1e5 --- /dev/null +++ b/game/client/src/main/resources/shaders/acid_overlay.vsh @@ -0,0 +1,21 @@ +#version 410 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec4 aColor; +layout (location = 2) in vec2 aUV; + +out vec4 Color; +out vec2 TexCoord; + +uniform mat4 model; +layout (std140) uniform Matrices { + mat4 projection; + mat4 projectionInv; + mat4 view; + mat4 viewInv; +} matrices; + +void main() { + gl_Position = matrices.projection * matrices.view * model * vec4(aPos, 1); + Color = aColor; + TexCoord = aUV; +} diff --git a/game/client/src/main/resources/shaders/font.gsh b/game/client/src/main/resources/shaders/font.gsh.disabled similarity index 100% rename from game/client/src/main/resources/shaders/font.gsh rename to game/client/src/main/resources/shaders/font.gsh.disabled diff --git a/game/client/src/main/resources/shaders/font.vsh b/game/client/src/main/resources/shaders/font.vsh index 12aa80801..c34eccbe3 100644 --- a/game/client/src/main/resources/shaders/font.vsh +++ b/game/client/src/main/resources/shaders/font.vsh @@ -1,18 +1,35 @@ #version 410 core -layout (location = 0) in vec2 aPos; -layout (location = 1) in vec2 aSize; -layout (location = 2) in vec4 aColor; -layout (location = 3) in vec2 aUV; -layout (location = 4) in float aConfig; -layout (location = 5) in float aLightmap; - -out VS_OUT { - vec2 size; - vec4 color; - vec2 uv; - vec2 lightmap; - float config; -} vs_out; + +#define MASK_ITALIC 0x01u +#define MASK_UNDERLINE 0x02u +#define MASK_STRIKETHROUGH 0x04u +#define MASK_BOLD 0x08u +#define MASK_OBFUSCATED 0x10u +#define MASK_OUTLINE 0x20u +#define MASK_SHADOW 0x80u + +layout (location = 0) in vec2 aMesh; +layout (location = 1) in vec2 aPos; +layout (location = 2) in vec2 aSize; +layout (location = 3) in vec4 aColor; +layout (location = 4) in vec2 aUV; +layout (location = 5) in float aConfig; +layout (location = 6) in float aLightmap; + +out vec4 Color; +out vec2 UV; +out vec2 TexCoord; +out vec2 Lightmap; +out vec2 Size; +out float Config; + +uniform mat4 model; +layout (std140) uniform Matrices { + mat4 projection; + mat4 projectionInv; + mat4 view; + mat4 viewInv; +} matrices; uniform float uZ; @@ -22,11 +39,29 @@ vec2 unpackLightCoord() { } void main() { - gl_Position = vec4(aPos, uZ, 1); + vec2 bSize = aSize/2; + vec4 bColor = aColor; + vec2 bUV = aUV/256.0; + vec2 bLightmap = unpackLightCoord(); + float bConfig = aConfig; + + UV = bUV; + Size = bSize; + Config = bConfig; + Color = bColor; + Lightmap = bLightmap; + + // x, y, shiftx, exX, exY, exU, exV +// 0, 1, -1, -1, 2, -1, 2 +// 1, 1, -1, 2, 2, 2, 2 +// 0, 0, 1, -1, -1, -1, -1 +// 1, 0, 1, 2, -1, 2, -1 + + // shiftx, exX, and exY are are derivable from the mesh vertices so are not encoded seperately in the static mesh + float shiftX = ((aMesh.y * -2) + 1); + vec2 ex = (aMesh * 3) - vec2(1, 1); - vs_out.size = aSize/2; - vs_out.color = aColor; - vs_out.uv = aUV/256.0; - vs_out.lightmap = unpackLightCoord(); - vs_out.config = aConfig; + vec2 shift = vec2((uint(bConfig) & MASK_ITALIC) * shiftX + 8/256, 0); + TexCoord = bUV + ((aMesh * aSize + ex)/128); + gl_Position = matrices.projection * matrices.view * model * vec4(aPos + aSize * aMesh + ex + shift, uZ, 1); } diff --git a/game/client/src/main/resources/shaders/particle.gsh b/game/client/src/main/resources/shaders/particle.gsh.disabled similarity index 100% rename from game/client/src/main/resources/shaders/particle.gsh rename to game/client/src/main/resources/shaders/particle.gsh.disabled diff --git a/game/client/src/main/resources/shaders/particle.vsh b/game/client/src/main/resources/shaders/particle.vsh index a23f94354..8e00c2704 100644 --- a/game/client/src/main/resources/shaders/particle.vsh +++ b/game/client/src/main/resources/shaders/particle.vsh @@ -1,18 +1,23 @@ #version 330 core -layout (location = 0) in vec3 aPos; -layout (location = 1) in float aScale; -layout (location = 2) in vec4 aColor; -layout (location = 3) in vec2 aUv; -layout (location = 4) in vec2 aUvSizes; -layout (location = 5) in float aLightmap; +layout (location = 0) in vec2 aMesh; +layout (location = 1) in vec3 aPos; +layout (location = 2) in float aScale; +layout (location = 3) in vec4 aColor; +layout (location = 4) in vec2 aUv; +layout (location = 5) in vec2 aUvSizes; +layout (location = 6) in float aLightmap; -out VS_OUT { - float scale; - vec4 color; - vec2 uv; - vec2 uvSizes; - vec2 lightmap; -} vs_out; +uniform mat4 model; +layout (std140) uniform Matrices { + mat4 projection; + mat4 projectionInv; + mat4 view; + mat4 viewInv; +} matrices; + +out vec4 Color; +out vec2 TexCoord; +out vec2 LightMapCoord; vec2 unpackLightCoord() { int asInt = int(aLightmap); @@ -20,11 +25,9 @@ vec2 unpackLightCoord() { } void main() { - gl_Position = vec4(aPos, 1); + Color = aColor; + LightMapCoord = unpackLightCoord(); - vs_out.scale = aScale; - vs_out.color = aColor; - vs_out.uv = aUv; - vs_out.uvSizes = aUvSizes; - vs_out.lightmap = unpackLightCoord(); + TexCoord = aUv + (((aMesh * vec2(1, -1)) + vec2(1, 1))/2.0) * aUvSizes; + gl_Position = matrices.projection * matrices.view * model * (vec4(aPos, 1) + matrices.viewInv * vec4(aMesh.x, aMesh.y, 0.0, 1.0) * aScale); } diff --git a/game/core/src/main/java/net/minecraft/core/achievement/Achievements.java b/game/core/src/main/java/net/minecraft/core/achievement/Achievements.java index 1fa32fe63..9e05ec69e 100644 --- a/game/core/src/main/java/net/minecraft/core/achievement/Achievements.java +++ b/game/core/src/main/java/net/minecraft/core/achievement/Achievements.java @@ -149,6 +149,13 @@ public abstract class Achievements new Achievement(NamespaceID.fromPool("minecraft", "fast_travel"), "fastTravel", Blocks.GRASS, ENTER_NETHER) .setType(Achievement.TYPE_NORMAL) .registerAchievement(); + public static final Achievement GET_STEEL_BLAST_FURNACE = + new Achievement(NamespaceID.fromPool("minecraft", "blast_furnace"), "blastFurnace", Blocks.FURNACE_BLAST_ACTIVE, Achievements.GET_NETHERCOAL) + .setType(Achievement.TYPE_SPECIAL) + .registerAchievement(); + public static final Achievement OBTAIN_STEEL = + new Achievement(NamespaceID.fromPool("minecraft", "obtain_steel"), "obtainSteel", Items.INGOT_STEEL, GET_STEEL_BLAST_FURNACE) + .registerAchievement(); public static void init(){}; } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java index bde66452d..62b5b9bcf 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java @@ -25,6 +25,7 @@ import net.minecraft.core.util.phys.BoundingVolume; import net.minecraft.core.util.phys.HitResult; import net.minecraft.core.world.World; import net.minecraft.core.world.WorldSource; +import net.minecraft.core.world.particle.ParticleEmitterRange; import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -191,10 +192,39 @@ public class BlockLogic implements BlockInterface, IItemConvertible { } @Override - public void onPlacedByWorld(final @NotNull World world, final @NotNull TilePosc tilePos) { } + public void onPlacedByWorld(final @NotNull World world, final @NotNull TilePosc tilePos) { + if (world.isClientSide) { + ParticleEmitterRange t = this.getParticleEmitterRange(); + if (t != null) { + world.particleEmitters.add(tilePos, t); + } + } + } + + @Override + public void onRemoved(final @NotNull World world, final @NotNull TilePosc tilePos, final int data) { + if (world.isClientSide) { + ParticleEmitterRange t = this.getParticleEmitterRange(); + if (t != null) { + world.particleEmitters.remove(tilePos); + } + } + } @Override - public void onRemoved(final @NotNull World world, final @NotNull TilePosc tilePos, final int data) { } + public void onPlacedByMob(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side, final @NotNull Mob mob, final double xHit, final double yHit) { + this.onPlacedOnSide(world, tilePos, side, xHit, yHit); + + if (world.isClientSide) { + ParticleEmitterRange t = this.getParticleEmitterRange(); + if (t != null) { + world.particleEmitters.add(tilePos, t); + } + } + } + + @Override + public void onPlacedOnSide(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side, final double xHit, final double yHit) { } @Override public void onDestroyedByPlayer(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side, final int data, final @NotNull Player player, final @Nullable Item item) { } @@ -438,14 +468,6 @@ public class BlockLogic implements BlockInterface, IItemConvertible { return true; } - @Override - public void onPlacedByMob(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side, final @NotNull Mob mob, final double xHit, final double yHit) { - this.onPlacedOnSide(world, tilePos, side, xHit, yHit); - } - - @Override - public void onPlacedOnSide(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side, final double xHit, final double yHit) { } - @Override public @NotNull String getLanguageKey(final int data) { return this.block.getKey(); @@ -493,4 +515,8 @@ public class BlockLogic implements BlockInterface, IItemConvertible { public @NotNull ItemStack getDefaultStack() { return this.block.getDefaultStack(); } + + public @Nullable ParticleEmitterRange getParticleEmitterRange() { + return null; // null by default, 16 block radius + } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicAsh.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicAsh.java index 8db54e008..054fea3df 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicAsh.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicAsh.java @@ -17,9 +17,6 @@ public class BlockLogicAsh @Override public ItemStack[] getBreakResult(final @NotNull World world, final @NotNull EnumDropCause dropCause, final int data, final @Nullable TileEntity tileEntity) { - return switch (dropCause) { - case PICK_BLOCK, SILK_TOUCH -> new ItemStack[] { new ItemStack(this) }; - default -> null; - }; + return new ItemStack[] { new ItemStack(this) }; } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBonepile.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBonePile.java similarity index 80% rename from game/core/src/main/java/net/minecraft/core/block/BlockLogicBonepile.java rename to game/core/src/main/java/net/minecraft/core/block/BlockLogicBonePile.java index 00bc1c4fc..84c3ebcb3 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBonepile.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBonePile.java @@ -10,10 +10,10 @@ import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class BlockLogicBonepile +public class BlockLogicBonePile extends BlockLogicFlower { - public BlockLogicBonepile(final @NotNull Block block) { + public BlockLogicBonePile(final @NotNull Block block) { super(block); final float f = 0.4F; this.setBlockBounds(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, 0.8F, 0.5F + f); @@ -31,13 +31,14 @@ public class BlockLogicBonepile @Override public @NotNull ItemStack @Nullable [] getBreakResult(final @NotNull World world, final @NotNull EnumDropCause dropCause, final int meta, final @Nullable TileEntity tileEntity) { - final int quantity = world.rand.nextInt(3) + 1; - return switch (dropCause) { case SILK_TOUCH, PICK_BLOCK -> new ItemStack[] { new ItemStack(this) }; default -> { - if (quantity == 0 || world.rand.nextInt(8) != 0) yield null; - yield new ItemStack[] { new ItemStack(Items.BONE, quantity) }; + int dropChance = 5; + if (world.rand.nextInt(dropChance) == 0) { + yield new ItemStack[] { new ItemStack(Items.BONE, 1) }; + } + yield null; } }; } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBoulderMagmatic.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBoulderMagmatic.java new file mode 100644 index 000000000..4c551034a --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBoulderMagmatic.java @@ -0,0 +1,43 @@ +package net.minecraft.core.block; + +import net.minecraft.core.block.entity.TileEntity; +import net.minecraft.core.entity.Entity; +import net.minecraft.core.enums.EnumDropCause; +import net.minecraft.core.item.ItemStack; +import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class BlockLogicBoulderMagmatic extends BlockLogicFlower { + public BlockLogicBoulderMagmatic(@NotNull Block block) { + super(block); + this.setBlockBounds(0.1F, 0.0F, 0.1F, 0.9F, 0.8F, 0.9F); + } + + @Override + public void onEntityCollision(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Entity entity) { + entity.maxFireTicks = 100; + entity.remainingFireTicks = 100; + entity.activeFireBlock = Blocks.FIRE; + } + + @Override + public boolean canStay(@NotNull World world, @NotNull TilePosc tilePos) { + return this.mayPlaceOn(world.getBlockType(tilePos.down(new TilePos()))); + } + + @Override + public boolean mayPlaceOn(@NotNull Block block) { + return block.isSolidRender(); + } + + @Override + public @NotNull ItemStack @Nullable [] getBreakResult(@NotNull World world, @NotNull EnumDropCause dropCause, int meta, @Nullable TileEntity tileEntity) { + return switch (dropCause) { + case SILK_TOUCH, PICK_BLOCK -> new ItemStack[]{new ItemStack(this)}; + default -> null; + }; + } +} diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBoulderSulfuric.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBoulderSulfuric.java new file mode 100644 index 000000000..5fcbe3029 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBoulderSulfuric.java @@ -0,0 +1,20 @@ +package net.minecraft.core.block; + +import net.minecraft.core.entity.Entity; +import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; + +public class BlockLogicBoulderSulfuric extends BlockLogicBoulderMagmatic { + public BlockLogicBoulderSulfuric(@NotNull Block block) { + super(block); + this.setBlockBounds(0.1F, 0.0F, 0.1F, 0.9F, 0.8F, 0.9F); + } + + @Override + public void onEntityCollision(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Entity entity) { + entity.maxFireTicks = 100; + entity.remainingFireTicks = 100; + entity.activeFireBlock = Blocks.FIRE_SULFURIC; + } +} diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBrimstone.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBrimstone.java new file mode 100644 index 000000000..d44d73ab5 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBrimstone.java @@ -0,0 +1,20 @@ +package net.minecraft.core.block; + +import net.minecraft.core.block.entity.TileEntity; +import net.minecraft.core.block.material.Material; +import net.minecraft.core.enums.EnumDropCause; +import net.minecraft.core.item.ItemStack; +import net.minecraft.core.world.World; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class BlockLogicBrimstone extends BlockLogic { + public BlockLogicBrimstone(@NotNull Block block, @NotNull Material material) { + super(block, material); + } + + @Override + public ItemStack @Nullable [] getBreakResult(@NotNull World world, @NotNull EnumDropCause dropCause, int data, @Nullable TileEntity tileEntity) { + return dropCause == EnumDropCause.PISTON_CRUSH ? new ItemStack[]{new ItemStack(Blocks.BRIMSAND, world.rand.nextInt(2) + 1)} : super.getBreakResult(world, dropCause, data, tileEntity); + } +} diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBrimthaw.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBrimthaw.java new file mode 100644 index 000000000..a8884933e --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBrimthaw.java @@ -0,0 +1,50 @@ +package net.minecraft.core.block; + +import net.minecraft.core.block.material.Material; +import net.minecraft.core.block.material.Materials; +import net.minecraft.core.entity.Entity; +import net.minecraft.core.entity.EntityItem; +import net.minecraft.core.util.helper.Direction; +import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; + +import java.util.Random; + +public class BlockLogicBrimthaw extends BlockLogicMagma { + + public BlockLogicBrimthaw(@NotNull Block block) { + super(block); + } + + @Override + public boolean canMelt(@NotNull World world, @NotNull TilePosc tilePos) { + boolean canMelt = false; + final TilePos queryPos = new TilePos(); + for (final Direction dir : Direction.all) { + final Block block = world.getBlockType(tilePos.add(dir, queryPos)); + final Material adjacentMaterial = block.getMaterial(); + if (adjacentMaterial == Materials.WATER) { + return false; + } + canMelt |= adjacentMaterial == Materials.ACID; + } + return canMelt; + } + + @Override + public void onEntityCollision(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Entity entity) { + if (entity instanceof EntityItem) return; // Don't burn items for this block + entity.fireHurt(Blocks.FIRE_SULFURIC); + } + + @Override + public void updateTick(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Random rand, boolean isRandomTick) { + if (canMelt(world, tilePos)) { + world.setBlockTypeNotify(tilePos, Blocks.FLUID_ACID_FLOWING); + } + } + +} + diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicEmber.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicEmber.java new file mode 100644 index 000000000..31c37986c --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicEmber.java @@ -0,0 +1,74 @@ +package net.minecraft.core.block; + +import net.minecraft.core.block.material.Material; +import net.minecraft.core.entity.Entity; +import net.minecraft.core.entity.animal.MobWolf; +import net.minecraft.core.entity.player.Player; +import net.minecraft.core.util.helper.DamageType; +import net.minecraft.core.util.phys.HitResult; +import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; + +import java.util.Random; + +public class BlockLogicEmber extends BlockLogic { + public BlockLogicEmber(@NotNull Block block, @NotNull Material material) { + super(block, material); + } + + @Override + public void onEntityCollision(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Entity entity) { + if(entity instanceof Player || entity instanceof MobWolf){ + this.ignite(world, tilePos, entity); + } + } + + @Override + public void onEntityWalkedOn(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Entity entity) { + if(entity instanceof Player || entity instanceof MobWolf){ // We do a little trolling here... + this.ignite(world, tilePos, entity); + } + } + + public void ignite(@NotNull World world, @NotNull TilePosc tilePos, Entity entity) { + if (entity != null) { + entity.hurt(null, 8, DamageType.BLAST); + entity.remainingFireTicks = 100; + entity.fling(1.0f, 1.0f, 1.0f, 0.0f); + } + + world.setBlockType(tilePos, Blocks.AIR); + world.createExplosion(null, tilePos.x(), tilePos.y(), tilePos.z(), 3.0F, true, false); + } + + @Override + public void animationTick(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Random rand) { + double xPos = (double) tilePos.x() + rand.nextDouble(); + double zPos = (double) tilePos.z() + rand.nextDouble(); + + TilePos blockAboveTilePos = new TilePos(tilePos.x(), tilePos.y() + 1, tilePos.z()); + + Block block = world.getBlockType(blockAboveTilePos); + double yPos = tilePos.y() + 1.1D; + + boolean isAir = block == Blocks.AIR; + boolean isAshLayer = block == Blocks.LAYER_ASH; + + if (isAshLayer) { + int data = world.getBlockData(blockAboveTilePos) & BlockLogicLayerBase.MASK_HEIGHT; + int layers = data + 1; + yPos += layers * 0.125D; + } + + if (isAir || isAshLayer) { + if (rand.nextInt(3) == 0) { + world.spawnParticle("flame", xPos, yPos, zPos, 0.0F, 0.01F, 0.0F, 0, false); + world.spawnParticle("largesmoke", xPos, yPos + 0.30, zPos, 0.0F, 0.02F, 0.0F, 0, false); + world.spawnParticle("largesmoke", xPos, yPos + 0.30, zPos, 0.0F, 0.01F, 0.0F, 0, false); + } + world.spawnParticle("largesmoke", xPos, yPos + 0.30, zPos, 0.0F, 0.015F, 0.0F, 0, false); + } + } +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFire.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFire.java index 593ab4942..9372320e5 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFire.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFire.java @@ -6,6 +6,10 @@ import net.minecraft.core.block.support.ISupport; import net.minecraft.core.block.support.PartialSupport; import net.minecraft.core.block.tag.BlockTags; import net.minecraft.core.data.gamerule.GameRules; +import net.minecraft.core.data.registry.Registries; +import net.minecraft.core.data.tag.Tag; +import net.minecraft.core.entity.Entity; +import net.minecraft.core.item.block.ItemBlock; import net.minecraft.core.sound.SoundCategory; import net.minecraft.core.util.helper.Side; import net.minecraft.core.enums.EnumDropCause; @@ -122,7 +126,15 @@ public class BlockLogicFire } public void setBurnResult(final @NotNull World world, final @NotNull TilePosc tilePos) { - world.setBlockTypeNotify(tilePos, this.getBurnResult(world, tilePos)); + final Block currentBlock = world.getBlockType(tilePos); + final int currentData = world.getBlockData(tilePos); + final Block resultBlock = this.getBurnResult(world, tilePos); + + if (resultBlock != Blocks.AIR && resultBlock != this.block) { + world.setBlockTypeDataNotify(tilePos, resultBlock, currentData); + } else { + world.setBlockTypeNotify(tilePos, resultBlock); + } } @Override @@ -130,7 +142,7 @@ public class BlockLogicFire TilePos queryPos = new TilePos(); final @Nullable Block blockUnder = world.getBlockType(tilePos.down(queryPos)); - final boolean infiniBurn = blockUnder != null && blockUnder.hasTag(BlockTags.INFINITE_BURN); + final boolean infiniBurn = blockUnder.hasTag(this.getInfiniteBurnTag()); // Extinguish fire if (!this.isValidFireLocation(world, tilePos)) { @@ -203,8 +215,7 @@ public class BlockLogicFire if (world.getGameRuleValue(GameRules.DO_FIRE_SPREAD) && this.getBurnResult(world, localPos) == Blocks.AIR /* Fix for fire destroying moss blocks */) { //Spread Fire with higher meta - world.setBlockTypeDataNotify(localPos, this.block, Math.min(meta + rand.nextInt(5) / 4, 15)); - } + world.setBlockTypeDataNotify(localPos, this.getSpreadFireBlock(), Math.min(meta + rand.nextInt(5) / 4, 15));} } } } @@ -218,8 +229,7 @@ public class BlockLogicFire if (random.nextInt(meta + 10) < 5 && !world.isBlockBeingRainedOn(tilePos)) { if (this.getBurnResult(world, tilePos) == Blocks.AIR /* Fix for fire destroying moss blocks */) { //Spread Fire with higher meta - world.setBlockTypeDataNotify(tilePos, this.block, Math.min(meta + random.nextInt(5) / 4, 15)); - } + world.setBlockTypeDataNotify(tilePos, this.getSpreadFireBlock(), Math.min(meta + random.nextInt(5) / 4, 15));} } else { this.setBurnResult(world, tilePos); } @@ -281,12 +291,15 @@ public class BlockLogicFire @Override public void onNeighborChanged(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Block block) { if (!world.isBlockNormalCube(tilePos.down(new TilePos())) && !this.canNeighborCatchFire(world, tilePos)) { - - world.setBlockTypeNotify(tilePos, this.getBurnResult(world, tilePos)); + this.setBurnResult(world, tilePos); } } protected @NotNull Block getBurnResult(final @NotNull World world, final @NotNull TilePosc tilePos) { + Block blockAtPos = world.getBlockType(tilePos); + int blockDataAtPos = world.getBlockData(tilePos); + if (blockAtPos.getLogic() instanceof BlockLogicLog) return Blocks.LOG_SCORCHED; + final @NotNull Block block = world.getBlockType(tilePos); final @Nullable Block noMossBlock = BlockLogicMoss.getNoMossBlock(block); return Objects.requireNonNullElse(noMossBlock, Blocks.AIR); @@ -299,7 +312,7 @@ public class BlockLogicFire return; } if (!world.isBlockNormalCube(tilePos.down(queryPos)) && !this.canNeighborCatchFire(world, tilePos)) { - world.setBlockTypeNotify(tilePos, this.getBurnResult(world, tilePos)); + this.setBurnResult(world, tilePos); } else { world.scheduleBlockUpdate(tilePos, this.block, this.tickDelay()); } @@ -364,4 +377,17 @@ public class BlockLogicFire } } } + + protected Tag> getInfiniteBurnTag() { + return BlockTags.INFINITE_BURN; + } + + protected Block getSpreadFireBlock() { + return this.block; + } + + @Override + public void onEntityCollision(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Entity entity) { + entity.activeFireBlock = this.block; + } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFireCold.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFireCold.java index 3b48a1e51..6a8b7b25c 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFireCold.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFireCold.java @@ -1,59 +1,22 @@ package net.minecraft.core.block; import net.minecraft.core.block.tag.BlockTags; -import net.minecraft.core.world.World; -import net.minecraft.core.world.pos.TilePos; -import net.minecraft.core.world.pos.TilePosc; -import net.minecraft.core.world.weather.IPrecipitation; +import net.minecraft.core.data.tag.Tag; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import java.util.Random; +public class BlockLogicFireCold extends BlockLogicFire { -public class BlockLogicFireCold - extends BlockLogicFire { public BlockLogicFireCold(final @NotNull Block block) { super(block); } @Override - public void updateTick(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Random rand, final boolean isRandomTick) { - TilePos queryPos = new TilePos(); - final @Nullable Block blockUnder = world.getBlockType(tilePos.down(queryPos)); - final boolean infiniBurn = blockUnder != null && blockUnder.hasTag(BlockTags.INFINITE_BURN_COLD); - - // Extinguish fire - if (!this.isValidFireLocation(world, tilePos)) { - this.setBurnResult(world, tilePos); - } - - // Extinguish fire (Rain / Snow) - if (!infiniBurn && world.getCurrentWeather() != null && world.getCurrentWeather() instanceof IPrecipitation && ( - world.isBlockBeingRainedOn(tilePos) - || world.isBlockBeingRainedOn(tilePos.west(queryPos)) - || world.isBlockBeingRainedOn(tilePos.east(queryPos)) - || world.isBlockBeingRainedOn(tilePos.north(queryPos)) - || world.isBlockBeingRainedOn(tilePos.south(queryPos)))) { - this.setBurnResult(world, tilePos); - return; - } - - final int meta = world.getBlockData(tilePos); - if (meta < 15) { - world.setBlockData(tilePos, meta + rand.nextInt(3) / 2); - } - world.scheduleBlockUpdate(tilePos, this.block, this.tickDelay()); - - - if (!infiniBurn && !this.canNeighborCatchFire(world, tilePos)) { - if (!world.isBlockNormalCube(tilePos.down(queryPos)) || meta > 3) { - this.setBurnResult(world, tilePos); - } - return; - } + protected Tag> getInfiniteBurnTag() { + return BlockTags.INFINITE_BURN_COLD; + } - if (!infiniBurn && !canBurn(world, tilePos.down(queryPos)) && meta == 15 && rand.nextInt(4) == 0) { - this.setBurnResult(world, tilePos); - } + @Override + protected Block getSpreadFireBlock() { + return Blocks.FIRE; } -} +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFireSulfuric.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFireSulfuric.java new file mode 100644 index 000000000..3e8eeb4c3 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFireSulfuric.java @@ -0,0 +1,25 @@ +package net.minecraft.core.block; + +import net.minecraft.core.block.tag.BlockTags; +import net.minecraft.core.data.tag.Tag; +import net.minecraft.core.entity.Entity; +import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; + +public class BlockLogicFireSulfuric extends BlockLogicFire { + + public BlockLogicFireSulfuric(final @NotNull Block block) { + super(block); + } + + @Override + protected Tag> getInfiniteBurnTag() { + return BlockTags.INFINITE_BURN_SULFURIC; + } + + @Override + protected Block getSpreadFireBlock() { + return Blocks.FIRE_SULFURIC; + } +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlowstone.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlowstone.java deleted file mode 100644 index 860092d4b..000000000 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlowstone.java +++ /dev/null @@ -1,143 +0,0 @@ -package net.minecraft.core.block; - -import net.minecraft.core.block.material.Materials; -import net.minecraft.core.block.tag.BlockTags; -import net.minecraft.core.entity.EntityFallingBlock; -import net.minecraft.core.entity.player.Player; -import net.minecraft.core.item.ItemStack; -import net.minecraft.core.util.helper.Side; -import net.minecraft.core.world.World; -import net.minecraft.core.world.WorldSource; -import net.minecraft.core.world.pos.TilePos; -import net.minecraft.core.world.pos.TilePosc; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.joml.primitives.AABBd; -import org.joml.primitives.AABBdc; - -import java.util.Random; - -public class BlockLogicFlowstone extends BlockLogic { - public BlockLogicFlowstone(final @NotNull Block block) { - super(block, Materials.STONE); - } - - @Override - public int getPlacedData(final @Nullable Player player, final @NotNull ItemStack itemStack, final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side, final double xHit, final double yHit) { - return itemStack.getMetadata(); - } - - @Override - public @NotNull AABBdc getBoundsFromState(final @NotNull WorldSource source, final @NotNull TilePosc tilePos) { - final int data = source.getBlockData(tilePos); - - if (data == 0 || data > 3) { - return new AABBd(0.0, 0.0, 0.0, 1.0, 1.0, 1.0); - } else { - final double offset = 2.0 * data; - return new AABBd(offset / 16.0, 0.0, offset / 16.0, (16.0 - offset) / 16.0, 1.0, (16.0 - offset) / 16.0); - } - } - - @Override - public boolean isSolidRender() { - return false; - } - - @Override - public boolean isCubeShaped() { - return false; - } - - @Override - public void onPlacedByWorld(final @NotNull World world, final @NotNull TilePosc tilePos) { - world.scheduleBlockUpdate(tilePos, this.block, this.tickDelay()); - } - - @Override - public void onNeighborChanged(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Block block) { - world.scheduleBlockUpdate(tilePos, this.block, this.tickDelay()); - } - - @Override - public void updateTick(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Random rand, final boolean isRandomTick) { - this.tryToFall(world, tilePos); - } - - private void tryToFall(final @NotNull World world, final @NotNull TilePosc tilePos) { - boolean topCanFall = false; - boolean bottomCanFall = false; - int y1 = -1; - int y0 = -1; - - final @NotNull TilePos queryPos = new TilePos(); - - // Check if top block of stack is unsupported - for (int y = tilePos.y(); y < world.getHeightBlocks(); y++) { - queryPos.set(tilePos.x(), y + 1, tilePos.z()); - if (canFall(world, queryPos)) { - topCanFall = true; - y1 = y; - break; - } else if (world.getBlockType(queryPos).getLogic() != this) { - return; - } - } - - if (!topCanFall) { - return; - } - - // Check if bottom block of stack is unsupported - for (int y = tilePos.y(); y > 0; y--) { - queryPos.set(tilePos.x(), y - 1, tilePos.z()); - if (canFall(world, queryPos)) { - bottomCanFall = true; - y0 = y; - break; - } else if (world.getBlockType(queryPos).getLogic() != this) { - return; - } - } - - if (!bottomCanFall) { - return; - } - - // Make stack fall - for (int y = y0; y <= y1; y++) { - queryPos.set(tilePos.x(), y, tilePos.z()); - final int data = world.getBlockData(queryPos); - final @NotNull EntityFallingBlock entity = new EntityFallingBlock(world, tilePos.x() + 0.5F, y + 0.5F, tilePos.z() + 0.5F, this.block.id(), data, null); - world.entityJoinedWorld(entity); - } - } - - @Override - public int tickDelay() { - return 3; - } - - @Override - public void animationTick(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Random rand) { - final int data = world.getBlockData(tilePos); - - if (world.getBlockType(tilePos.down(new TilePos())) == Blocks.AIR && rand.nextInt(20) == 0) { - final double scale = 1.0 - (2.0 / 16.0) * data; - final double cx = (tilePos.x() + 0.5) - scale / 2.0; - final double cz = (tilePos.z() + 0.5) - scale / 2.0; - final double dx = rand.nextDouble(); - final double dz = rand.nextDouble(); - - world.spawnParticle("dripWater", cx + scale * dx, tilePos.y() - 0.05f, cz + scale * dz, 0.0, 0.0, 0.0, 0, false); - } - } - - private static boolean canFall(final @NotNull World world, final @NotNull TilePosc tilePos) { - final @NotNull Block block = world.getBlockType(tilePos); - if (block == Blocks.FLOWSTONE) { - return false; - } - return block.hasTag(BlockTags.PLACE_OVERWRITES); - } -} diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java index 89f9f5c6c..01e71607e 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java @@ -263,4 +263,19 @@ public abstract class BlockLogicFluid extends BlockLogic { public boolean isFullBlock(@NotNull World world, TilePos tilePos){ return getFluidHeight(world, tilePos) == 1; } + + public static boolean isAcid(@NotNull World world, TilePos pos) { + Block block = world.getBlockType(pos); + return block == Blocks.FLUID_ACID_STILL || block == Blocks.FLUID_ACID_FLOWING; + } + + public static boolean isWater(@NotNull World world, TilePos pos) { + Block block = world.getBlockType(pos); + return block == Blocks.FLUID_WATER_STILL || block == Blocks.FLUID_WATER_FLOWING; + } + + public static boolean isLava(@NotNull World world, TilePos pos) { + Block block = world.getBlockType(pos); + return block == Blocks.FLUID_LAVA_STILL || block == Blocks.FLUID_LAVA_FLOWING; + } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicGrowthRubyglass.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicGrowthRubyglass.java new file mode 100644 index 000000000..1c9369df2 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicGrowthRubyglass.java @@ -0,0 +1,226 @@ +package net.minecraft.core.block; + +import net.minecraft.core.block.entity.TileEntity; +import net.minecraft.core.block.material.Material; +import net.minecraft.core.enums.EnumDropCause; +import net.minecraft.core.item.ItemStack; +import net.minecraft.core.util.helper.Direction; +import net.minecraft.core.util.helper.Side; +import net.minecraft.core.world.LevelListener; +import net.minecraft.core.world.World; +import net.minecraft.core.world.WorldSource; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.joml.primitives.AABBd; +import org.joml.primitives.AABBdc; + +public class BlockLogicGrowthRubyglass extends BlockLogic { + + public static final int DIRECTION_MASK = 0b0000_0111; + public static final int SHAPE_MASK = 0b0001_1000; + + public static final int STATE_BUD = 0b0000_0000; + public static final int STATE_BOTTOM = 0b0000_1000; + public static final int STATE_TOP = 0b0001_0000; + + public BlockLogicGrowthRubyglass(final @NotNull Block block, final @NotNull Material material) { + super(block, material); + } + + @Override + public @Nullable AABBdc getCollisionAABB(final @NotNull WorldSource source, final @NotNull TilePosc tilePos) { + int data = source.getBlockData(tilePos); + int shape = data & SHAPE_MASK; + if(shape == STATE_BUD) return null; + else return super.getCollisionAABB(source, tilePos); + } + + @Override + public boolean isSolidRender() { + return false; + } + + @Override + public boolean isCubeShaped() { + return false; + } + + @Override + public void onNeighborChanged(final @NotNull World world, final @NotNull TilePosc pos, final @NotNull Block neighborBlock) { + int data = world.getBlockData(pos); + int shape = data & SHAPE_MASK; + Direction dir = Direction.fromId(data & DIRECTION_MASK); + + if (!this.canStay(world, pos)) { + this.dropWithCause(world, EnumDropCause.IMPROPER_TOOL, pos, data, null, null); + world.playBlockEvent(pos, LevelListener.EVENT_BLOCK_BREAK, id()); + world.setBlockTypeNotify(pos, Blocks.AIR); + return; + } + + if (shape == STATE_BOTTOM) { + TilePos topPos = pos.add(dir, new TilePos()); + int topMeta = world.getBlockData(topPos); + if (world.getBlockType(topPos) != this.block || (topMeta & SHAPE_MASK) != STATE_TOP) { + world.setBlockTypeDataNotify(pos, this.block, STATE_BUD | dir.id); + } + } + } + + @Override + public boolean canPlaceOnSide(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side) { + TilePos anchorPos = tilePos.add(side.direction().opposite(), new TilePos()); + Block anchorBlock = world.getBlockType(anchorPos); + + if (anchorBlock == this.block) { + int anchorMeta = world.getBlockData(anchorPos); + int anchorShape = anchorMeta & SHAPE_MASK; + + if (anchorShape == STATE_BUD) { + Direction budDir = Direction.fromId(anchorMeta & DIRECTION_MASK); + + if (budDir == side.direction()) return true; + + if (world.getBlockType(tilePos) == Blocks.AIR) { + TilePos growthPos = anchorPos.add(budDir, new TilePos()); + return world.getBlockType(growthPos) == Blocks.AIR; + } + return false; + } + } + + return world.isBlockNormalCube(anchorPos); + } + + @Override + public boolean canPlaceAt(final @NotNull World world, final @NotNull TilePosc tilePos) { + if (!super.canPlaceAt(world, tilePos)) return false; + + for (Side side : Side.values()) { + TilePos anchorPos = tilePos.add(side.direction().opposite(), new TilePos()); + + if (world.isBlockNormalCube(anchorPos)) return true; + + if (world.getBlockType(anchorPos) == this.block) { + int meta = world.getBlockData(anchorPos); + int shape = meta & SHAPE_MASK; + Direction dir = Direction.fromId(meta & DIRECTION_MASK); + + if (shape == STATE_BUD) { + if (dir == side.direction()) return true; + + if (world.getBlockType(tilePos) == Blocks.AIR) { + TilePos growthPos = anchorPos.add(dir, new TilePos()); + if (world.getBlockType(growthPos) == Blocks.AIR) { + return true; + } + } + } + } + } + return false; + } + + @Override + public void onPlacedOnSide(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Side side, double xHit, double yHit) { + TilePos clickedAnchor = tilePos.add(side.direction().opposite(), new TilePos()); + + if (world.getBlockType(clickedAnchor) == this.block) { + int data = world.getBlockData(clickedAnchor); + if ((data & SHAPE_MASK) == STATE_BUD) { + Direction budDir = Direction.fromId(data & DIRECTION_MASK); + TilePos growthPos = clickedAnchor.add(budDir, new TilePos()); + + if (!tilePos.equals(growthPos) && world.getBlockType(growthPos) == Blocks.AIR) { + world.setBlockTypeNotify(tilePos, Blocks.AIR); + world.setBlockData(clickedAnchor, STATE_BOTTOM | (data & DIRECTION_MASK)); + world.markBlockNeedsUpdate(clickedAnchor); + world.setBlockTypeDataNotify(growthPos, this.block, STATE_TOP | (data & DIRECTION_MASK)); + return; + } + else if (tilePos.equals(growthPos)) { + world.setBlockData(clickedAnchor, STATE_BOTTOM | (data & DIRECTION_MASK)); + world.markBlockNeedsUpdate(clickedAnchor); + world.setBlockTypeDataNotify(tilePos, this.block, STATE_TOP | (data & DIRECTION_MASK)); + return; + } + } + } + + if (world.isBlockNormalCube(clickedAnchor)) { + world.setBlockTypeDataNotify(tilePos, this.block, STATE_BUD | side.direction().id); + return; + } + + for (Side fallback : Side.values()) { + TilePos fallbackAnchor = tilePos.add(fallback.direction.opposite(), new TilePos()); + if (world.isBlockNormalCube(fallbackAnchor)) { + world.setBlockTypeDataNotify(tilePos, this.block, STATE_BUD | fallback.direction.id); + return; + } + } + } + + @Override + public boolean canStay(final @NotNull World world, final @NotNull TilePosc tilePos) { + int data = world.getBlockData(tilePos); + int shape = data & SHAPE_MASK; + Direction dir = Direction.fromId(data & DIRECTION_MASK); + + if (shape == STATE_TOP) { + TilePos bottomPos = tilePos.add(dir.opposite(), new TilePos()); + return world.getBlockType(bottomPos) == this.block && + (world.getBlockData(bottomPos) & SHAPE_MASK) == STATE_BOTTOM; + } else { + TilePos anchorPos = tilePos.add(dir.opposite(), new TilePos()); + return world.isBlockNormalCube(anchorPos); + } + } + + @Override + public @NotNull AABBdc getBoundsFromState(final @NotNull WorldSource source, final @NotNull TilePosc tilePos) { + int data = source.getBlockData(tilePos); + int shape = data & SHAPE_MASK; + Direction dir = Direction.fromId(data & DIRECTION_MASK); + + double height; + double min = 5.0 / 16.0; + double max = 11.0 / 16.0; + if (shape == STATE_TOP) { + height = 11.0 / 16.0; + } else if (shape == STATE_BOTTOM) { + min = 3.0 / 16.0; + max = 13.0 / 16.0; + height = 1.0; + } else { + height = 12.0 / 16.0; + } + + return switch (dir) { + case UP -> new AABBd(min, 0.0, min, max, height, max); // +Y + case DOWN -> new AABBd(min, 1.0 - height, min, max, 1.0, max); // -Y + case SOUTH -> new AABBd(min, min, 0.0, max, max, height); // +Z + case NORTH -> new AABBd(min, min, 1.0 - height, max, max, 1.0); // -Z + case EAST -> new AABBd(0.0, min, min, height, max, max); // +X + case WEST -> new AABBd(1.0 - height, min, min, 1.0, max, max); // -X + default -> new AABBd(min, 0.0, min, max, height, max); + }; + } + + @Override + public ItemStack @Nullable [] getBreakResult(@NotNull World world, @NotNull EnumDropCause dropCause, int data, @Nullable TileEntity tileEntity) { + if (dropCause != EnumDropCause.SILK_TOUCH) { + return null; + } + + int shape = data & SHAPE_MASK; + + if (shape == STATE_BOTTOM) { + return new ItemStack[] { new ItemStack(this.block, 2) }; + } + + return new ItemStack[] { new ItemStack(this.block, 1) }; + } +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerAsh.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerAsh.java index 64492b0b8..013332665 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerAsh.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerAsh.java @@ -2,6 +2,9 @@ package net.minecraft.core.block; import net.minecraft.core.block.entity.TileEntity; import net.minecraft.core.block.material.Material; +import net.minecraft.core.entity.Entity; +import net.minecraft.core.entity.animal.MobWolf; +import net.minecraft.core.entity.player.Player; import net.minecraft.core.enums.EnumDropCause; import net.minecraft.core.item.ItemStack; import net.minecraft.core.util.helper.Direction; @@ -14,13 +17,27 @@ import org.jetbrains.annotations.Nullable; public class BlockLogicLayerAsh extends BlockLogicLayerBase { - public BlockLogicLayerAsh(Block block, Block fullBlock, Material material) + public BlockLogicLayerAsh(Block block, Block fullBlock, Material material) { super(block, fullBlock, material); setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F); block.setTicking(true); } + @Override + public void onEntityWalkedOn(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Entity entity) { + TilePos emberPos = tilePos.down(new TilePos()); + + if (world.getBlockId(emberPos.x(), emberPos.y(), emberPos.z()) == Blocks.EMBER.id()) { + BlockLogic logic = Blocks.EMBER.getLogic(); + if (logic instanceof BlockLogicEmber) { + if(entity instanceof Player || entity instanceof MobWolf) { + ((BlockLogicEmber) logic).ignite(world, emberPos, entity); + } + } + } + } + public void accumulate(@NotNull World world, @NotNull TilePosc tilePos) { int myMetadata = world.getBlockData(tilePos); if (myMetadata == 0x7) return; @@ -35,20 +52,19 @@ public class BlockLogicLayerAsh extends BlockLogicLayerBase } @Override - public boolean canPlaceAt(@NotNull World world, @NotNull TilePosc tilePos) { + public boolean canPlaceAt(@NotNull World world, @NotNull TilePosc tilePos) { TilePos down = tilePos.down(new TilePos()); Block b = world.getBlockType(down); - if(b == null || !b.isSolidRender()) { - return false; + if(!b.isSolidRender()) { + return false; } else { - Material material = world.getBlockMaterial(down); + Material material = world.getBlockMaterial(down); return material.blocksMotion(); } } @Override public void onNeighborChanged(@NotNull World world, @NotNull TilePosc tilePos, final @NotNull Block block) { - // Remove if no longer valid if (!canPlaceAt(world, tilePos)) { dropWithCause(world, EnumDropCause.WORLD, tilePos, world.getBlockData(tilePos), null, null); world.setBlockTypeNotify(tilePos, Blocks.AIR); @@ -58,9 +74,8 @@ public class BlockLogicLayerAsh extends BlockLogicLayerBase @Override public @NotNull ItemStack @Nullable [] getBreakResult(@NotNull World world, @NotNull EnumDropCause dropCause, int data, @Nullable TileEntity tileEntity) { return switch (dropCause) { - case SILK_TOUCH -> new ItemStack[]{new ItemStack(this, data + 1)}; - case PICK_BLOCK -> new ItemStack[]{new ItemStack(this)}; + case SILK_TOUCH, PICK_BLOCK -> new ItemStack[]{new ItemStack(this)}; default -> null; }; } -} +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLog.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLog.java index 495b14a2e..a0639d527 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLog.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLog.java @@ -22,7 +22,7 @@ public class BlockLogicLog extends BlockLogicAxisAligned { for (queryPos.y = tilePos.x() - r; queryPos.y <= tilePos.y() + r; queryPos.y++) { for (queryPos.z = -tilePos.x() - r; queryPos.z <= tilePos.z() + r; queryPos.z++) { Block block = world.getBlockType(queryPos); - if (!(block != null && block.getLogic() instanceof BlockLogicLeavesBase)) { + if (!(block.getLogic() instanceof BlockLogicLeavesBase)) { continue; } int leavesMeta = world.getBlockData(queryPos); diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMagma.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMagma.java index 448ef8f85..4083ba26a 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMagma.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMagma.java @@ -54,7 +54,7 @@ public class BlockLogicMagma extends BlockLogic { TilePos queryPos = new TilePos(); for (final var dir : Direction.all) { Block block = world.getBlockType(tilePos.add(dir, queryPos)); - Material adjacentMaterial = block == null ? Materials.AIR : block.getMaterial(); + Material adjacentMaterial = block.getMaterial(); if (adjacentMaterial == Materials.WATER) { return false; } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicOreRubyglass.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicNodeRubyglass.java similarity index 84% rename from game/core/src/main/java/net/minecraft/core/block/BlockLogicOreRubyglass.java rename to game/core/src/main/java/net/minecraft/core/block/BlockLogicNodeRubyglass.java index 8a32ca537..52c12fe06 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicOreRubyglass.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicNodeRubyglass.java @@ -9,11 +9,11 @@ import net.minecraft.core.world.World; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class BlockLogicOreRubyglass extends BlockLogicRubyglass +public class BlockLogicNodeRubyglass extends BlockLogicRubyglass { public static Int2IntArrayMap variantMap = new Int2IntArrayMap(); - public BlockLogicOreRubyglass(@NotNull Block block){ + public BlockLogicNodeRubyglass(@NotNull Block block){ super(block); variantMap.put(Blocks.RUBYGLASS_COLUMN.id(), block.id()); } @@ -22,7 +22,7 @@ public class BlockLogicOreRubyglass extends BlockLogicRubyglass public ItemStack[] getBreakResult(@NotNull World world, @NotNull EnumDropCause dropCause, int data, @Nullable TileEntity tileEntity) { return switch (dropCause) { case SILK_TOUCH, PICK_BLOCK -> new ItemStack[]{new ItemStack(this)}; - case EXPLOSION, PROPER_TOOL, PISTON_CRUSH -> new ItemStack[]{new ItemStack(Items.RUBYGLASS_CRYSTAL)}; + case EXPLOSION, PROPER_TOOL, PISTON_CRUSH -> new ItemStack[]{new ItemStack(Items.RUBYGLASS)}; default -> null; }; } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicOreRedstone.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicOreRedstone.java index 28070ac04..782117b85 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicOreRedstone.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicOreRedstone.java @@ -6,10 +6,14 @@ import net.minecraft.core.block.entity.TileEntityActivator; import net.minecraft.core.entity.Entity; import net.minecraft.core.entity.player.Player; import net.minecraft.core.enums.EnumDropCause; +import net.minecraft.core.item.Item; import net.minecraft.core.item.Items; import net.minecraft.core.item.ItemStack; +import net.minecraft.core.item.block.ItemBlock; +import net.minecraft.core.sound.SoundCategory; import net.minecraft.core.util.helper.Direction; import net.minecraft.core.util.helper.Side; +import net.minecraft.core.world.LevelListener; import net.minecraft.core.world.World; import net.minecraft.core.block.material.Material; import net.minecraft.core.world.WorldSource; @@ -48,6 +52,20 @@ public class BlockLogicOreRedstone extends BlockLogic { @Override public boolean onInteracted(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Player player, @Nullable Side side, double xHit, double yHit) { + + if(player.getHeldItem() == null || !(player.getHeldItem().getItem() instanceof ItemBlock)){ + if(block == Blocks.ORE_REDSTONE_PERMAFROST || block == Blocks.ORE_REDSTONE_GLOWING_PERMAFROST){ + player.swingItem(); + world.playSoundEffectAtTile(player, SoundCategory.WORLD_SOUNDS, tilePos, "step.permafrost", 1F, 0.8F + world.rand.nextFloat() * 0.1F); + } else { + player.swingItem(); + world.playSoundEffectAtTile(player, SoundCategory.WORLD_SOUNDS, tilePos, "step.stone", 1F, 0.8F + world.rand.nextFloat() * 0.1F); + } + world.playSoundEffectAtTile(player, SoundCategory.WORLD_SOUNDS, tilePos, "random.fizz", 0.1F, 2F); + world.playSoundEffectAtTile(player, SoundCategory.WORLD_SOUNDS, tilePos, "random.fizz", 0.1F, 1.4F); + } + + lightRedstone(world, tilePos); return false; } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassCrop.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassCrop.java deleted file mode 100644 index 31ef59f76..000000000 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassCrop.java +++ /dev/null @@ -1,156 +0,0 @@ -package net.minecraft.core.block; - -import net.minecraft.core.block.entity.TileEntity; -import net.minecraft.core.block.material.Materials; -import net.minecraft.core.block.tag.BlockTags; -import net.minecraft.core.enums.EnumDropCause; -import net.minecraft.core.item.ItemStack; -import net.minecraft.core.item.Items; -import net.minecraft.core.world.World; -import net.minecraft.core.world.WorldSource; -import net.minecraft.core.world.pos.TilePos; -import net.minecraft.core.world.pos.TilePosc; -import net.minecraft.core.world.type.tag.WorldTypeTags; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.joml.primitives.AABBd; - -import java.util.Random; - -public class BlockLogicRubyglassCrop extends BlockLogic { - public BlockLogicRubyglassCrop(Block block) { - super(block, Materials.PLANT); - block.setTicking(true); - } - - public static final int MASK_GROWTH_STAGE = 0b0000_0011; - - public static final int MAX_GROWTH_STATE = 3; - - @Override - public boolean isSolidRender() { - return false; - } - - @Override - public boolean isCubeShaped() { - return false; - } - - @Override - public @Nullable AABBd getCollisionAABB(final @NotNull WorldSource source, final @NotNull TilePosc tilePos) { - return null; - } - - public boolean mayPlaceOnBlockAt(final @NotNull World world, final @NotNull TilePosc tilePos) { - return world.getBlockType(tilePos) == Blocks.COBBLE_NETHERRACK || world.getBlockType(tilePos) == Blocks.COBBLE_NETHERRACK_CRYSTALLINE; - } - - @Override - public boolean canPlaceAt(final @NotNull World world, final @NotNull TilePosc tilePos) { - final @NotNull TilePos temp = new TilePos(); - return mayPlaceOnBlockAt(world, tilePos.down(temp)); - } - - @Override - public boolean canStay(final @NotNull World world, final @NotNull TilePosc tilePos) { - final @NotNull TilePos temp = new TilePos(); - return mayPlaceOnBlockAt(world, tilePos.down(temp)); - } - - public boolean isValidGrowthConditions(final @NotNull World world, final @NotNull TilePosc tilePos) { - TilePos cursor = new TilePos(tilePos.x(), tilePos.y() + 1, tilePos.z()); - TilePos waterCursor = new TilePos(tilePos.x(), tilePos.y() + 2, tilePos.z()); - - boolean isAir = world.isAirBlock(cursor); - - for (int iy = 1; iy < 8 && iy < world.getWorldType().getMaxY(world)-1; iy++){ - cursor.set(cursor.x, ++cursor.y, cursor.z); - waterCursor.set(waterCursor.x, ++waterCursor.y, waterCursor.z); - - boolean solidBlockFound = world.isBlockNormalCube(cursor); - - if(isAir){ - if(solidBlockFound) { - return world.getBlockType(waterCursor).hasTag(BlockTags.IS_WATER); - } else { - isAir = world.isAirBlock(cursor); - } - } else { - return false; - } - } - return false; - } - - @Override - public void onNeighborChanged(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Block block) { - if(!canStay(world, tilePos)) - { - world.setBlockTypeNotify(tilePos, Blocks.AIR); - } - } - - @Override - public void updateTick(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Random rand, final boolean isRandomTick) { - super.updateTick(world, tilePos, rand, isRandomTick); - if (isValidGrowthConditions(world, tilePos)) { - - TilePos blockBelow = new TilePos(); - tilePos.down(blockBelow); - - if(world.getBlockType(blockBelow) == Blocks.COBBLE_NETHERRACK){ - world.setBlockTypeNotify(blockBelow, Blocks.COBBLE_NETHERRACK_CRYSTALLINE); - } - - final int stage = metaToGrowthStage(world.getBlockData(tilePos)); - - if (stage < MAX_GROWTH_STATE) { - float growthRate = getGrowthRate(world, tilePos); - if(growthRate > 0.0F) { - if (rand.nextInt((int) (100 / growthRate)) == 0) { - world.setBlockDataNotify(tilePos, stage + 1); - } - } - } - } - } - - private float getGrowthRate (final @NotNull World world, final @NotNull TilePosc tilePos) { - float growthRate = 0F; - if(world.getWorldType().hasTag(WorldTypeTags.HOT)) { - growthRate = 5F; - } - else if(isLavaNearby(world, tilePos)) { - growthRate = 3.5F; - } - return growthRate; - } - - public boolean isLavaNearby(@NotNull World world, @NotNull TilePosc tilePos) { - TilePos cursor = new TilePos(); - TilePos queryPos = new TilePos(); - tilePos.down(cursor); - return - world.getBlockType(cursor.east(queryPos)).hasTag(BlockTags.IS_LAVA) || - world.getBlockType(cursor.west(queryPos)).hasTag(BlockTags.IS_LAVA) || - world.getBlockType(cursor.down(queryPos)).hasTag(BlockTags.IS_LAVA) || - world.getBlockType(cursor.south(queryPos)).hasTag(BlockTags.IS_LAVA) || - world.getBlockType(cursor.north(queryPos)).hasTag(BlockTags.IS_LAVA); - } - -// @Override -// public @NotNull ItemStack @Nullable [] getBreakResult(final @NotNull World world, final @NotNull EnumDropCause dropCause, final int data, final @Nullable TileEntity tileEntity) { -// if (data != MAX_GROWTH_STATE) { -// return new ItemStack[] { new ItemStack(Items.RUBYGLASS_DUST) }; -// } else { -// return new ItemStack[] { new ItemStack(Items.RUBYGLASS_CRYSTAL) }; -// } -// } - - - public static int metaToGrowthStage(int meta) { - return meta & MASK_GROWTH_STAGE; - } - -} diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassCrystal.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassCrystal.java new file mode 100644 index 000000000..7499cab16 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassCrystal.java @@ -0,0 +1,74 @@ +package net.minecraft.core.block; + +import net.minecraft.core.block.entity.TileEntity; +import net.minecraft.core.block.material.Materials; +import net.minecraft.core.entity.Entity; +import net.minecraft.core.enums.EnumDropCause; +import net.minecraft.core.item.ItemStack; +import net.minecraft.core.util.helper.Direction; +import net.minecraft.core.world.Dimension; +import net.minecraft.core.world.World; +import net.minecraft.core.world.WorldSource; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Random; + +public class BlockLogicRubyglassCrystal extends BlockLogicTransparent { + public BlockLogicRubyglassCrystal(@NotNull Block block) { + super(block, Materials.ICE); + block.friction = 0.98F; + } + + @Override + public ItemStack[] getBreakResult(@NotNull World world, @NotNull EnumDropCause dropCause, int data, @Nullable TileEntity tileEntity) { + return switch (dropCause) { + case PICK_BLOCK, SILK_TOUCH -> new ItemStack[]{new ItemStack(this)}; + default -> null; + }; + } + + @Override + public void onEntityCollision(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Entity entity) { + if (world.isClientSide) return; + + int data = world.getBlockData(tilePos); + int nextData = data + 1; + + if (nextData >= 3) { + world.setBlockType(tilePos, Blocks.AIR); + } else { + world.setBlockDataNotify(tilePos, nextData); + } + } + + @Override + public void onEntityWalkedOn(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Entity entity) { + this.onEntityCollision(world, tilePos, entity); + } + + @Override + public float getAmbientOcclusionStrength(@NotNull WorldSource source, @NotNull TilePosc tilePos) { + return 0.0F; + } + + @Override + public void updateTick(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Random rand, boolean isRandomTick) { + if (!world.isClientSide && world.dimension == Dimension.NETHER && rand.nextInt(10) == 0) { + int dir = rand.nextInt(6); + Direction direction = Direction.fromId(dir); + TilePos checkPos = tilePos.add(direction, new TilePos()); + Block checkBlock = world.getBlockType(checkPos); + if (checkBlock == Blocks.AIR) { + world.spawnParticle("rubyglassLightning", tilePos.x(), tilePos.y(), tilePos.z(), 0.0F, 0.0F, 0.0F, dir, 1600.0F, true); + } + } + } + + @Override + public int getPistonPushReaction(@NotNull World world, @NotNull TilePosc tilePos) { + return 0; + } +} diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassSprout.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassSprout.java deleted file mode 100644 index 026c98085..000000000 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassSprout.java +++ /dev/null @@ -1,196 +0,0 @@ -package net.minecraft.core.block; - -import net.minecraft.core.block.entity.TileEntity; -import net.minecraft.core.block.material.Materials; -import net.minecraft.core.enums.EnumDropCause; -import net.minecraft.core.item.ItemStack; -import net.minecraft.core.item.Items; -import net.minecraft.core.util.helper.Direction; -import net.minecraft.core.util.helper.Side; -import net.minecraft.core.world.World; -import net.minecraft.core.world.WorldSource; -import net.minecraft.core.world.pos.TilePos; -import net.minecraft.core.world.pos.TilePosc; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.joml.primitives.AABBd; - -public class BlockLogicRubyglassSprout extends BlockLogic { - public BlockLogicRubyglassSprout(Block block) { - super(block, Materials.PLANT); - block.setTicking(true); - } - - public static final int MASK_DIRECTION = 0b0000_0111; - - @Override - public void onPlacedOnSide(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side, final double xHit, final double yHit) { - final @NotNull TilePos temp = new TilePos(); - if((side == Side.NORTH && world.isBlockNormalCube(tilePos.south(temp))) - || side == Side.SOUTH && world.isBlockNormalCube(tilePos.north(temp)) - || (side == Side.EAST && world.isBlockNormalCube(tilePos.west(temp))) - || (side == Side.WEST && world.isBlockNormalCube(tilePos.east(temp))) - || (side == Side.BOTTOM && world.isBlockNormalCube(tilePos.up(temp))) - || (side == Side.TOP && world.isBlockNormalCube(tilePos.down(temp)))) { - world.setBlockDataNotify(tilePos, BlockLogicRotatable.setDirection(0, side.direction())); - } else { - world.setBlockDataNotify(tilePos, BlockLogicRotatable.setDirection(0, getOrientation(world, tilePos))); - } - } - - private Direction getOrientation(World world, TilePosc tilePos) - { - final @NotNull TilePos temp = new TilePos(); - if(world.isBlockNormalCube(tilePos.west(temp))) - { - return Side.EAST.direction(); - } - if(world.isBlockNormalCube(tilePos.east(temp))) - { - return Side.WEST.direction(); - } - if(world.isBlockNormalCube(tilePos.south(temp))) - { - return Side.NORTH.direction(); - } - if (world.isBlockNormalCube(tilePos.north(temp))){ - return Side.SOUTH.direction(); - } - if (world.isBlockNormalCube(tilePos.down(temp))){ - return Side.TOP.direction(); - } - if (world.isBlockNormalCube(tilePos.up(temp))){ - return Side.BOTTOM.direction(); - } - return Side.TOP.direction(); - } - - @Override - public void onNeighborChanged(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Block block) { - boolean invalid; - int meta = world.getBlockData(tilePos); - Direction dir = metaToDirection(meta); - final @NotNull TilePos temp = new TilePos(); - invalid = switch (dir) { - case EAST -> !world.isBlockNormalCube(tilePos.west(temp)); - case WEST -> !world.isBlockNormalCube(tilePos.east(temp)); - case SOUTH -> !world.isBlockNormalCube(tilePos.north(temp)); - case NORTH -> !world.isBlockNormalCube(tilePos.south(temp)); - case DOWN -> !world.isBlockNormalCube(tilePos.up(temp)); - case UP -> !world.isBlockNormalCube(tilePos.down(temp)); - default -> false; - }; - if(invalid) - { - world.setBlockTypeNotify(tilePos, Blocks.AIR); - } - } - - @Override - public boolean isSolidRender() { - return false; - } - - @Override - public boolean isCubeShaped() { - return false; - } - - @Override - public @Nullable AABBd getCollisionAABB(final @NotNull WorldSource source, final @NotNull TilePosc tilePos) { - return null; - } - - public boolean mayPlaceOnBlockAt(final @NotNull World world, final @NotNull TilePosc tilePos) { - return world.isBlockNormalCube(tilePos); - } - - @Override - public boolean canPlaceAt(final @NotNull World world, final @NotNull TilePosc tilePos) { - final @NotNull TilePos temp = new TilePos(); - if(mayPlaceOnBlockAt(world, tilePos.south(temp))) - { - return true; - } - if(mayPlaceOnBlockAt(world, tilePos.north(temp))) - { - return true; - } - if(mayPlaceOnBlockAt(world, tilePos.west(temp))) - { - return true; - } - if(mayPlaceOnBlockAt(world, tilePos.east(temp))) - { - return true; - } - if(mayPlaceOnBlockAt(world, tilePos.up(temp))) - { - return true; - } - return mayPlaceOnBlockAt(world, tilePos.down(temp)); - } - - @Override - public boolean canStay(final @NotNull World world, final @NotNull TilePosc tilePos) { - final @NotNull TilePos temp = new TilePos(); - return world.isBlockNormalCube(tilePos.south(temp)) - || world.isBlockNormalCube(tilePos.north(temp)) - || world.isBlockNormalCube(tilePos.west(temp)) - || world.isBlockNormalCube(tilePos.east(temp)) - || world.isBlockNormalCube(tilePos.up(temp)) - || world.isBlockNormalCube(tilePos.down(temp)); - } - - public static void setDefaultDirection(World world, TilePosc tilePos) - { - final @NotNull TilePos temp = new TilePos(); - if(world.isClientSide) - { - return; - } - Direction direction = Direction.UP; - if(world.isBlockNormalCube(tilePos.north(temp))) - { - direction = Direction.SOUTH; - } - else if(world.isBlockNormalCube(tilePos.south(temp))) - { - direction = Direction.NORTH; - } - else if(world.isBlockNormalCube(tilePos.west(temp))) - { - direction = Direction.EAST; - } - else if(world.isBlockNormalCube(tilePos.east(temp))) - { - direction = Direction.WEST; - } - else if(world.isBlockNormalCube(tilePos.up(temp))) - { - direction = Direction.DOWN; - } - world.setBlockDataNotify(tilePos, direction.id); - } - - @Override - public ItemStack[] getBreakResult(@NotNull World world, @NotNull EnumDropCause dropCause, int meta, TileEntity tileEntity) { - return switch (dropCause) { - case PICK_BLOCK, SILK_TOUCH -> new ItemStack[]{new ItemStack(this)}; - default -> dropCrystal(world); - }; - } - - private ItemStack[] dropCrystal(@NotNull World world) { - // Buds have a 1/50 chance to drop pure Rubyglass. - if(world.rand.nextInt(50) == 0) { - return new ItemStack[] { new ItemStack(Items.RUBYGLASS_CRYSTAL) }; - } - return null; - } - - public static Direction metaToDirection(int meta) { - return Direction.fromId(meta & MASK_DIRECTION); - } - -} diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSoulcatcher.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSoulCatcher.java similarity index 89% rename from game/core/src/main/java/net/minecraft/core/block/BlockLogicSoulcatcher.java rename to game/core/src/main/java/net/minecraft/core/block/BlockLogicSoulCatcher.java index 8d616a0f7..3050d08ba 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSoulcatcher.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSoulCatcher.java @@ -4,16 +4,15 @@ import net.minecraft.core.block.entity.TileEntity; import net.minecraft.core.entity.Entity; import net.minecraft.core.enums.EnumDropCause; import net.minecraft.core.item.ItemStack; -import net.minecraft.core.item.Items; import net.minecraft.core.world.World; import net.minecraft.core.world.pos.TilePos; import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class BlockLogicSoulcatcher extends BlockLogicFlower { +public class BlockLogicSoulCatcher extends BlockLogicFlower { - public BlockLogicSoulcatcher(final @NotNull Block block) { + public BlockLogicSoulCatcher(final @NotNull Block block) { super(block); final float f = 0.4F; this.setBlockBounds(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, 0.8F, 0.5F + f); diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStairs.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStairs.java index 3ce6bd769..e0294b7a3 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStairs.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStairs.java @@ -176,7 +176,6 @@ public class BlockLogicStairs extends BlockLogic { public BlockLogicStairs(@NotNull Block block, @NotNull Block modelBlock) { super(block, Materials.STONE); this.modelBlock = modelBlock; - block.withLightBlock(255); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java index 15de385de..9825de3f8 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java @@ -146,7 +146,7 @@ public class BlockLogicStatue extends BlockLogic { // All else fails - next pose statueEntity.nextPose(); - world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, (double) tilePos.x() + 0.5D, (double) tilePos.y() + 0.5D, (double) tilePos.z() + 0.5D, "random.scrape", 0.7F, 0.2F + world.rand.nextFloat() * 0.2F); + world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, (double) tilePos.x() + 0.5D, (double) tilePos.y() + 0.5D, (double) tilePos.z() + 0.5D, "scrape", 1.0F, 0.15F + world.rand.nextFloat() * 0.7F); return true; } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSulfur.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSulfur.java new file mode 100644 index 000000000..4570f258a --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSulfur.java @@ -0,0 +1,110 @@ +package net.minecraft.core.block; + +import net.minecraft.core.block.entity.TileEntity; +import net.minecraft.core.block.material.Material; +import net.minecraft.core.block.material.Materials; +import net.minecraft.core.entity.Mob; +import net.minecraft.core.entity.player.Player; +import net.minecraft.core.enums.EnumDropCause; +import net.minecraft.core.item.Item; +import net.minecraft.core.item.ItemStack; +import net.minecraft.core.item.Items; +import net.minecraft.core.sound.SoundCategory; +import net.minecraft.core.util.helper.Direction; +import net.minecraft.core.util.helper.Side; +import net.minecraft.core.world.LevelListener; +import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Random; + +public class BlockLogicSulfur extends BlockLogic { + + public BlockLogicSulfur(@NotNull Block block) { + super(block, Materials.SOUL_SAND); + block.setTicking(true); + } + + @Override + public ItemStack[] getBreakResult(@NotNull World world, @NotNull EnumDropCause dropCause, int data, @Nullable TileEntity tileEntity) { + return switch (dropCause) { + case PICK_BLOCK, SILK_TOUCH -> new ItemStack[]{new ItemStack(this)}; + default -> new ItemStack[]{new ItemStack(Items.SULFUR, 1 + world.rand.nextInt(2))}; + }; + } + + @Override + public int tickDelay() { + return 20; + } + + @Override + public void onNeighborChanged(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Block block) { + world.scheduleBlockUpdate(tilePos, this.block, this.tickDelay() + world.rand.nextInt(5) - world.rand.nextInt(5)); + } + + @Override + public void onPlacedByWorld(@NotNull World world, @NotNull TilePosc tilePos) { + world.scheduleBlockUpdate(tilePos, this.block, this.tickDelay() + world.rand.nextInt(5) - world.rand.nextInt(5)); + } + + public boolean canMelt(@NotNull World world, @NotNull TilePosc tilePos) { + int acidCount = 0; + TilePos queryPos = new TilePos(); + + for (Direction dir : Direction.ID_MAP) { + Block block = world.getBlockType(tilePos.add(dir, queryPos)); + Material adjacentMaterial = block.getMaterial(); + if (adjacentMaterial == Materials.LAVA) return false; + if (adjacentMaterial == Materials.WATER) return false; + if (adjacentMaterial == Materials.ACID) { + acidCount++; + } + } + + return acidCount >= 3; + } + + @Override + public void updateTick(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Random rand, boolean isRandomTick) { + if (this.canMelt(world, tilePos)) { + world.playBlockEvent(tilePos, LevelListener.EVENT_ACID_SPREAD, 0); + world.setBlockTypeNotify(tilePos, Blocks.FLUID_ACID_FLOWING); + } + + } + + @Override + public void onPlacedByMob(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side, final @NotNull Mob mob, final double xHit, final double yHit) { + world.playSoundEffect( + mob, + SoundCategory.WORLD_SOUNDS, + tilePos.x() + 0.5, + tilePos.y() + 0.5, + tilePos.z() + 0.5, + "step.stone", + 1.0F, + 0.8F + ); + this.onPlacedOnSide(world, tilePos, side, xHit, yHit); + } + + @Override + public void onDestroyedByPlayer(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side, final int data, final @NotNull Player player, final @Nullable Item item) { + super.onDestroyedByPlayer(world, tilePos, side, data, player, item); + + world.playSoundEffect( + player, + SoundCategory.WORLD_SOUNDS, + tilePos.x() + 0.5, + tilePos.y() + 0.5, + tilePos.z() + 0.5, + "step.stone", + 1.0F, + 0.8F + ); + } +} diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSulfurHardened.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSulfurHardened.java new file mode 100644 index 000000000..dec03b406 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSulfurHardened.java @@ -0,0 +1,100 @@ +package net.minecraft.core.block; + +import net.minecraft.core.block.entity.TileEntity; +import net.minecraft.core.entity.Mob; +import net.minecraft.core.entity.player.Player; +import net.minecraft.core.enums.EnumDropCause; +import net.minecraft.core.item.Item; +import net.minecraft.core.item.ItemStack; +import net.minecraft.core.sound.SoundCategory; +import net.minecraft.core.util.helper.Side; +import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Random; + +public class BlockLogicSulfurHardened extends BlockLogicSulfur { + + public BlockLogicSulfurHardened(@NotNull Block block) { + super(block); + block.setTicking(false); + } + + @Override + public ItemStack[] getBreakResult(@NotNull World world, @NotNull EnumDropCause dropCause, int data, @Nullable TileEntity tileEntity) { + return switch (dropCause) { + case PICK_BLOCK, SILK_TOUCH -> new ItemStack[]{new ItemStack(Blocks.SULFUR_HARDENED)}; + default -> null; + }; + } + + @Override + public void onDestroyedByPlayer(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side, final int data, final @NotNull Player player, final @Nullable Item item) { + super.onDestroyedByPlayer(world, tilePos, side, data, player, item); + world.playSoundEffect( + player, + SoundCategory.WORLD_SOUNDS, + tilePos.x() + 0.5, + tilePos.y() + 0.5, + tilePos.z() + 0.5, + "mob.skeleton", + 1.0F, + 2.0F + ); + + world.playSoundEffect( + player, + SoundCategory.WORLD_SOUNDS, + tilePos.x() + 0.5, + tilePos.y() + 0.5, + tilePos.z() + 0.5, + "step.stone", + 1.0F, + 0.8F + ); + } + + @Override + public boolean canMelt(@NotNull World world, @NotNull TilePosc tilePos) { + return false; + } + + @Override + public void onNeighborChanged(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Block block) { + } + + @Override + public void onPlacedByWorld(@NotNull World world, @NotNull TilePosc tilePos) { + } + + @Override + public void updateTick(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Random rand, boolean isRandomTick) { + } + + @Override + public void onPlacedByMob(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side, final @NotNull Mob mob, final double xHit, final double yHit) { + world.playSoundEffect( + mob, + SoundCategory.WORLD_SOUNDS, + tilePos.x() + 0.5, + tilePos.y() + 0.5, + tilePos.z() + 0.5, + "mob.skeleton", + 1.0F, + 2.0F + ); + world.playSoundEffect( + mob, + SoundCategory.WORLD_SOUNDS, + tilePos.x() + 0.5, + tilePos.y() + 0.5, + tilePos.z() + 0.5, + "step.stone", + 1.0F, + 0.8F + ); + this.onPlacedOnSide(world, tilePos, side, xHit, yHit); + } +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicThermalVent.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicThermalVent.java index 82999466d..8ba5af230 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicThermalVent.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicThermalVent.java @@ -2,18 +2,19 @@ package net.minecraft.core.block; import net.minecraft.core.block.material.Materials; import net.minecraft.core.entity.Entity; -import net.minecraft.core.sound.SoundCategory; +import net.minecraft.core.entity.player.Player; import net.minecraft.core.world.World; +import net.minecraft.core.world.particle.ParticleEmitterRange; import net.minecraft.core.world.pos.TilePos; import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.joml.primitives.AABBd; import java.util.List; import java.util.Random; -public class BlockLogicThermalVent - extends BlockLogic { +public class BlockLogicThermalVent extends BlockLogic { public static final int META_MASK = 0b0000_0111; public static int DORMANT_STATE = 0; public static int VENTING_STATE = 4; @@ -35,12 +36,12 @@ public class BlockLogicThermalVent return; } - world.spawnParticle("ventsmoke", xPos, yPos, zPos, 0.0D, 0.005D, 0.0D, 1, 32, false); + world.spawnParticle("ventsmoke", xPos, yPos, zPos, 0.0D, 0.005D, 0.0D, 1, 1000, true); if (state >= VENTING_STATE - 1) { for (int i = 0; i < 4; i++) { - world.spawnParticle("ventsmoke", xPos, yPos, zPos, 0.0D, 0.005D, 0.0D, 0, 32, false); - world.spawnParticle("smoke", xPos + rand.nextFloat() - 0.5D, yPos, zPos + rand.nextFloat() - 0.5D, 0.0D, 0.005D, 0.0D, 1, 32, false); + world.spawnParticle("ventsmoke", xPos, yPos, zPos, 0.0D, 0.005D, 0.0D, 0, 1000.0, true); + world.spawnParticle("smoke", xPos + rand.nextFloat() - 0.5D, yPos, zPos + rand.nextFloat() - 0.5D, 0.0D, 0.005D, 0.0D, 1, 1000.0, true); } } } @@ -58,14 +59,28 @@ public class BlockLogicThermalVent return; } - int state = getVentState(world.getBlockData(tilePos)); - if (state < VENTING_STATE) { - final int buildUpRate = getBuildupRate(world, tilePos, rand); - state += buildUpRate; - world.setBlockDataNotify(tilePos, state); + if (rand.nextInt(4) != 0) { + int state = getVentState(world.getBlockData(tilePos)); + if (state < VENTING_STATE) { + final int buildUpRate = getBuildupRate(world, tilePos, rand); + state += buildUpRate; + world.setBlockDataNotify(tilePos, state); + } else { + vent(world, tilePos, rand); + } + } + } + + private static void alertNearbyPlayers(final @NotNull World world, final @NotNull TilePosc tilePos) { + double searchRadius = 200.0; + double ventX = tilePos.x() + 0.5D; + double ventY = tilePos.y() + 0.5D; + double ventZ = tilePos.z() + 0.5D; + + List nearbyPlayers = world.getPlayersWithinRange(ventX, ventY, ventZ, searchRadius); - } else { - vent(world, tilePos, rand); + for (Player player : nearbyPlayers) { + player.handleThermalPing(player, ventX, ventY, ventZ, searchRadius); } } @@ -73,8 +88,8 @@ public class BlockLogicThermalVent return META_MASK & data; } - private static void vent(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Random rand) { + for (int i = 0; i < 40; i++) { final double xPos = tilePos.x() + 0.5D; final double yPos = tilePos.y() + 1.125D; @@ -83,17 +98,34 @@ public class BlockLogicThermalVent final double xd = (rand.nextFloat() - 0.5d) * 0.5d; final double zd = (rand.nextFloat() - 0.5d) * 0.5d; - world.spawnParticle("ventsmoke", xPos, yPos, zPos, 0.0D, 0.25D + rand.nextFloat(), 0.0D, 1, 32, false); - world.spawnParticle("flame", xPos, yPos, zPos, xd, 0.25D + rand.nextFloat(), zd, 0, 32, false); + world.spawnParticle("ventsmoke", xPos, yPos, zPos, 0.0D, 0.25D + rand.nextFloat(), 0.0D, 1, false); + world.spawnParticle("flame", xPos, yPos, zPos, xd, 0.25D + rand.nextFloat(), zd, 0, false); } - world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, tilePos.x(), tilePos.y(), tilePos.z(), "random.explode", 2.0F, 0.5F + rand.nextFloat() * 0.2F); - final List entities = world.getEntitiesWithinAABB(Entity.class, new AABBd(tilePos.x() - 1, tilePos.y(), tilePos.z() - 1, tilePos.x() + 1, tilePos.y() + 6, tilePos.z() + 1)); - for (final @NotNull Entity entity : entities) { - entity.fling(0, 2, 0, 1f); + if (!world.isClientSide) { + alertNearbyPlayers(world, tilePos); + + final List entities = world.getEntitiesWithinAABB(Entity.class, new AABBd(tilePos.x() - 1, tilePos.y(), tilePos.z() - 1, tilePos.x() + 1, tilePos.y() + 6, tilePos.z() + 1)); + for (final @NotNull Entity entity : entities) { + entity.fling(0, 2, 0, 1f); + } + + world.setBlockDataNotify(tilePos, DORMANT_STATE); + } + } + + @Override + public void onPlacedByWorld(final @NotNull World world, final @NotNull TilePosc tilePos) { + super.onPlacedByWorld(world, tilePos); + + if (!world.isClientSide) { + world.setBlockDataNotify(tilePos, world.rand.nextInt(VENTING_STATE)); } - world.setBlockDataNotify(tilePos, DORMANT_STATE); } -} + @Override + public @Nullable ParticleEmitterRange getParticleEmitterRange() { + return ParticleEmitterRange.FAR; + } +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/block/Blocks.java b/game/core/src/main/java/net/minecraft/core/block/Blocks.java index 0f412e6ec..f1c2b4de5 100644 --- a/game/core/src/main/java/net/minecraft/core/block/Blocks.java +++ b/game/core/src/main/java/net/minecraft/core/block/Blocks.java @@ -174,7 +174,7 @@ public final class Blocks { .withTags(BlockTags.BROKEN_BY_FLUIDS, BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.PREVENT_MOB_SPAWNS, BlockTags.CAN_HANG_OFF, BlockTags.INSTANT_PICKUP); public static final @NotNull Block BRICK_CLAY = register("brick.clay", "minecraft:block/brick_clay", 120, (b) -> new BlockLogic(b, Materials.STONE)) - .withSound(BlockSounds.STONE).withHardness(3.0F).withBlastResistance(10F).withOverrideColor(MaterialColor.brick) + .withSound(BlockSounds.STONE).withHardness(2.0F).withBlastResistance(10F).withOverrideColor(MaterialColor.brick) .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT); public static final @NotNull Block BRICK_STONE_POLISHED = register("brick.stone.polished", "minecraft:block/brick_stone_polished", 121, (b) -> new BlockLogic(b, Materials.STONE)) .withSound(BlockSounds.STONE).withHardness(2.0F).withBlastResistance(10F) @@ -189,7 +189,7 @@ public final class Blocks { .withSound(BlockSounds.METAL).withHardness(3F).withBlastResistance(10F).withOverrideColor(MaterialColor.gold) .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT); public static final @NotNull Block BRICK_LAPIS = register("brick.lapis", "minecraft:block/brick_lapis", 125, (b) -> new BlockLogic(b, Materials.LAPIS)) - .withSound(BlockSounds.STONE).withHardness(3F).withBlastResistance(10F).withOverrideColor(MaterialColor.lapis) + .withSound(BlockSounds.STONE).withHardness(2.0F).withBlastResistance(10F).withOverrideColor(MaterialColor.lapis) .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT); public static final @NotNull Block BRICK_BASALT = register("brick.basalt", "minecraft:block/brick_basalt", 126, (b) -> new BlockLogic(b, Materials.BASALT)) .withSound(BlockSounds.STONE).withHardness(2.0F).withBlastResistance(10F) @@ -214,17 +214,17 @@ public final class Blocks { .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT); public static final @NotNull Block BRICK_IRON = register("brick.iron", "minecraft:block/brick_iron", 133, (b) -> new BlockLogic(b, Materials.IRON)) - .withSound(BlockSounds.METAL).withHardness(5F).withBlastResistance(10F).withOverrideColor(MaterialColor.iron) + .withSound(BlockSounds.METAL).withHardness(3.0F).withBlastResistance(10F).withOverrideColor(MaterialColor.iron) .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT); public static final @NotNull Block BRICK_STEEL = register("brick.steel", "minecraft:block/brick_steel", 134, (b) -> new BlockLogic(b, Materials.STEEL)) - .withSound(BlockSounds.METAL).withHardness(5F).withBlastResistance(2000F).withOverrideColor(MaterialColor.steel) + .withSound(BlockSounds.METAL).withHardness(3.0F).withBlastResistance(2000F).withOverrideColor(MaterialColor.steel) .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT); public static final @NotNull Block BRICK_OLIVINE = register("brick.olivine", "minecraft:block/brick_olivine", 135, (b) -> new BlockLogic(b, Materials.OLIVINE)) - .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT).withSound(BlockSounds.PERMAFROST).withHardness(3F).withBlastResistance(10F).withOverrideColor(MaterialColor.olivine); + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT).withSound(BlockSounds.PERMAFROST).withHardness(2.0F).withBlastResistance(10F).withOverrideColor(MaterialColor.olivine); public static final @NotNull Block BRICK_QUARTZ = register("brick.quartz", "minecraft:block/brick_quartz", 136, (b) -> new BlockLogic(b, Materials.QUARTZ)) - .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT).withSound(BlockSounds.PERMAFROST).withHardness(3F).withBlastResistance(10F).withOverrideColor(MaterialColor.quartz); + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT).withSound(BlockSounds.PERMAFROST).withHardness(2.0F).withBlastResistance(10F).withOverrideColor(MaterialColor.quartz); public static final @NotNull Block BRICK_DIAMOND = register("brick.diamond", "minecraft:block/brick_diamond", 137, (b) -> new BlockLogic(b, Materials.DIAMOND)) - .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT).withSound(BlockSounds.PERMAFROST).withHardness(5F).withBlastResistance(10F).withOverrideColor(MaterialColor.diamond); + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT).withSound(BlockSounds.PERMAFROST).withHardness(2.0F).withBlastResistance(10F).withOverrideColor(MaterialColor.diamond); public static final @NotNull Block SLAB_PLANKS_OAK = register("slab.planks.oak", "minecraft:block/slab_planks_oak", 140, (BlockLogicSupplier)b -> new BlockLogicSlabPaintable(b, Blocks.PLANKS_OAK)) @@ -423,9 +423,6 @@ public final class Blocks { .withSound(BlockSounds.GRAVEL).withHardness(0.6F) .withTags(BlockTags.MINEABLE_BY_SHOVEL) .withOverrideColor(MaterialColor.stone); - public static final Block BRIMSAND = register("brimsand", "minecraft:block/brimsand", 252, (b) -> new BlockLogic(b, Materials.SAND)) - .withSound(BlockSounds.SAND).withHardness(0.7F) - .withTags(BlockTags.MINEABLE_BY_SHOVEL, BlockTags.CAVES_CUT_THROUGH, BlockTags.NETHER_MOBS_SPAWN, BlockTags.NETHER_SURFACE_BLOCK); public static final @NotNull Block BEDROCK = register("bedrock", "minecraft:block/bedrock", 260, (b) -> new BlockLogicBedrock(b, Materials.STONE)) .withSound(BlockSounds.STONE).withSetUnbreakable().withBlastResistance(6000000F).withImmovableFlagSet() @@ -670,23 +667,23 @@ public final class Blocks { public static final @NotNull Block ORE_REDSTONE_GLOWING_STONE = register("ore.redstone.glowing.stone", "minecraft:block/ore_redstone_glowing_stone", 400, (b) -> new BlockLogicOreRedstone(b, null, Materials.STONE, true, Blocks.ORE_REDSTONE_STONE, Blocks.ORE_REDSTONE_GLOWING_STONE)) - .withSound(BlockSounds.STONE).withLightEmission(0.2F).withHardness(3F).withBlastResistance(5F).withDisabledNeighborNotifyOnMetadataChange().setStatParent(() -> ORE_REDSTONE_STONE) + .withSound(BlockSounds.STONE).withHardness(3F).withBlastResistance(5F).withDisabledNeighborNotifyOnMetadataChange().setStatParent(() -> ORE_REDSTONE_STONE) .withTags(BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.MINEABLE_BY_PICKAXE); public static final @NotNull Block ORE_REDSTONE_GLOWING_BASALT = register("ore.redstone.glowing.basalt", "minecraft:block/ore_redstone_glowing_basalt", 401, (b) -> new BlockLogicOreRedstone(b, null, Materials.BASALT, true, Blocks.ORE_REDSTONE_BASALT, Blocks.ORE_REDSTONE_GLOWING_BASALT)) - .withSound(BlockSounds.STONE).withLightEmission(0.2F).withHardness(3F).withBlastResistance(5F).withDisabledNeighborNotifyOnMetadataChange().setStatParent(() -> ORE_REDSTONE_BASALT) + .withSound(BlockSounds.STONE).withHardness(3F).withBlastResistance(5F).withDisabledNeighborNotifyOnMetadataChange().setStatParent(() -> ORE_REDSTONE_BASALT) .withTags(BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.MINEABLE_BY_PICKAXE); public static final @NotNull Block ORE_REDSTONE_GLOWING_LIMESTONE = register("ore.redstone.glowing.limestone", "minecraft:block/ore_redstone_glowing_limestone", 402, (b) -> new BlockLogicOreRedstone(b, null, Materials.LIMESTONE, true, Blocks.ORE_REDSTONE_LIMESTONE, Blocks.ORE_REDSTONE_GLOWING_LIMESTONE)) - .withSound(BlockSounds.STONE).withLightEmission(0.2F).withHardness(3F).withBlastResistance(5F).withDisabledNeighborNotifyOnMetadataChange().setStatParent(() -> ORE_REDSTONE_LIMESTONE) + .withSound(BlockSounds.STONE).withHardness(3F).withBlastResistance(5F).withDisabledNeighborNotifyOnMetadataChange().setStatParent(() -> ORE_REDSTONE_LIMESTONE) .withTags(BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.MINEABLE_BY_PICKAXE); public static final @NotNull Block ORE_REDSTONE_GLOWING_GRANITE = register("ore.redstone.glowing.granite", "minecraft:block/ore_redstone_glowing_granite", 403, (b) -> new BlockLogicOreRedstone(b, null, Materials.GRANITE, true, Blocks.ORE_REDSTONE_GRANITE, Blocks.ORE_REDSTONE_GLOWING_GRANITE)) - .withSound(BlockSounds.STONE).withLightEmission(0.2F).withHardness(3F).withBlastResistance(5F).withDisabledNeighborNotifyOnMetadataChange().setStatParent(() -> ORE_REDSTONE_GRANITE) + .withSound(BlockSounds.STONE).withHardness(3F).withBlastResistance(5F).withDisabledNeighborNotifyOnMetadataChange().setStatParent(() -> ORE_REDSTONE_GRANITE) .withTags(BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.MINEABLE_BY_PICKAXE); public static final @NotNull Block ORE_REDSTONE_GLOWING_PERMAFROST = register("ore.redstone.glowing.permafrost", "minecraft:block/ore_redstone_glowing_permafrost", 404, (b) -> new BlockLogicOreRedstone(b, null, Materials.PERMAFROST, true, Blocks.ORE_REDSTONE_PERMAFROST, Blocks.ORE_REDSTONE_GLOWING_PERMAFROST)) - .withSound(BlockSounds.PERMAFROST).withLightEmission(0.2F).withHardness(3F).withBlastResistance(5F).withDisabledNeighborNotifyOnMetadataChange().setStatParent(() -> ORE_REDSTONE_PERMAFROST) + .withSound(BlockSounds.PERMAFROST).withHardness(3F).withBlastResistance(5F).withDisabledNeighborNotifyOnMetadataChange().setStatParent(() -> ORE_REDSTONE_PERMAFROST) .withTags(BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.MINEABLE_BY_PICKAXE); public static final @NotNull Block ORE_DIAMOND_STONE = register("ore.diamond.stone", "minecraft:block/ore_diamond_stone", 410, (b) -> new BlockLogicOreDiamond(b, Blocks.STONE, Materials.STONE)) @@ -706,13 +703,13 @@ public final class Blocks { .withTags(BlockTags.MINEABLE_BY_PICKAXE); public static final @NotNull Block ORE_NETHERCOAL_NETHERRACK = register("ore.nethercoal.netherrack", "minecraft:block/ore_nethercoal_netherrack", 420, (b) -> new BlockLogicOreNetherCoal(b, Blocks.COBBLE_NETHERRACK, Materials.NETHERRACK)) - .withSound(BlockSounds.STONE).withHardness(3F).withBlastResistance(5F).withLightEmission(0.625F) + .withSound(BlockSounds.STONE).withHardness(3F).withBlastResistance(5F) .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NETHER_MOBS_SPAWN); public static final @NotNull Block ORE_NETHERCOAL_BASALT = register("ore.nethercoal.basalt", "minecraft:block/ore_nethercoal_basalt", 421, (b) -> new BlockLogicOreNetherCoal(b, Blocks.COBBLE_BASALT, Materials.BASALT)) - .withSound(BlockSounds.STONE).withHardness(3F).withBlastResistance(5F).withLightEmission(0.625F) + .withSound(BlockSounds.STONE).withHardness(3F).withBlastResistance(5F) .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NETHER_MOBS_SPAWN); public static final @NotNull Block ORE_NETHERCOAL_GLOOMSTONE = register("ore.nethercoal.gloomstone", "minecraft:block/ore_nethercoal_gloomstone", 422, (b) -> new BlockLogicOreNetherCoal(b, Blocks.COBBLE_GLOOMSTONE, Materials.GLOOMSTONE)) - .withSound(BlockSounds.STONE).withHardness(3F).withBlastResistance(10F).withLightEmission(0.625F) + .withSound(BlockSounds.STONE).withHardness(3F).withBlastResistance(10F) .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NETHER_MOBS_SPAWN); public static final @NotNull Block BLOCK_COAL = register("block.coal", "minecraft:block/block_coal", 430, (b) -> new BlockLogic(b, Materials.STONE)) @@ -868,7 +865,7 @@ public final class Blocks { public static final @NotNull Block DISPENSER_COBBLE_STONE = register("dispenser.cobble.stone", "minecraft:block/dispenser_cobble_stone", 560, BlockLogicDispenser::new) .withSound(BlockSounds.STONE).withHardness(1.5F).withDisabledNeighborNotifyOnMetadataChange() .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.PREVENT_MOB_SPAWNS, BlockTags.CHAINLINK_FENCES_CONNECT); - public static final @NotNull Block ACTIVATOR_COBBLE_NETHERRACK = register("activator.cobble.netherrack", "minecraft:block/activator_cobble_netherrack", 561, BlockLogicActivator::new) + public static final @NotNull Block ACTIVATOR = register("activator.cobble.netherrack", "minecraft:block/activator_cobble_netherrack", 561, BlockLogicActivator::new) .withSound(BlockSounds.STONE).withHardness(1.5F).withDisabledNeighborNotifyOnMetadataChange() .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT, BlockTags.PREVENT_MOB_SPAWNS); @@ -942,7 +939,7 @@ public final class Blocks { .withSound(BlockSounds.METAL).withHardness(1F).withOverrideColor(MaterialColor.gold) .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT, BlockTags.CAN_HANG_OFF); - public static final @NotNull Block BED = register("bed", "minecraft:block/bed", 610, (BlockLogicSupplier)BlockLogicBed::new) + public static final @NotNull Block BED = register("bed", "minecraft:block/bed", 610, BlockLogicBed::new) .withSound(BlockSounds.WOOD).withHardness(0.2F).withDisabledNeighborNotifyOnMetadataChange().withLitInteriorSurface(true).setStatParent(() -> Items.BED) .withTags(BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.MINEABLE_BY_AXE); public static final @NotNull Block SEAT = register("seat", "minecraft:block/seat", 611, BlockLogicSeat::new) @@ -965,6 +962,9 @@ public final class Blocks { public static final @NotNull Block FIRE_COLD = register("fire_cold", "minecraft:block/fire_cold", 633, BlockLogicFireCold::new) .withSound(BlockSounds.FIRE).withHardness(0.0F).withLightEmission(1.0F).withDisabledStats().withDisabledNeighborNotifyOnMetadataChange() .withTags(BlockTags.BROKEN_BY_FLUIDS, BlockTags.PLACE_OVERWRITES, BlockTags.NOT_IN_CREATIVE_MENU); + public static final @NotNull Block FIRE_SULFURIC = register("fire_sulfuric", "minecraft:block/fire_sulfuric", 634, BlockLogicFireSulfuric::new) + .withSound(BlockSounds.FIRE).withHardness(0.0F).withLightEmission(1.0F).withDisabledStats().withDisabledNeighborNotifyOnMetadataChange() + .withTags(BlockTags.BROKEN_BY_FLUIDS, BlockTags.PLACE_OVERWRITES, BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.SULFURIC_FIRE_OVERLAY_SOURCE); public static final @NotNull Block MOBSPAWNER = register("mobspawner", "minecraft:block/mobspawner", 640, BlockLogicMobSpawner::new) .withSound(BlockSounds.METAL).withHardness(5F).withImmovableFlagSet() @@ -1146,35 +1146,38 @@ public final class Blocks { public static final @NotNull Block GLOWSTONE = register("glowstone", "minecraft:block/glowstone", 820, (b) -> new BlockLogicGlowStone(b, Materials.STONE)) .withSound(BlockSounds.GLASS).withHardness(0.3F).withLightEmission(1.0F).withOverrideColor(MaterialColor.paintedYellow) + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.INFINITE_BURN_SULFURIC); + + public static final @NotNull Block RUBYGLASS_COLUMN = register("rubyglass.column", "minecraft:block/rubyglass_column", 821, (b) -> new BlockLogicRubyglass(b)) + .withSound(BlockSounds.CRYSTAL).withOverrideColor(MaterialColor.rubyglass).withHardness(2F) .withTags(BlockTags.MINEABLE_BY_PICKAXE); - public static final Block RUBYGLASS_COLUMN = register("rubyglass.column", "minecraft:block/rubyglass_column", 821, (b) -> new BlockLogicRubyglass(b)) - .withSound(BlockSounds.GLASS).withHardness(3F).withLightEmission(0.1F).withLightBlock(0) - .withTags(BlockTags.MINEABLE_BY_PICKAXE) - .withOverrideColor(MaterialColor.rubyglass); - public static final Block BLOCK_RUBYGLASS = register("block.rubyglass", "minecraft:block/block_rubyglass", 822, (b) -> new BlockLogicTransparent(b, Materials.STONE)) - .withSound(BlockSounds.GLASS).withHardness(3F).withLightEmission(0.5F) + public static final @NotNull Block BLOCK_RUBYGLASS = register("block.rubyglass", "minecraft:block/rubyglass_block", 822, (b) -> new BlockLogic(b, Materials.STONE)) + .withSound(BlockSounds.CRYSTAL).withOverrideColor(MaterialColor.rubyglass).withHardness(2F) + .withTags(BlockTags.MINEABLE_BY_PICKAXE); + public static final @NotNull Block RUBYGLASS_CRYSTAL = register("rubyglass.crystal", "minecraft:block/rubyglass_crystal", 823, BlockLogicRubyglassCrystal::new) + .withSound(BlockSounds.CRYSTAL).withHardness(1.5F).withOverrideColor(MaterialColor.rubyglass) + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.SKATEABLE, BlockTags.NETHER_MOBS_SPAWN, BlockTags.NETHER_SURFACE_BLOCK, BlockTags.CAVES_CUT_THROUGH); + public static final @NotNull Block CONDUIT = register("rubyglass.conduit", "minecraft:block/conduit", 824, (BlockLogicSupplier) b -> new BlockLogicConduit(b, Materials.STONE)) + .withSound(BlockSounds.STONE).withHardness(1.5F).withOverrideColor(MaterialColor.rubyglass).withDisabledNeighborNotifyOnMetadataChange() + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT, BlockTags.PREVENT_MOB_SPAWNS); + public static final @NotNull Block RUBYGLASS_GROWTH = register("rubyglass.growth", "minecraft:block/rubyglass_growth", 825, block -> new BlockLogicGrowthRubyglass(block, Materials.PLANT)) + .withSound(BlockSounds.CRYSTAL).withOverrideColor(MaterialColor.rubyglass) + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.SHEARS_DO_SILK_TOUCH); + public static final @NotNull Block RUBYGLASS_NODE = register("rubyglass.node", "minecraft:block/rubyglass_node", 826, (b) -> new BlockLogicNodeRubyglass(b)) + .withSound(BlockSounds.CRYSTAL).withHardness(3F) .withTags(BlockTags.MINEABLE_BY_PICKAXE) .withOverrideColor(MaterialColor.rubyglass); - public static final Block RUBYGLASS_SPROUT = register("rubyglass.sprout", "minecraft:block/rubyglass_sprout", 823, (b) -> new BlockLogicRubyglassSprout(b)) - .withSound(BlockSounds.GLASS).withDisabledNeighborNotifyOnMetadataChange().withLightEmission(0.5F) + public static final @NotNull Block BRICK_RUBYGLASS = register("brick.rubyglass", "minecraft:block/rubyglass_brick", 827, (b) -> new BlockLogicRubyglass(b)) + .withSound(BlockSounds.CRYSTAL).withHardness(2F) .withTags(BlockTags.MINEABLE_BY_PICKAXE) .withOverrideColor(MaterialColor.rubyglass); - public static final Block CONDUIT = register("rubyglass.conduit", "minecraft:block/conduit", 824, (BlockLogicSupplier) b -> new BlockLogicConduit(b, Materials.STONE)) - .withSound(BlockSounds.STONE).withHardness(1.5F).withDisabledNeighborNotifyOnMetadataChange() - .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT, BlockTags.PREVENT_MOB_SPAWNS) - .withOverrideColor(MaterialColor.rubyglass); - - public static final Block RUBYGLASS_NODE = register("rubyglass.node", "minecraft:block/rubyglass_node", 826, (b) -> new BlockLogicOreRubyglass(b)) - .withSound(BlockSounds.GLASS).withHardness(3F).withLightEmission(1.0F) - .withTags(BlockTags.MINEABLE_BY_PICKAXE) - .withOverrideColor(MaterialColor.rubyglass); public static final @NotNull Block PORTAL_NETHER = register("portal.nether", "minecraft:block/portal_nether", 830, (BlockLogicSupplier) b -> new BlockLogicPortal(b, Dimension.NETHER, Blocks.OBSIDIAN, Blocks.FIRE)) .withSound(BlockSounds.GLASS).withHardness(-1F).withLightEmission(0.75F).withOverrideColor(MaterialColor.paintedPurple).withDisabledStats() .withTags(BlockTags.BROKEN_BY_FLUIDS, BlockTags.NOT_IN_CREATIVE_MENU); public static final @NotNull Block PORTAL_DRIFT = register("portal.drift", "minecraft:block/portal_drift", 831, (BlockLogicSupplier) b -> new BlockLogicPortal(b, Dimension.DRIFT, Blocks.GLOWSTONE, Blocks.BEDROCK)) - .withSound(BlockSounds.GLASS).withHardness(-1F).withLightEmission(0.75f).withOverrideColor(MaterialColor.paintedPurple).withDisabledStats() + .withSound(BlockSounds.GLASS).withHardness(-1F).withLightEmission(0.75f).withOverrideColor(MaterialColor.paintedSilver).withDisabledStats() .withTags(BlockTags.BROKEN_BY_FLUIDS, BlockTags.NOT_IN_CREATIVE_MENU); public static final @NotNull Block CAKE = register("cake", "minecraft:block/cake", 840, BlockLogicCake::new) @@ -1280,7 +1283,12 @@ public final class Blocks { .withSound(BlockSounds.GLASS).withHardness(0.1F).withDisabledNeighborNotifyOnMetadataChange().setStatParent(() -> Items.JAR_BUTTERFLY_SILVER) .withTags(BlockTags.BROKEN_BY_FLUIDS, BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU); - //ID 999 taken by SLAB_BRICK_DIAMOND, placed near other ore brick slabs for organization. Ran out of IDs on that side - id:999 - + public static final Block SLAB_BRICK_RUBYGLASS = register("slab.brick.rubyglass", "minecraft:block/slab_brick_rubyglass", 998, (BlockLogicSupplier) b -> new BlockLogicSlab(b, Blocks.BRICK_RUBYGLASS)) + .withSound(BlockSounds.CRYSTAL).withOverrideColor(MaterialColor.rubyglass).withLitInteriorSurface(true) + .withTags(BlockTags.MINEABLE_BY_PICKAXE); + public static final @NotNull Block SLAB_BRICK_DIAMOND = register("slab.brick.diamond", "minecraft:block/slab_brick_diamond", 999, (BlockLogicSupplier)b -> new BlockLogicSlab(b, Blocks.BRICK_DIAMOND)) + .withSound(BlockSounds.PERMAFROST).withDisabledNeighborNotifyOnMetadataChange().withLitInteriorSurface(true) + .withTags(BlockTags.MINEABLE_BY_PICKAXE); public static final @NotNull Block SLAB_BRICK_SANDSTONE = register("slab.brick.sandstone", "minecraft:block/slab_brick_sandstone", 1000, (BlockLogicSupplier) b -> new BlockLogicSlab(b, Blocks.BRICK_SANDSTONE)) .withSound(BlockSounds.STONE).withDisabledNeighborNotifyOnMetadataChange().withLitInteriorSurface(true) @@ -1295,9 +1303,6 @@ public final class Blocks { .withSound(BlockSounds.PERMAFROST).withDisabledNeighborNotifyOnMetadataChange().withLitInteriorSurface(true) .withTags(BlockTags.MINEABLE_BY_PICKAXE); - public static final @NotNull Block SLAB_BRICK_DIAMOND = register("slab.brick.diamond", "minecraft:block/slab_brick_diamond", 999, (BlockLogicSupplier)b -> new BlockLogicSlab(b, Blocks.BRICK_DIAMOND)) - .withSound(BlockSounds.PERMAFROST).withDisabledNeighborNotifyOnMetadataChange().withLitInteriorSurface(true) - .withTags(BlockTags.MINEABLE_BY_PICKAXE); public static final @NotNull Block SLAB_BRICK_IRON = register("slab.brick.iron", "minecraft:block/slab_brick_iron", 1004, (BlockLogicSupplier)b -> new BlockLogicSlab(b, Blocks.BRICK_IRON)) .withSound(BlockSounds.METAL).withDisabledNeighborNotifyOnMetadataChange().withLitInteriorSurface(true) .withTags(BlockTags.MINEABLE_BY_PICKAXE); @@ -1355,34 +1360,36 @@ public final class Blocks { .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU); public static final Block THERMAL_VENT = register("vent", "minecraft:block/thermal_vent", 1025, BlockLogicThermalVent::new) - .withSound(BlockSounds.STONE).withHardness(1.5F).withTags(BlockTags.MINEABLE_BY_PICKAXE); + .withSound(BlockSounds.STONE).withHardness(1.5F) + .withTags(BlockTags.MINEABLE_BY_PICKAXE); - public static final Block BONE_PILE = register("bone_pile", "minecraft:block/bone_pile", 1030, BlockLogicBonepile::new) + public static final Block BONE_PILE = register("bone_pile", "minecraft:block/bone_pile", 1030, BlockLogicBonePile::new) .withSound(BlockSounds.STONE).withHardness(1.0F).withOverrideColor(MaterialColor.marble) .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.BROKEN_BY_FLUIDS, BlockTags.PLACE_OVERWRITES, BlockTags.SHEARS_DO_SILK_TOUCH, BlockTags.PLANTABLE_IN_JAR); - public static final Block SOULCATCHER = register("soul_catcher", "minecraft:block/soul_catcher", 1031, BlockLogicSoulcatcher::new) + public static final Block SOUL_CATCHER = register("soul_catcher", "minecraft:block/soul_catcher", 1031, BlockLogicSoulCatcher::new) .withSound(BlockSounds.GRAVEL).withHardness(1.0F).withOverrideColor(MaterialColor.sand) .withTags(BlockTags.MINEABLE_BY_SHOVEL, BlockTags.BROKEN_BY_FLUIDS, BlockTags.PLACE_OVERWRITES, BlockTags.SHEARS_DO_SILK_TOUCH, BlockTags.PLANTABLE_IN_JAR) .withOverrideColor(MaterialColor.soulsand); public static final Block GLOOMSTONE = register("gloomstone", "minecraft:block/gloomstone", 1032, (b) -> new BlockLogicStone(b, Blocks.COBBLE_GLOOMSTONE, Materials.GLOOMSTONE)) - .withSound(BlockSounds.STONE).withHardness(1.5F).withBlastResistance(10F) - .withTags(BlockTags.CAVES_CUT_THROUGH, BlockTags.NETHER_MOBS_SPAWN, BlockTags.NETHER_SURFACE_BLOCK, BlockTags.CHAINLINK_FENCES_CONNECT, BlockTags.MINEABLE_BY_PICKAXE); + .withSound(BlockSounds.STONE).withHardness(2.0F).withBlastResistance(10F) + .withTags(BlockTags.CAVES_CUT_THROUGH, BlockTags.NETHER_MOBS_SPAWN, BlockTags.NETHER_SURFACE_BLOCK, BlockTags.CHAINLINK_FENCES_CONNECT, BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CAVES_CUT_THROUGH); public static final Block COBBLE_GLOOMSTONE = register("cobble.gloomstone", "minecraft:block/cobble_gloomstone", 1033, (b) -> new BlockLogicCobble(b, Materials.GLOOMSTONE, () -> null)) .withSound(BlockSounds.STONE).withHardness(2.0F).withBlastResistance(10F) - .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT); + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT, BlockTags.CAVES_CUT_THROUGH); public static final Block BRICK_GLOOMSTONE = register("brick.gloomstone", "minecraft:block/brick_gloomstone", 1034, (b) -> new BlockLogic(b, Materials.GLOOMSTONE)) - .withSound(BlockSounds.STONE).withHardness(1.5F).withBlastResistance(10F) + .withSound(BlockSounds.STONE).withHardness(2.0F).withBlastResistance(10F) .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT); public static final @NotNull Block SLAB_GLOOMSTONE_POLISHED = register("slab.gloomstone.carved", "minecraft:block/slab_gloomstone_carved", 1035, (BlockLogicSupplier)b -> new BlockLogicSlab(b, Blocks.GLOOMSTONE_CARVED)) - .withSound(BlockSounds.STONE).withHardness(1.5F).withBlastResistance(10F) + .withSound(BlockSounds.STONE).withHardness(2.0F).withBlastResistance(10F) .withTags(BlockTags.MINEABLE_BY_PICKAXE); public static final @NotNull Block SLAB_COBBLE_GLOOMSTONE = register("slab.cobble.gloomstone", "minecraft:block/slab_cobble_gloomstone", 1036, (BlockLogicSupplier)b -> new BlockLogicSlab(b, Blocks.COBBLE_GLOOMSTONE)) - .withSound(BlockSounds.STONE).withHardness(1.5F).withBlastResistance(10F) + .withSound(BlockSounds.STONE).withHardness(2.0F).withBlastResistance(10F) .withTags(BlockTags.MINEABLE_BY_PICKAXE); public static final @NotNull Block SLAB_BRICK_GLOOMSTONE = register("slab.brick.gloomstone", "minecraft:block/slab_brick_gloomstone", 1037, (BlockLogicSupplier)b -> new BlockLogicSlab(b, Blocks.BRICK_GLOOMSTONE)) - .withSound(BlockSounds.STONE).withHardness(1.5F).withBlastResistance(10F) + .withSound(BlockSounds.STONE).withHardness(2.0F).withBlastResistance(10F) .withTags(BlockTags.MINEABLE_BY_PICKAXE); + public static final @NotNull Block STAIRS_COBBLE_GLOOMSTONE = register("stairs.cobble.gloomstone", "minecraft:block/stairs_cobble_gloomstone", 1038, (BlockLogicSupplier)b -> new BlockLogicStairs(b, Blocks.COBBLE_GLOOMSTONE)) .withSound(BlockSounds.STONE).withHardness(1.5F).withBlastResistance(10F).withLitInteriorSurface(true) .withTags(BlockTags.MINEABLE_BY_PICKAXE); @@ -1397,6 +1404,10 @@ public final class Blocks { .withSound(BlockSounds.STONE).withHardness(1.5F).withDisabledNeighborNotifyOnMetadataChange() .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.CHAINLINK_FENCES_CONNECT, BlockTags.PREVENT_MOB_SPAWNS); + public static final @NotNull Block STAIRS_BRICK_RUBYGLASS = register("stairs.brick.rubyglass", "minecraft:block/stairs_brick_rubyglass", 1048, (BlockLogicSupplier) b -> new BlockLogicStairs(b, Blocks.BRICK_RUBYGLASS)) + .withSound(BlockSounds.CRYSTAL).withOverrideColor(MaterialColor.rubyglass).withLitInteriorSurface(true) + .withTags(BlockTags.MINEABLE_BY_PICKAXE); + public static final @NotNull Block STAIRS_BRICK_DIAMOND = register("stairs.brick.diamond", "minecraft:block/stairs_brick_diamond", 1049, (BlockLogicSupplier)b -> new BlockLogicStairs(b, Blocks.BRICK_DIAMOND)) .withSound(BlockSounds.PERMAFROST).withDisabledNeighborNotifyOnMetadataChange().withLitInteriorSurface(true) .withTags(BlockTags.MINEABLE_BY_PICKAXE); @@ -1419,10 +1430,92 @@ public final class Blocks { .withSound(BlockSounds.PERMAFROST).withDisabledNeighborNotifyOnMetadataChange().withLitInteriorSurface(true) .withTags(BlockTags.MINEABLE_BY_PICKAXE); - public static final @NotNull Block FLOWSTONE = register("flowstone", "minecraft:block/flowstone", 1060, BlockLogicFlowstone::new) - .withSound(BlockSounds.STONE).withHardness(1.5F).withDisabledNeighborNotifyOnMetadataChange() + public static final @NotNull Block BOULDER_MAGMATIC = register("boulder.magmatic", "minecraft:block/boulder_magmatic", 1060, BlockLogicBoulderMagmatic::new) + .withHardness(1.0F).withLitInteriorSurface(true).setTicking(true) + .withTags(BlockTags.BROKEN_BY_FLUIDS, BlockTags.MINEABLE_BY_PICKAXE); + public static final @NotNull Block BOULDER_SULFURIC = register("boulder.sulfuric", "minecraft:block/boulder_sulfuric", 1061, BlockLogicBoulderSulfuric::new) + .withHardness(1.0F).withLitInteriorSurface(true).setTicking(true) + .withTags(BlockTags.BROKEN_BY_FLUIDS, BlockTags.MINEABLE_BY_PICKAXE, BlockTags.SULFURIC_FIRE_OVERLAY_SOURCE); + + public static final @NotNull Block FLUID_ACID_FLOWING = register("fluid.acid.flowing", "minecraft:block/fluid_acid_flowing", 1062, (BlockLogicSupplier) b -> new BlockLogicFluidFlowing(b, Materials.ACID, new FluidAcid(), Blocks.FLUID_ACID_STILL)) + .withHardness(100.0F).withLitInteriorSurface(true).withDisabledStats().withDisabledNeighborNotifyOnMetadataChange() + .withTags(BlockTags.PLACE_OVERWRITES, BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.IS_ACID); + public static final @NotNull Block FLUID_ACID_STILL = register("fluid.acid.still", "minecraft:block/fluid_acid_still", 1063, (BlockLogicSupplier) b -> new BlockLogicFluidStill(b, Materials.ACID, new FluidAcid(), Blocks.FLUID_ACID_FLOWING)) + .withHardness(100.0F).withLitInteriorSurface(true).withDisabledStats().withDisabledNeighborNotifyOnMetadataChange().setStatParent(() -> FLUID_ACID_FLOWING) + .withTags(BlockTags.PLACE_OVERWRITES, BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.IS_ACID); + + public static final Block EMBER = register("ember", "minecraft:block/ember", 1065, block -> new BlockLogicEmber(block, Materials.STONE)) + .withHardness(1.0f).withOverrideColor(MaterialColor.paintedBlack).withLightEmission(5) + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NETHER_SURFACE_BLOCK, BlockTags.NETHER_MOBS_SPAWN, BlockTags.CAVES_CUT_THROUGH); + + public static final Block SLATE_CARVED = register("slate.carved", "minecraft:block/slate_carved", 1070, block -> new BlockLogic(block, Materials.SLATE)) + .withSound(BlockSounds.STONE).withHardness(1.0F).withBlastResistance(10.0F).withDisabledStats() + .withTags(BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT, BlockTags.NETHER_MOBS_SPAWN); + public static final Block SLAB_SLATE_POLISHED = register("slab.slate.carved", "minecraft:block/slab_slate_carved", 1071, block -> new BlockLogicSlab(block, SLATE_CARVED)) + .withSound(BlockSounds.STONE) .withTags(BlockTags.MINEABLE_BY_PICKAXE); + public static final Block LOG_SCORCHED = register("log.scorched", "minecraft:block/log_scorched", 1072, BlockLogicLog::new) + .withSound(BlockSounds.WOOD).withHardness(1.5F) + .withTags(BlockTags.FENCES_CONNECT, BlockTags.MINEABLE_BY_AXE); + + public static final Block STATUE_SLATE_LOWER = register("statue.slate.lower", "minecraft:block/statue_slate_lower", 1075, (BlockLogicSupplier) block -> new BlockLogicStatue(block, Materials.SLATE, true, () -> Items.STATUE_SLATE)) + .withSound(BlockSounds.STONE).withHardness(1.5F).setStatParent(() -> Items.STATUE_SLATE) + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU); + public static final Block STATUE_SLATE_UPPER = register("statue.slate.upper", "minecraft:block/statue_slate_upper", 1076, (BlockLogicSupplier) block -> new BlockLogicStatue(block, Materials.SLATE, false, () -> Items.STATUE_SLATE)) + .withSound(BlockSounds.STONE).withHardness(1.5F).setStatParent(() -> Items.STATUE_SLATE) + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU); + public static final Block STATUE_PERMAFROST_LOWER = register("statue.permafrost.lower", "minecraft:block/statue_permafrost_lower", 1077, (BlockLogicSupplier) block -> new BlockLogicStatue(block, Materials.PERMAFROST, true, () -> Items.STATUE_PERMAFROST)) + .withSound(BlockSounds.PERMAFROST).withHardness(1.5F).setStatParent(() -> Items.STATUE_PERMAFROST) + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU); + public static final Block STATUE_PERMAFROST_UPPER = register("statue.permafrost.upper", "minecraft:block/statue_permafrost_upper", 1078, (BlockLogicSupplier) block -> new BlockLogicStatue(block, Materials.PERMAFROST, false, () -> Items.STATUE_PERMAFROST)) + .withSound(BlockSounds.PERMAFROST).withHardness(1.5F).setStatParent(() -> Items.STATUE_PERMAFROST) + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU); + public static final Block STATUE_NETHERRACK_LOWER = register("statue.netherrack.lower", "minecraft:block/statue_netherrack_lower", 1079, (BlockLogicSupplier) block -> new BlockLogicStatue(block, Materials.NETHERRACK, true, () -> Items.STATUE_NETHERRACK)) + .withSound(BlockSounds.STONE).withHardness(1.5F).setStatParent(() -> Items.STATUE_NETHERRACK) + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU); + public static final Block STATUE_NETHERRACK_UPPER = register("statue.netherrack.upper", "minecraft:block/statue_netherrack_upper", 1080, (BlockLogicSupplier) block -> new BlockLogicStatue(block, Materials.NETHERRACK, false, () -> Items.STATUE_NETHERRACK)) + .withSound(BlockSounds.STONE).withHardness(1.5F).setStatParent(() -> Items.STATUE_NETHERRACK) + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU); + public static final Block STATUE_GLOOMSTONE_LOWER = register("statue.gloomstone.lower", "minecraft:block/statue_gloomstone_lower", 1081, (BlockLogicSupplier) block -> new BlockLogicStatue(block, Materials.GLOOMSTONE, true, () -> Items.STATUE_GLOOMSTONE)) + .withSound(BlockSounds.STONE).withHardness(1.5F).setStatParent(() -> Items.STATUE_GLOOMSTONE) + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU); + public static final Block STATUE_GLOOMSTONE_UPPER = register("statue.gloomstone.upper", "minecraft:block/statue_gloomstone_upper", 1082, (BlockLogicSupplier) block -> new BlockLogicStatue(block, Materials.GLOOMSTONE, false, () -> Items.STATUE_GLOOMSTONE)) + .withSound(BlockSounds.STONE).withHardness(1.5F).setStatParent(() -> Items.STATUE_GLOOMSTONE) + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU); + + public static final Block BRIMSAND = register("brimsand", "minecraft:block/brimsand", 1085, (b) -> new BlockLogic(b, Materials.SAND)) + .withSound(BlockSounds.SAND).withHardness(0.7F) + .withTags(BlockTags.MINEABLE_BY_SHOVEL, BlockTags.CAVES_CUT_THROUGH, BlockTags.NETHER_MOBS_SPAWN, BlockTags.NETHER_SURFACE_BLOCK, BlockTags.INFINITE_BURN_SULFURIC); + public static final Block BRIMSTONE = register("brimstone", "minecraft:block/brimstone", 1086, block -> new BlockLogicBrimstone(block, Materials.STONE)) + .withSound(BlockSounds.STONE).withHardness(1.8F).withOverrideColor(MaterialColor.paintedBlack) + .withTags(BlockTags.CAVES_CUT_THROUGH, BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT, BlockTags.NETHER_MOBS_SPAWN, BlockTags.NETHER_SURFACE_BLOCK, BlockTags.INFINITE_BURN_SULFURIC); + public static final Block SLAB_BRIMSTONE = register("slab.brimstone", "minecraft:block/slab_brimstone", 1087, block -> new BlockLogicSlab(block, BRIMSTONE)) + .withSound(BlockSounds.STONE).withDisabledNeighborNotifyOnMetadataChange().withLitInteriorSurface(true).withOverrideColor(MaterialColor.paintedBlack) + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.INFINITE_BURN_SULFURIC); + public static final Block STAIRS_BRIMSTONE = register("stairs.brimstone", "minecraft:block/stairs_brimstone", 1088, block -> new BlockLogicStairs(block, BRIMSTONE)) + .withSound(BlockSounds.STONE).withDisabledNeighborNotifyOnMetadataChange().withLitInteriorSurface(true).withOverrideColor(MaterialColor.paintedBlack) + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.INFINITE_BURN_SULFURIC); + public static final Block BRICK_BRIMSTONE = register("brick.brimstone", "minecraft:block/brick_brimstone", 1089, block -> new BlockLogicBrimstone(block, Materials.STONE)) + .withSound(BlockSounds.STONE).withHardness(1.8F).withOverrideColor(MaterialColor.paintedBlack) + .withTags(BlockTags.CAVES_CUT_THROUGH, BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT, BlockTags.NETHER_MOBS_SPAWN, BlockTags.NETHER_SURFACE_BLOCK, BlockTags.INFINITE_BURN_SULFURIC); + public static final Block SLAB_BRICK_BRIMSTONE = register("slab.brick.brimstone", "minecraft:block/slab_brick_brimstone", 1090, block -> new BlockLogicSlab(block, BRICK_BRIMSTONE)) + .withSound(BlockSounds.STONE).withDisabledNeighborNotifyOnMetadataChange().withLitInteriorSurface(true).withOverrideColor(MaterialColor.paintedBlack) + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.INFINITE_BURN_SULFURIC); + public static final Block STAIRS_BRICK_BRIMSTONE = register("stairs.brick.brimstone", "minecraft:block/stairs_brick_brimstone", 1091, block -> new BlockLogicStairs(block, BRICK_BRIMSTONE)) + .withSound(BlockSounds.STONE).withDisabledNeighborNotifyOnMetadataChange().withLitInteriorSurface(true).withOverrideColor(MaterialColor.paintedBlack) + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.INFINITE_BURN_SULFURIC); + public static final @NotNull Block BRIMTHAW = register("brimthaw", "minecraft:block/brimthaw", 1092, BlockLogicBrimthaw::new) + .withSound(BlockSounds.STONE).withHardness(1.25F).withBlastResistance(7F).withLightEmission(10).withOverrideColor(MaterialColor.paintedYellow) + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.INFINITE_BURN_SULFURIC, BlockTags.SULFURIC_FIRE_OVERLAY_SOURCE); + + public static final Block SULFUR = register("sulfur", "minecraft:block/sulfur", 1098, BlockLogicSulfur::new) + .withSound(BlockSounds.SAND).withHardness(0.5f).withOverrideColor(MaterialColor.paintedYellow) + .withTags(BlockTags.MINEABLE_BY_SHOVEL, BlockTags.NETHER_SURFACE_BLOCK, BlockTags.NETHER_MOBS_SPAWN, BlockTags.CAVES_CUT_THROUGH, BlockTags.INFINITE_BURN_SULFURIC); + public static final Block SULFUR_HARDENED = register("sulfur_hardened", "minecraft:block/sulfur_hardened", 1099, BlockLogicSulfurHardened::new) + .withSound(BlockSounds.SAND).withHardness(0.5f).withOverrideColor(MaterialColor.paintedYellow) + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NETHER_SURFACE_BLOCK, BlockTags.NETHER_MOBS_SPAWN, BlockTags.CAVES_CUT_THROUGH, BlockTags.INFINITE_BURN_SULFURIC); + public static Block register(String key, String namespaceId, int id, BlockLogicSupplier logicSupplier) { Block container = new Block<>(id, key, namespaceId, logicSupplier); diff --git a/game/core/src/main/java/net/minecraft/core/block/FluidAcid.java b/game/core/src/main/java/net/minecraft/core/block/FluidAcid.java new file mode 100644 index 000000000..dc9189408 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/block/FluidAcid.java @@ -0,0 +1,107 @@ +package net.minecraft.core.block; + +import net.minecraft.core.block.material.Material; +import net.minecraft.core.block.material.Materials; +import net.minecraft.core.enums.EnumDropCause; +import net.minecraft.core.sound.SoundCategory; +import net.minecraft.core.world.LevelListener; +import net.minecraft.core.world.World; +import net.minecraft.core.world.type.tag.WorldTypeTags; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; + +import java.util.Random; + +public class FluidAcid implements Fluid { + public FluidAcid() { + } + + public int tickDelay() { + return 40; + } + + @Override + public void animationTick(@NotNull BlockLogicFluid logicFluid, @NotNull World world, @NotNull TilePosc tilePos, @NotNull Random rand) { + int data = world.getBlockData(tilePos) & 15; + TilePos queryPos = new TilePos(); + + boolean isBottom = world.isBlockOpaqueCube(tilePos.down(queryPos)); + if (rand.nextInt(64) == 0) { + world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, (float) tilePos.x() + 0.5F, (float) tilePos.y() + 0.5F, (float) tilePos.z() + 0.5F, + "random.fizz", rand.nextFloat() * 0.125F, rand.nextFloat() + 0.5F); + } + + if (rand.nextInt(64) == 0) { + world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, (float) tilePos.x() + 0.5F, (float) tilePos.y() + 0.5F, (float) tilePos.z() + 0.5F, + "tile.acidbubble", rand.nextFloat() * 0.25F + 0.25F, rand.nextFloat() - 1.0F); + } + + if ((isBottom || rand.nextInt(16) == 0) && data == 0 && rand.nextInt(2) == 0) { + world.spawnParticle("acidBoiling", (double) tilePos.x() + Math.random(), (float) tilePos.y() + 0.05F, (double) tilePos.z() + Math.random(), 0.0F, 0.0F, 0.0F, 0, false); + } + + if (rand.nextInt(4) == 0 && world.getBlockType(tilePos.down(new TilePos())).solid() && !world.getBlockType(tilePos.down(new TilePos()).down()).solid()) { + float off1 = rand.nextFloat() * 0.9F + 0.05F; + float off2 = rand.nextFloat() * 0.9F + 0.05F; + float lOff = 0.01F; + world.spawnParticle("acidDrip", (float) tilePos.x() + off1, (float) (tilePos.y() - 1) - lOff, (float) tilePos.z() + off2, 0.0F, 0.0F, 0.0F, 0, false); + } + + } + + @Override + public boolean checkForHarden(@NotNull BlockLogicFluid logicFluid, @NotNull World world, @NotNull TilePosc tilePos, @NotNull Material encountered) { + if (encountered == Materials.LAVA || encountered == Materials.WATER) { + final int data = world.getBlockData(tilePos) & 15; + final boolean netherWorld = world.getWorldType().hasTag(WorldTypeTags.NETHER); + if (netherWorld) { + if (data == 0) { + world.setBlockTypeNotify(tilePos, Blocks.BRIMTHAW); + } else { + world.setBlockTypeNotify(tilePos, Blocks.BRIMSTONE); + } + } else { + if (data == 0) { + world.setBlockTypeNotify(tilePos, Blocks.SULFUR); + } else { + world.setBlockTypeNotify(tilePos, Blocks.SULFUR_HARDENED); + } + } + + world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, (float) tilePos.x() + 0.5F, (float) tilePos.y() + 0.5F, (float) tilePos.z() + 0.5F, "random.fizz", 0.5F, 2.6F + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.8F); + + for (int i = 0; i < 8; ++i) { + world.spawnParticle("largesmoke", (double) tilePos.x() + Math.random(), (double) tilePos.y() + 1.01, (double) tilePos.z() + Math.random(), 0.0F, 0.0F, 0.0F, 0, false); + } + return true; + } else { + return false; + } + } + + public boolean shouldTick() { + return false; + } + + public void updateTickStill(@NotNull BlockLogicFluid logicFluid, @NotNull World world, @NotNull TilePosc tilePos, @NotNull Random rand) { + } + + public byte getFlowDecayMod(@NotNull BlockLogicFluid logicFluid, @NotNull World world, @NotNull TilePosc tilePos) { + return 2; + } + + public boolean canBecomeSource(@NotNull BlockLogicFluid logicFluid, @NotNull World world, @NotNull TilePosc tilePos, @NotNull Random rand) { + return false; + } + + public void onFlowIntoBlock(@NotNull BlockLogicFluid logicFluid, @NotNull World world, @NotNull TilePos tilePos, int meta) { + world.getBlockType(tilePos).dropWithCause(world, EnumDropCause.WORLD, tilePos, world.getBlockData(tilePos), null, null); + world.playBlockEvent(tilePos, LevelListener.EVENT_ACID_SPREAD, 0); + } + + public boolean canSpreadTo(@NotNull BlockLogicFluid logicFluid, @NotNull World world, @NotNull TilePos tilePos, @NotNull Material material) { + return material != Materials.LAVA && material != Materials.WATER; + } +} + diff --git a/game/core/src/main/java/net/minecraft/core/block/FluidLava.java b/game/core/src/main/java/net/minecraft/core/block/FluidLava.java index d307bf7c6..fc8367a19 100644 --- a/game/core/src/main/java/net/minecraft/core/block/FluidLava.java +++ b/game/core/src/main/java/net/minecraft/core/block/FluidLava.java @@ -59,6 +59,10 @@ public class FluidLava } } + BlockLogicFluid.fizz(world, tilePos); + return true; + } else if (encountered == Blocks.FLUID_ACID_STILL.getMaterial()) { + world.setBlockTypeNotify(tilePos, Blocks.SULFUR_HARDENED); BlockLogicFluid.fizz(world, tilePos); return true; } @@ -125,6 +129,6 @@ public class FluidLava @Override public boolean canSpreadTo(final @NotNull BlockLogicFluid logicFluid, final @NotNull World world, final @NotNull TilePos tilePos, final @NotNull Material material) { - return material != Materials.LAVA; + return material != Materials.WATER && material != Blocks.FLUID_ACID_STILL.getMaterial(); } } diff --git a/game/core/src/main/java/net/minecraft/core/block/FluidWater.java b/game/core/src/main/java/net/minecraft/core/block/FluidWater.java index 4460b1a87..ccbd936ef 100644 --- a/game/core/src/main/java/net/minecraft/core/block/FluidWater.java +++ b/game/core/src/main/java/net/minecraft/core/block/FluidWater.java @@ -61,6 +61,10 @@ public class FluidWater } BlockLogicFluid.fizz(world, tilePos); return true; + } else if (encountered == Blocks.FLUID_ACID_STILL.getMaterial()) { + world.setBlockTypeNotify(tilePos, Blocks.SULFUR_HARDENED); + BlockLogicFluid.fizz(world, tilePos); + return true; } return false; } @@ -92,6 +96,6 @@ public class FluidWater @Override public boolean canSpreadTo(final @NotNull BlockLogicFluid logicFluid, final @NotNull World world, final @NotNull TilePos tilePos, final @NotNull Material material) { - return material != Materials.LAVA; + return material != Materials.LAVA && material != Blocks.FLUID_ACID_STILL.getMaterial(); } } diff --git a/game/core/src/main/java/net/minecraft/core/block/material/Materials.java b/game/core/src/main/java/net/minecraft/core/block/material/Materials.java index bdd7e38ad..7b24e0757 100644 --- a/game/core/src/main/java/net/minecraft/core/block/material/Materials.java +++ b/game/core/src/main/java/net/minecraft/core/block/material/Materials.java @@ -51,6 +51,6 @@ public final class Materials { public static final @NotNull Material PISTON = new Material(MaterialColor.stone); public static final @NotNull Material MOSS = new Material(MaterialColor.grass).flammable().notAlwaysDestroyable(); public static final @NotNull Material WOOD_WET = (new Material(MaterialColor.grass).setConductivity(Material.LIGHTNING_LIGHT_CONDUCTOR)); - + public static final @NotNull Material ACID = new MaterialLiquid(MaterialColor.paintedYellow).setConductivity(5).destroyOnPush(); private Materials() { } } diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java index 95d6d5b68..cb836acbe 100644 --- a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java +++ b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java @@ -36,6 +36,7 @@ import static net.minecraft.core.block.piston.PistonCommon.*; public class BlockLogicPistonHead extends BlockLogic implements ICarrySource { // "Good lord. This really is our most NSFW update" -- Jonk + // "Daaayyymmnn boy! He thick boy! That's a thick ass boy, DAYMN!" -- Melon final double headThickness, shaftThickness; public BlockLogicPistonHead(final Block block, final double headThickness, final double shaftThickness) { diff --git a/game/core/src/main/java/net/minecraft/core/block/tag/BlockTags.java b/game/core/src/main/java/net/minecraft/core/block/tag/BlockTags.java index 5f4b11937..ea1db34c2 100644 --- a/game/core/src/main/java/net/minecraft/core/block/tag/BlockTags.java +++ b/game/core/src/main/java/net/minecraft/core/block/tag/BlockTags.java @@ -68,6 +68,10 @@ public abstract class BlockTags * derived block has the properties of lava. */ public static final Tag> IS_LAVA = Tag.of("is_lava"); + /** + * derived block has the properties of acid. + */ + public static final Tag> IS_ACID = Tag.of("is_acid"); /** * {@link BlockLogicFlower BlockFlower}-derived blocks can be placed on this block. */ @@ -150,9 +154,17 @@ public abstract class BlockTags */ public static final Tag> INFINITE_BURN = Tag.of("infinite_burn"); /** - * Block allows fire to burn forever on it {@link BlockLogicFire BlockFire} + * Block allows fire to burn forever on it {@link net.minecraft.core.block.BlockLogicFireCold BlockFireCold} */ public static final Tag> INFINITE_BURN_COLD = Tag.of("infinite_burn_cold"); + /** + * Block allows fire to burn forever on it {@link net.minecraft.core.block.BlockLogicFireSulfuric BlockFireSulfuric} + */ + public static final Tag> INFINITE_BURN_SULFURIC = Tag.of("infinite_burn_sulfuric"); + /** + * Set entity on sulfuric fire instead of Normal Fire + */ + public static final Tag> SULFURIC_FIRE_OVERLAY_SOURCE = Tag.of("sulfuric_fire_overlay_source"); /** * Block is broken on contact with an {@link EntityBoat EntityBoat} */ diff --git a/game/core/src/main/java/net/minecraft/core/data/gamerule/GameRules.java b/game/core/src/main/java/net/minecraft/core/data/gamerule/GameRules.java index d6199334e..509fb9c7f 100644 --- a/game/core/src/main/java/net/minecraft/core/data/gamerule/GameRules.java +++ b/game/core/src/main/java/net/minecraft/core/data/gamerule/GameRules.java @@ -1,6 +1,7 @@ package net.minecraft.core.data.gamerule; import net.minecraft.core.data.registry.Registries; +import net.minecraft.core.entity.Entity; public abstract class GameRules { @@ -16,6 +17,7 @@ public abstract class GameRules public static GameRuleBoolean DO_WEATHER_CYCLE = register(new GameRuleBoolean("doWeatherCycle", "gamerule.do_weather_cycle", true)); public static GameRuleBoolean DO_FIRE_SPREAD = register(new GameRuleBoolean("doFireSpread", "gamerule.do_fire_spread", true)); public static GameRuleBoolean INSTANT_HEALING = register(new GameRuleBoolean("instantHealing", "gamerule.instant_healing", false)); + public static GameRuleInteger ACID_MELT_RATE = register(new GameRuleInteger("acidMeltRate", "gamerule.acid_melt_rate", Entity.FIRE_DAMAGE_INTERVAL_TICKS)); public static GameRuleInteger RANDOM_TICK_SPEED = register(new GameRuleInteger("randomTickSpeed", "gamerule.random_tick_speed", 4)); public static GameRuleInteger ITEM_DESPAWN_DELAY = register(new GameRuleInteger("itemDespawnDelay", "gamerule.item_despawn_delay", 12000)); public static GameRuleInteger DROPPED_ITEM_DESPAWN_DELAY = register(new GameRuleInteger("droppedItemDespawnDelay", "gamerule.dropped_item_despawn_delay", 12000)); diff --git a/game/core/src/main/java/net/minecraft/core/entity/Entity.java b/game/core/src/main/java/net/minecraft/core/entity/Entity.java index 0f22991d0..8e7cf0baa 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/Entity.java +++ b/game/core/src/main/java/net/minecraft/core/entity/Entity.java @@ -19,6 +19,7 @@ import net.minecraft.core.enums.EnumBlockSoundEffectType; import net.minecraft.core.item.ItemStack; import net.minecraft.core.lang.I18n; import net.minecraft.core.util.collection.NamespaceID; +import net.minecraft.core.data.tag.Tag; import net.minecraft.core.util.helper.*; import net.minecraft.core.world.ICarriable; import net.minecraft.core.world.IVehicle; @@ -37,19 +38,30 @@ import java.util.List; import java.util.Random; public abstract class Entity - implements IVehicle { + implements IVehicle { + + // Util + protected @NotNull Random random = new Random(); + public @NotNull World world; + public static final int DATA_SHARED_FLAGS_ID = 0; public static final int FLAG_ONFIRE = 0; public static final int FLAG_SNEAKING = 1; public static final int FLAG_RIDING = 2; public static final int FLAG_SPRINTING = 3; + + // Misc/IDK + public boolean slide = true; + public boolean removed = false; + public boolean hadNicknameSet; + public boolean blocksBuilding = false; + public double viewScale = 1.0D; private static int entityCounter = 0; public int id = entityCounter++; - public double viewScale = 1.0D; - public boolean blocksBuilding = false; public @Nullable Entity passenger; - public @Nullable IVehicle vehicle; - public @NotNull World world; + private int soundCooldown; + + // Position public double xo; public double yo; public double zo; @@ -63,60 +75,89 @@ public abstract class Entity public float xRot; public float yRotO; public float xRotO; - public float pushTime; - public int pushesThisTick; + public int serverPosX; + public int serverPosY; + public int serverPosZ; + private final @NotNull TilePos workingPos1 = new TilePos(); + private final @NotNull TilePos workingPos2 = new TilePos(); + + // Collision/Hitbox public final @NotNull AABBd bb = new AABBd(); - public boolean onGround = false; - public boolean horizontalCollision; - public boolean verticalCollision; - public boolean collision = false; - public boolean hurtMarked = false; - public boolean hadNicknameSet; - public boolean stuckInCobweb; - public boolean stuckInSpikes; - public boolean slide = true; - public boolean removed = false; public float heightOffset = 0.0F; public float bbWidth = 0.6F; public float bbHeight = 1.825F; + public boolean horizontalCollision; + public boolean verticalCollision; + public boolean collision = false; + public boolean onGround = false; + private final @NotNull AABBd workingBox1 = new AABBd(); + private final @NotNull AABBd workingBox2 = new AABBd(); + private final @NotNull AABBd workingBox3 = new AABBd(); + private final @NotNull AABBd workingBox4 = new AABBd(); + + // Movement/Physics + public boolean noPhysics = false; + public float pushthrough = 0.0F; public float walkDistO = 0.0F; public float walkDist = 0.0F; public float fallDistance = 0.0F; private int nextStep = 1; public float ySlideOffset = 0.0F; - public float footSize = 0.0F; - public boolean noPhysics = false; - public float pushthrough = 0.0F; - protected @NotNull Random random = new Random(); - public int tickCount; + public boolean stuckInCobweb; + public boolean stuckInSpikes; + public float pushTime; + public int pushesThisTick; + public int acidJumpCooldown = 0; + + // Vehicle + public @Nullable IVehicle vehicle; + private double entityRiderPitchDelta; + private double entityRiderYawDelta; + public boolean turnWithVehicle = true; + + // Damage + public int heartsFlashTime = 0; + public boolean hurtMarked = false; + + // Water + public int airSupply = 300; + protected int airMaxSupply = 300; + protected boolean wasInWater = false; + + // Fire + public static final int FIRE_DAMAGE_INTERVAL_TICKS = 20; public int fireImmuneTicks = 1; public int remainingFireTicks = 0; public int maxFireTicks; - private int soundCooldown; - protected int airMaxSupply = 300; - protected boolean wasInWater = false; - public int heartsFlashTime = 0; - public int airSupply = 300; - private boolean firstTick = true; protected boolean fireImmune; - protected final @NotNull SynchedEntityData entityData = new SynchedEntityData(); + public Block activeFireBlock = Blocks.FIRE; + + // Visual public float entityBrightness = 0.0F; - private double entityRiderPitchDelta; - private double entityRiderYawDelta; + public boolean ignoreFrustumCheck; + + // Chunk public boolean addedToChunk = false; public int chunkCoordX; public int chunkCoordY; public int chunkCoordZ; - public int serverPosX; - public int serverPosY; - public int serverPosZ; - public boolean ignoreFrustumCheck; - public boolean isWalking = false; - protected boolean muteStepSounds = false; + + // Speed public float speed; public float flySpeed; + + // Walk + public boolean isWalking = false; + protected boolean muteStepSounds = false; + public float footSize = 0.0F; + + // Tick + private boolean firstTick = true; + public int tickCount; + + // Data public boolean sendAdditionalData = false; - public boolean turnWithVehicle = true; + protected final @NotNull SynchedEntityData entityData = new SynchedEntityData(); public Entity(final @NotNull World world) { this.world = world; @@ -270,7 +311,7 @@ public abstract class Entity this.remainingFireTicks = 0; } } else { - if (this.remainingFireTicks % 20 == 0) { + if (this.remainingFireTicks % FIRE_DAMAGE_INTERVAL_TICKS == 0) { hurt(null, 1, DamageType.FIRE); } this.remainingFireTicks--; @@ -348,17 +389,22 @@ public abstract class Entity hurt(null, 4, DamageType.FIRE); this.remainingFireTicks = 600; this.maxFireTicks = this.remainingFireTicks; + this.activeFireBlock = Blocks.FIRE; } } - public void fireHurt() { + public void fireHurt(Block fireSource) { if (!this.fireImmune) { hurt(null, 1, DamageType.FIRE); this.remainingFireTicks = 300; this.maxFireTicks = this.remainingFireTicks; + this.activeFireBlock = fireSource; } } + public void fireHurt() { + this.fireHurt(Blocks.FIRE); + } public void outOfWorld() { remove(); } @@ -411,17 +457,19 @@ public abstract class Entity this.stuckInSpikes = false; } + double oldXd = xd; double oldYd = yd; double oldZd = zd; - AABBd bbCopy = new AABBd(this.bb); + workingBox3.set(this.bb); double bbWidth = this.bb.maxX - this.bb.minX - 0.05; if (isSneaking()) { // Edge safety behavior - if (xd != 0.0) { - AABBd floor = new AABBd(this.bb.minX, this.bb.minY - 1.0, this.bb.minZ, this.bb.maxX, this.bb.minY, this.bb.maxZ); - MathHelper.aabbExpand(floor, xd, 0.0, 0.0, floor); - List collidingBoxes = this.world.getCubes(this, floor); + if (zd != 0.0) { + workingBox1.setMin(this.bb.minX, this.bb.minY - 1.0, this.bb.minZ); + workingBox1.setMax(this.bb.maxX, this.bb.minY, this.bb.maxZ); + MathHelper.aabbExpand(workingBox1, 0.0, 0.0, zd, workingBox1); + List collidingBoxes = this.world.getCubes(this, workingBox1); if (!collidingBoxes.isEmpty()) { double limitX = 0.0; for (int i = 0; i < collidingBoxes.size(); i++) { @@ -462,7 +510,18 @@ public abstract class Entity } } - List cubes = this.world.getCubes(this, MathHelper.aabbExpand(this.bb, xd, yd, zd, new AABBd())); + List cubes = this.world.getCubes(this, MathHelper.aabbExpand(this.bb, xd, yd, zd, workingBox2)); + List solidEntities = this.world.getEntitiesWithinAABBExcludingEntity(this, MathHelper.aabbExpand(this.bb, xd, yd, zd, workingBox2)); + + for (int i = 0; i < solidEntities.size(); i++) { + Entity solidEnt = solidEntities.get(i); + + if (solidEnt.hasCollision() && solidEnt.getCollisionAABB() != null) { + if (this.collidesWith(solidEnt) && solidEnt.collidesWith(this)) { + cubes.add(solidEnt.getCollisionAABB()); + } + } + } // Check collision on Y Axis for (int i = 0; i < cubes.size(); i++) { @@ -504,9 +563,11 @@ public abstract class Entity xd = oldXd; yd = this.footSize; zd = oldZd; - AABBd aabbCopy = new AABBd(this.bb); - this.bb.set(bbCopy); - cubes = this.world.getCubes(this, MathHelper.aabbExpand(this.bb, xd, 0.0, zd, new AABBd())); + + workingBox4.set(this.bb); + + this.bb.set(workingBox3); + cubes = this.world.getCubes(this, MathHelper.aabbExpand(this.bb, xd, 0.0, zd, workingBox2)); for (int i = 0; i < cubes.size(); i++) { yd = MathHelper.aabbClipYCollide(cubes.get(i), this.bb, yd); } @@ -546,7 +607,7 @@ public abstract class Entity xd = oldX; yd = oldY; zd = oldZ; - this.bb.set(aabbCopy); + this.bb.set(workingBox4); } } //fix for entity jitter when blasted by cannonballs (can cause some client-side jitter when entity is under a ceiling. unsure exactly why) @@ -559,6 +620,7 @@ public abstract class Entity this.verticalCollision = oldYd != yd; this.onGround = oldYd != yd && oldYd < 0.0D; this.collision = this.horizontalCollision || this.verticalCollision; + checkOnWater(false); checkFallDamage(yd, this.onGround); if (oldXd != xd) { @@ -573,13 +635,13 @@ public abstract class Entity double d10 = this.x - d3; double d12 = this.z - d4; if (makeStepSound() && !isSneaking() && this.vehicle == null) { - this.walkDist += (double) MathHelper.sqrt(d10 * d10 + d12 * d12) * 0.6; + this.walkDist += (float) ((double) MathHelper.sqrt(d10 * d10 + d12 * d12) * 0.6); - // Tiny bounding box - AABBdc boundingBox = new AABBd(this.x - 0.01, this.bb.minY - 0.01, this.z - 0.01, this.x + 0.01, this.bb.minY + 0.01, this.z + 0.01); + workingBox1.setMin(this.x - 0.01, this.bb.minY - 0.01, this.z - 0.01); + workingBox1.setMax(this.x + 0.01, this.bb.minY + 0.01, this.z + 0.01); int blockX = MathHelper.floor(this.x); - int blockY = MathHelper.floor(boundingBox.minY()); + int blockY = MathHelper.floor(workingBox1.minY()); int blockZ = MathHelper.floor(this.z); Block blockWalkedOn = null; @@ -589,12 +651,9 @@ public abstract class Entity for (int z = blockZ - 1; z <= blockZ + 1; z++) { for (int y = blockY - 1; y < blockY + 1; y++) { Block block = this.world.getBlock(x, y, z); - if (block == null) { - continue; - } this.world.collidingBoundingBoxes.clear(); - block.getCollidingBoundingBoxes(this.world, x, y, z, boundingBox, this.world.collidingBoundingBoxes); + block.getCollidingBoundingBoxes(this.world, x, y, z, workingBox1, this.world.collidingBoundingBoxes); if (!this.world.collidingBoundingBoxes.isEmpty()) { blockWalkedOn = block; @@ -608,7 +667,7 @@ public abstract class Entity } // Check for snow layers - int blockYUp = MathHelper.floor(boundingBox.maxY()); + int blockYUp = MathHelper.floor(workingBox1.maxY()); Block blockAbove = this.world.getBlock(blockX, blockYUp, blockZ); if (blockAbove != null && blockAbove.hasTag(BlockTags.OVERRIDE_STEPSOUND)) { blockWalkedOn = blockAbove; @@ -650,7 +709,7 @@ public abstract class Entity } boolean inWaterOrRain = isInWaterOrRain(); - if (this.world.isBoundingBoxBurning(MathHelper.aabbInsetBoundingBox(this.bb, 0.001D, 0.001D, 0.001D, new AABBd()))) { + if (this.world.isBoundingBoxBurning(MathHelper.aabbInsetBoundingBox(this.bb, 0.001D, 0.001D, 0.001D, workingBox1))) { burn(1); if (!inWaterOrRain) { this.remainingFireTicks++; @@ -705,12 +764,17 @@ public abstract class Entity return null; } - protected void burn(int damage) { + protected void burn(int damage, Block fireSource) { if (!this.fireImmune) { hurt(null, damage, DamageType.FIRE); + this.activeFireBlock = fireSource; } } + protected void burn(int damage) { + this.burn(damage, this.activeFireBlock != null ? this.activeFireBlock : Blocks.FIRE); + } + protected void causeFallDamage(float distance) { if (this.passenger != null) { this.passenger.causeFallDamage(distance); @@ -725,17 +789,78 @@ public abstract class Entity return this.wasInWater; } + public boolean isInAcid() { + return this.world.isMaterialInBB(this.bb, Materials.ACID); + } + + + public boolean isBoundingBoxIntersectingBlock(final @NotNull Block target) { + return isAabbIntersectingBlock(this.bb, target); + } + + public boolean isBoundingBoxIntersectingBlockTag(final @NotNull Tag> tag) { + return isAabbIntersectingBlockTag(this.bb, tag); + } + + private boolean isAabbIntersectingBlock(final @NotNull AABBdc queryBb, final @NotNull Block target) { + final double inset = 0.001D; + final int minX = MathHelper.floor(queryBb.minX() + inset); + final int minY = MathHelper.floor(queryBb.minY() + inset); + final int minZ = MathHelper.floor(queryBb.minZ() + inset); + final int maxX = MathHelper.floor(queryBb.maxX() - inset); + final int maxY = MathHelper.floor(queryBb.maxY() - inset); + final int maxZ = MathHelper.floor(queryBb.maxZ() - inset); + if (!this.world.areBlocksLoaded(minX, minY, minZ, maxX, maxY, maxZ)) { + return false; + } + final TilePos p = new TilePos(); + for (p.x = minX; p.x <= maxX; p.x++) { + for (p.y = minY; p.y <= maxY; p.y++) { + for (p.z = minZ; p.z <= maxZ; p.z++) { + if (this.world.getBlockType(p) == target) { + return true; + } + } + } + } + return false; + } + + private boolean isAabbIntersectingBlockTag(final @NotNull AABBdc queryBb, final @NotNull Tag> tag) { + final double inset = 0.001D; + final int minX = MathHelper.floor(queryBb.minX() + inset); + final int minY = MathHelper.floor(queryBb.minY() + inset); + final int minZ = MathHelper.floor(queryBb.minZ() + inset); + final int maxX = MathHelper.floor(queryBb.maxX() - inset); + final int maxY = MathHelper.floor(queryBb.maxY() - inset); + final int maxZ = MathHelper.floor(queryBb.maxZ() - inset); + if (!this.world.areBlocksLoaded(minX, minY, minZ, maxX, maxY, maxZ)) { + return false; + } + final TilePos p = new TilePos(); + for (p.x = minX; p.x <= maxX; p.x++) { + for (p.y = minY; p.y <= maxY; p.y++) { + for (p.z = minZ; p.z <= maxZ; p.z++) { + if (Blocks.hasTag(this.world.getBlockType(p), tag)) { + return true; + } + } + } + } + return false; + } + public boolean checkAndHandleWater(boolean addVelocity) { return this.world.handleMaterialAcceleration(MathHelper.aabbInsetBoundingBox(this.bb/*.expand(0.0D, -0.4D, 0.0D)*/, 0.001D, 0.001D, 0.001D, new AABBd()), Materials.WATER, this, addVelocity); } public boolean isUnderLiquid(@NotNull Material material) { double headY = this.y + (double) getHeadHeight(); - TilePos tilePos = new TilePos(this.x, headY, this.z); - Block block = this.world.getBlockType(tilePos); - if (block != null && block.getMaterial() == material) { - float f = BlockLogicFluid.getHeight(this.world.getBlockData(tilePos)) - 0.2F; - float f1 = (float) (tilePos.y + 1) - f; + workingPos1.set(this.x, headY, this.z); + Block block = this.world.getBlockType(workingPos1); + if (block.getMaterial() == material) { + float f = BlockLogicFluid.getHeight(this.world.getBlockData(workingPos1)) - 0.2F; + float f1 = (float) (workingPos1.y + 1) - f; return headY < (double) f1; } else { return false; @@ -887,18 +1012,23 @@ public abstract class Entity return !(this.pushTime > 0.5f) || !((this.xd * this.xd + this.yd * this.yd + this.zd * this.zd) > 1) || !Block.hasLogicClass(block, BlockLogicPistonHead.class); // TODO horrible hardcoded exception to getting stuck in piston heads during flings } - public void push(Entity entity) { + public void push(@NotNull Entity entity) { if (entity.passenger == this || entity.vehicle == this || entity.noPhysics || !entity.isPickable() || !this.collidesWith(entity) || !entity.collidesWith(this)) { return; } + + if (this.bb.minY >= entity.bb.maxY - 0.25D || entity.bb.minY >= this.bb.maxY - 0.25D) { + return; + } + double d = entity.x - this.x; double d1 = entity.z - this.z; - double d2 = MathHelper.abs_max(d, d1); - if (d2 >= 0.01D) { - d2 = MathHelper.sqrt(d2); - d /= d2; - d1 /= d2; - double d3 = 1.0D / d2; + double distSq = d * d + d1 * d1; + if (distSq >= 0.0001D) { + double dist = MathHelper.sqrt(distSq); + d /= dist; + d1 /= dist; + double d3 = 1.0D / dist; if (d3 > 1.0D) { d3 = 1.0D; } @@ -940,6 +1070,10 @@ public abstract class Entity return false; } + public boolean hasCollision() { + return false; + } + public void awardKillScore(Entity entity, int i) { } @@ -952,8 +1086,8 @@ public abstract class Entity } public boolean shouldRenderAtSqrDistance(final double distance, final double viewDistanceModifier) { - double d1 = MathHelper.getAABBSize(this.bb); - d1 *= 64D * this.viewScale * viewDistanceModifier; + double d1 = (this.bbWidth * 2.0F + this.bbHeight) / 3.0F; + d1 *= 64.0D * this.viewScale * viewDistanceModifier; return distance < d1 * d1; } @@ -1070,10 +1204,13 @@ public abstract class Entity } public boolean isInWall() { + float widthOffset = this.bbWidth * 0.45F; + float heightOffset = 0.05F; + for (int i = 0; i < 8; i++) { - float f = ((float) ((i >> 0) % 2) - 0.5F) * this.bbWidth * 0.9F; - float f1 = ((float) ((i >> 1) % 2) - 0.5F) * 0.1F; - float f2 = ((float) ((i >> 2) % 2) - 0.5F) * this.bbWidth * 0.9F; + float f = (i & 1) == 0 ? -widthOffset : widthOffset; + float f1 = (i & 2) == 0 ? -heightOffset : heightOffset; + float f2 = (i & 4) == 0 ? -widthOffset : widthOffset; int x = MathHelper.floor(this.x + (double) f); int y = MathHelper.floor(this.y + (double) getHeadHeight() + (double) f1); int z = MathHelper.floor(this.z + (double) f2); @@ -1181,7 +1318,7 @@ public abstract class Entity float xRot, int i) { setPos(x, y, z); setRot(yRot, xRot); - List cubes = this.world.getCubes(this, MathHelper.aabbInsetBoundingBox(this.bb, 0.03125D, 0.0D, 0.03125D, new AABBd())); + List cubes = this.world.getCubes(this, MathHelper.aabbInsetBoundingBox(this.bb, 0.03125D, 0.0D, 0.03125D, workingBox1)); if (!cubes.isEmpty()) { double d3 = 0.0D; for (AABBdc cube : cubes) { @@ -1276,35 +1413,35 @@ public abstract class Entity } protected boolean checkAndPushInTile(double x, double y, double z) { - TilePosc tilePos = new TilePos(x, y, z); - TilePos queryPos = new TilePos(); - double depthX = x - (double) tilePos.x(); - double depthY = y - (double) tilePos.y(); - double depthZ = z - (double) tilePos.z(); - if (this.world.isBlockNormalCube(tilePos)) { + workingPos1.set(x, y, z); + double depthX = x - (double) workingPos1.x(); + double depthY = y - (double) workingPos1.y(); + double depthZ = z - (double) workingPos1.z(); + + if (this.world.isBlockNormalCube(workingPos1)) { Direction direction = Direction.NONE; double minDepth = Double.MAX_VALUE; - if (depthX < minDepth && !this.world.isBlockNormalCube(tilePos.west(queryPos))) { + if (depthX < minDepth && !this.world.isBlockNormalCube(workingPos1.west(workingPos2))) { minDepth = depthX; direction = Direction.WEST; } - if (1.0D - depthX < minDepth && !this.world.isBlockNormalCube(tilePos.east(queryPos))) { + if (1.0D - depthX < minDepth && !this.world.isBlockNormalCube(workingPos1.east(workingPos2))) { minDepth = 1.0D - depthX; direction = Direction.EAST; } - if (depthY < minDepth && !this.world.isBlockNormalCube(tilePos.down(queryPos))) { + if (depthY < minDepth && !this.world.isBlockNormalCube(workingPos1.down(workingPos2))) { minDepth = depthY; direction = Direction.DOWN; } - if (1.0D - depthY < minDepth && !this.world.isBlockNormalCube(tilePos.up(queryPos))) { + if (1.0D - depthY < minDepth && !this.world.isBlockNormalCube(workingPos1.up(workingPos2))) { minDepth = 1.0D - depthY; direction = Direction.UP; } - if (depthZ < minDepth && !this.world.isBlockNormalCube(tilePos.north(queryPos))) { + if (depthZ < minDepth && !this.world.isBlockNormalCube(workingPos1.north(workingPos2))) { minDepth = depthZ; direction = Direction.NORTH; } - if (1.0D - depthZ < minDepth && !this.world.isBlockNormalCube(tilePos.south(queryPos))) { + if (1.0D - depthZ < minDepth && !this.world.isBlockNormalCube(workingPos1.south(workingPos2))) { // minDepth = 1.0D - depthZ; direction = Direction.SOUTH; } diff --git a/game/core/src/main/java/net/minecraft/core/entity/EntityDispatcher.java b/game/core/src/main/java/net/minecraft/core/entity/EntityDispatcher.java index ea20d7f3c..3eed062cb 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/EntityDispatcher.java +++ b/game/core/src/main/java/net/minecraft/core/entity/EntityDispatcher.java @@ -391,6 +391,7 @@ public final class EntityDispatcher addMapping(MobChicken.class, "Chicken", 93); addMapping(MobSquid.class, "Squid", 94); addMapping(MobWolf.class, "Wolf", 95); + addMapping(ProjectileArrowFlaming.class, "FlamingArrow", 96); } } } diff --git a/game/core/src/main/java/net/minecraft/core/entity/EntityItemHoming.java b/game/core/src/main/java/net/minecraft/core/entity/EntityItemHoming.java new file mode 100644 index 000000000..4cd2339ae --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/entity/EntityItemHoming.java @@ -0,0 +1,59 @@ +package net.minecraft.core.entity; + +import net.minecraft.core.item.ItemStack; +import net.minecraft.core.world.World; +import net.minecraft.core.util.helper.MathHelper; + +public class EntityItemHoming extends EntityItem { + private Entity target; + private int homingTicks; + + public EntityItemHoming(World world, double x, double y, double z, ItemStack itemStack, Entity target) { + super(world, x, y, z, itemStack); + this.target = target; + this.homingTicks = 0; + this.pickupDelay = 20; + } + + @Override + public void tick() { + super.tick(); + + this.homingTicks++; + + if (this.target != null && !this.target.removed) { + double dX = this.target.x - this.x; + double dY = (this.target.y + (this.target.bbHeight / 2.0D)) - this.y; + double dZ = this.target.z - this.z; + double distance = MathHelper.sqrt(dX * dX + dY * dY + dZ * dZ); + + if (distance < 64.0D && distance > 0.1D) { + double acceleration = Math.min(0.5D, 0.02D + (this.homingTicks * 0.01D)); + + double noiseX = (this.random.nextFloat() - 0.5D) * 0.2D; + double noiseY = (this.random.nextFloat() - 0.5D) * 0.2D; + double noiseZ = (this.random.nextFloat() - 0.5D) * 0.2D; + + this.xd += ((dX / distance) + noiseX) * acceleration; + this.yd += ((dY / distance) + noiseY) * acceleration; + this.zd += ((dZ / distance) + noiseZ) * acceleration; + + double antiGravity = Math.min(0.02D, this.homingTicks * 0.002D); + this.yd += antiGravity; + + double currentSpeed = MathHelper.sqrt(this.xd * this.xd + this.yd * this.yd + this.zd * this.zd); + double maxSpeed = Math.min(1.2D, 0.2D + (this.homingTicks * 0.05D)); + + if (currentSpeed > maxSpeed) { + this.xd = (this.xd / currentSpeed) * maxSpeed; + this.yd = (this.yd / currentSpeed) * maxSpeed; + this.zd = (this.zd / currentSpeed) * maxSpeed; + } + + if (this.homingTicks > 10) { + this.noPhysics = true; + } + } + } + } +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/entity/IArmorWearing.java b/game/core/src/main/java/net/minecraft/core/entity/IArmorWearing.java index 2964241b9..31e196982 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/IArmorWearing.java +++ b/game/core/src/main/java/net/minecraft/core/entity/IArmorWearing.java @@ -24,8 +24,7 @@ public interface IArmorWearing { for (int i = 0; i < getNumArmorSlots(); i++) { final @NotNull T armorSlot = Objects.requireNonNull(getArmorSlotByIndex(i)); final @Nullable ItemStack armorItem = getItemInArmorSlot(armorSlot); - if (armorItem != null && armorItem.getItem() instanceof IArmorItem) { - final @NotNull IArmorItem armor = (IArmorItem) armorItem.getItem(); + if (armorItem != null && armorItem.getItem() instanceof @NotNull IArmorItem armor) { final @Nullable ArmorMaterial material = armor.getArmorMaterial(); if (material != null) { protectionPercentage += material.getProtection(damageType) * armor.getArmorPieceProtectionPercentage(); @@ -38,8 +37,7 @@ public interface IArmorWearing { default void damageArmor(final int damage, final @NotNull T armorSlot) { final @Nullable ItemStack armorItem = getItemInArmorSlot(armorSlot); - if (armorItem != null && armorItem.getItem() instanceof IArmorItem) { - final @NotNull IArmorItem armor = (IArmorItem) armorItem.getItem(); + if (armorItem != null && armorItem.getItem() instanceof @NotNull IArmorItem armor) { final @Nullable ArmorMaterial material = armor.getArmorMaterial(); if (material != null) { if (this instanceof Entity) { diff --git a/game/core/src/main/java/net/minecraft/core/entity/Mob.java b/game/core/src/main/java/net/minecraft/core/entity/Mob.java index 6f73ebaa1..1295c8448 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/Mob.java +++ b/game/core/src/main/java/net/minecraft/core/entity/Mob.java @@ -757,6 +757,29 @@ public abstract class Mob extends Entity { if (this.horizontalCollision && isFree(this.xd, ((this.yd + 0.6D) - this.y) + d1, this.zd)) { this.yd = 0.3D; } + } else if (isInAcid()) { + double d = this.y; + + moveRelative(moveStrafing, moveForward, 0.01F); + move(this.xd, this.yd, this.zd); + + this.xd *= 0.5D; + this.yd *= 0.5D; + this.zd *= 0.5D; + + this.yd -= 0.01D; + + int blockX = MathHelper.floor(this.x); + int blockY = MathHelper.floor(this.y - this.heightOffset); + int blockZ = MathHelper.floor(this.z); + Block b = this.world.getBlock(blockX, blockY, blockZ); + + float depth; + depth = 1 - (float) b.getBlockBoundsFromState(this.world, blockX, blockY, blockZ).maxY(); + + if (this.horizontalCollision && isFree(this.xd, ((this.yd + depth + 0.2) - this.y) + d, this.zd)) { + this.yd = 0.2D; + } } else if (canSkate() && BlockTags.SKATEABLE.appliesTo(floorBlock)) { this.muteStepSounds = true; this.isSkating = true; @@ -794,7 +817,7 @@ public abstract class Mob extends Entity { movementScale = 0.5460001F; if (BlockTags.OVERRIDE_FRICTION.appliesTo(floorAboveBlock)) { movementScale = floorAboveBlock.friction * 0.91F; - } else if (floorBlock != null) { + } else { movementScale = floorBlock.friction * 0.91F; } } @@ -940,11 +963,14 @@ public abstract class Mob extends Entity { } boolean inWater = isInWater(); boolean inLava = isInLava(); + boolean inAcid = isInAcid(); if (this.isJumping) { if (inWater) { this.yd += 0.04D; } else if (inLava) { this.yd += 0.04D; + } else if (inAcid) { + this.yd += 0.02D; } else if (this.onGround) { jump(); } @@ -1034,7 +1060,8 @@ public abstract class Mob extends Entity { } boolean inWater = isInWater(); boolean inLava = isInLava(); - if (inWater || inLava) { + boolean inAcid = isInAcid(); + if (inWater || inLava || inAcid) { this.isJumping = this.random.nextFloat() < 0.8F; } } @@ -1067,7 +1094,7 @@ public abstract class Mob extends Entity { return this.currentTarget; } - private float rotationLerp(float f, float f1, float f2) // Was called rotLerp in the b1.2 leak + protected float rotationLerp(float f, float f1, float f2) // Was called rotLerp in the b1.2 leak { float f3; for (f3 = f1 - f; f3 < -180F; f3 += 360F) { diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/MobButterfly.java b/game/core/src/main/java/net/minecraft/core/entity/animal/MobButterfly.java index a38227e25..98a7d3ff3 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/animal/MobButterfly.java +++ b/game/core/src/main/java/net/minecraft/core/entity/animal/MobButterfly.java @@ -109,7 +109,7 @@ public class MobButterfly extends MobFlying implements AmbientCreature { } @Override - public void push(Entity entity) { + public void push(@NotNull Entity entity) { } @Override diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/MobFireflyCluster.java b/game/core/src/main/java/net/minecraft/core/entity/animal/MobFireflyCluster.java index 649d9c0c2..6b05f57ac 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/animal/MobFireflyCluster.java +++ b/game/core/src/main/java/net/minecraft/core/entity/animal/MobFireflyCluster.java @@ -249,7 +249,7 @@ public class MobFireflyCluster extends MobFlying } @Override - public void push(Entity entity) { + public void push(@NotNull Entity entity) { } @Override diff --git a/game/core/src/main/java/net/minecraft/core/entity/monster/MobGhast.java b/game/core/src/main/java/net/minecraft/core/entity/monster/MobGhast.java index 89fdb342f..c62b4cf45 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/monster/MobGhast.java +++ b/game/core/src/main/java/net/minecraft/core/entity/monster/MobGhast.java @@ -2,24 +2,22 @@ package net.minecraft.core.entity.monster; import net.minecraft.core.WeightedRandomLootObject; import net.minecraft.core.block.tag.BlockTags; +import net.minecraft.core.entity.EntityItemHoming; import net.minecraft.core.entity.MobFlying; import net.minecraft.core.entity.player.Player; -import net.minecraft.core.entity.projectile.ProjectileFireball; import net.minecraft.core.entity.Entity; -import net.minecraft.core.entity.vehicle.EntityBoat; +import net.minecraft.core.entity.projectile.ProjectileFireball; +import net.minecraft.core.item.ItemStack; import net.minecraft.core.item.Items; -import net.minecraft.core.util.helper.LightIndexHelper; +import net.minecraft.core.player.gamemode.Gamemodes; import net.minecraft.core.util.helper.MathHelper; -import net.minecraft.core.world.Dimension; import net.minecraft.core.world.World; import net.minecraft.core.util.helper.DamageType; import net.minecraft.core.world.pos.TilePos; import org.jetbrains.annotations.NotNull; -import org.joml.Vector3dc; import org.joml.primitives.AABBd; -public class MobGhast extends MobFlying - implements Enemy { +public class MobGhast extends MobFlying implements Enemy { public static final int DATA_CHARGING = 16; public int courseChangeCooldown; public double waypointX; @@ -30,7 +28,6 @@ public class MobGhast extends MobFlying public int attackChargeO; public int attackCharge; - public MobGhast(World world) { super(world); this.courseChangeCooldown = 0; @@ -39,10 +36,9 @@ public class MobGhast extends MobFlying this.attackChargeO = 0; this.attackCharge = 0; setTextureIdentifier("minecraft", "ghast"); - setSize(4F, 7F); + setSize(4F, 4.5F); this.fireImmune = true; this.scoreValue = 1000; - MathHelper.aabbGrow(this.bb, 2f, 3f, 2f, this.bb); this.mobDrops.add(new WeightedRandomLootObject(Items.GUNPOWDER.getDefaultStack(), 0, 2)); } @@ -70,8 +66,8 @@ public class MobGhast extends MobFlying } } + @Override public void tick() { - //prevAttackCounter = attackCounter; -uncomment if it still doesn't work if (this.world.isClientSide) { byte i = this.entityData.getByte(DATA_CHARGING); if (i > 0 && this.attackCharge == 0) { @@ -84,11 +80,12 @@ public class MobGhast extends MobFlying if (this.attackCharge >= 20) { this.attackCharge = 20; } - if (this.attackCharge >= 20 && i == 0) { + if (this.attackCharge == 20 && i == 0) { this.world.playSoundAtEntity(null, this, "mob.ghast.fireball", getSoundVolume(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F); this.attackCharge = -40; } } + super.tick(); } @@ -96,86 +93,99 @@ public class MobGhast extends MobFlying protected void updateAI() { if (!this.world.isClientSide && !this.world.getDifficulty().canHostileMobsSpawn()) { remove(); + return; } tryToDespawn(); - this.attackChargeO = this.attackCharge; + double d = this.waypointX - this.x; double d1 = this.waypointY - this.y; double d2 = this.waypointZ - this.z; - double d3 = MathHelper.sqrt(d * d + d1 * d1 + d2 * d2); - if (d3 < 1.0D || d3 > 60D) { - this.waypointX = this.x + (double) ((this.random.nextFloat() * 2.0F - 1.0F) * 16F); - this.waypointY = this.y + (double) ((this.random.nextFloat() * 2.0F - 1.0F) * 16F); - this.waypointZ = this.z + (double) ((this.random.nextFloat() * 2.0F - 1.0F) * 16F); + double d3 = d * d + d1 * d1 + d2 * d2; + + if (d3 < 1.0D || d3 > 3600.0D) { + this.waypointX = this.x + (double)((this.random.nextFloat() * 2.0F - 1.0F) * 16.0F); + this.waypointY = this.y + (double)((this.random.nextFloat() * 2.0F - 1.0F) * 16.0F); + this.waypointZ = this.z + (double)((this.random.nextFloat() * 2.0F - 1.0F) * 16.0F); } + if (this.courseChangeCooldown-- <= 0) { this.courseChangeCooldown += this.random.nextInt(5) + 2; - if (isCourseTraversable(this.waypointX, this.waypointY, this.waypointZ, d3)) { - this.xd += (d / d3) * 0.1D; - this.yd += (d1 / d3) * 0.1D; - this.zd += (d2 / d3) * 0.1D; + d3 = MathHelper.sqrt(d3); + if (this.isCourseTraversable(this.waypointX, this.waypointY, this.waypointZ, d3)) { + this.xd += d / d3 * 0.1D; + this.yd += d1 / d3 * 0.1D; + this.zd += d2 / d3 * 0.1D; } else { this.waypointX = this.x; this.waypointY = this.y; this.waypointZ = this.z; } } - if (this.targetedEntity != null && this.targetedEntity.removed) { - this.targetedEntity = null; - } + if (this.targetedEntity == null || this.aggroCooldown-- <= 0) { - this.targetedEntity = this.world.getClosestPlayerToEntity(this, 100D); - if (this.targetedEntity != null && !((Player) this.targetedEntity).getGamemode().hasHostileMobs()) { - this.targetedEntity = null; + Entity potentialTarget = this.world.getClosestPlayerToEntity(this, 100.0D); + + if (potentialTarget instanceof Player p && p.gamemode != Gamemodes.CREATIVE && p.gamemode != Gamemodes.SPECTATOR) { + this.targetedEntity = potentialTarget; } + if (this.targetedEntity != null) { this.aggroCooldown = 20; } } - double d4 = 64D; - if (this.targetedEntity != null && this.targetedEntity.distanceToSqr(this) < d4 * d4) { - double d8 = 4D; - Vector3dc viewVec = getViewVector(1.0F); - assert viewVec != null; - double dX = this.targetedEntity.x - this.x; - double dY = this.targetedEntity.y - this.y; - double dZ = this.targetedEntity.z - this.z; - double dist = MathHelper.sqrt(dX * dX + dY * dY + dZ * dZ); - double vX = dX + (this.targetedEntity.xd * dist / 7.5d) - viewVec.x() * d8; - double vY = dY + (this.targetedEntity.yd * dist / 7.5d) - ((double) (this.bbHeight / 2.0F) + 0.5D); - double vZ = dZ + (this.targetedEntity.zd * dist / 7.5d) - viewVec.z() * d8; - this.yBodyRot = this.yRot = (-(float) java.lang.Math.atan2(vX, vZ) * 180F) / MathHelper.PI; - if (canEntityBeSeen(this.targetedEntity)) { + + double maxAttackDist = 64.0D; + if (this.targetedEntity != null && this.targetedEntity.distanceToSqr(this) < maxAttackDist * maxAttackDist) { + double tx = this.targetedEntity.x - this.x; + double ty = (this.targetedEntity.bb.minY + (double)(this.targetedEntity.bbHeight / 2.0F)) - (this.y + (double)(this.bbHeight / 2.0F)); + double tz = this.targetedEntity.z - this.z; + + // Calculate where we WANT to look + float targetYaw = (-(float)java.lang.Math.atan2(tx, tz) * 180F) / MathHelper.PI; + + // Safely calculate the shortest path to that angle + float deltaYaw = targetYaw - this.yRot; + while (deltaYaw < -180.0F) deltaYaw += 360.0F; + while (deltaYaw >= 180.0F) deltaYaw -= 360.0F; + + this.yRot += deltaYaw * 0.1F; + this.yBodyRot = this.yRot; + + if (this.canEntityBeSeen(this.targetedEntity)) { if (this.attackCharge == 10) { this.world.playSoundAtEntity(null, this, "mob.ghast.charge", getSoundVolume(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F); } this.attackCharge++; if (this.attackCharge == 20) { this.world.playSoundAtEntity(null, this, "mob.ghast.fireball", getSoundVolume(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F); - ProjectileFireball fireball = new ProjectileFireball(this.world, this, vX, vY, vZ); - - fireball.x = this.x + viewVec.x() * d8; - fireball.y = this.y + (double) (this.bbHeight / 2.0F) + 0.5D; - fireball.z = this.z + viewVec.z() * d8; + ProjectileFireball fireball = new ProjectileFireball(this.world, this, tx, ty, tz); this.world.entityJoinedWorld(fireball); this.attackCharge = -40; } } else if (this.attackCharge > 0) { this.attackCharge--; - } else { - this.targetedEntity = null; } } else { - this.yBodyRot = this.yRot = (-(float) java.lang.Math.atan2(this.xd, this.zd) * 180F) / MathHelper.PI; + if (this.xd * this.xd + this.zd * this.zd > 0.001D) { + float targetYaw = (-(float) java.lang.Math.atan2(this.xd, this.zd) * 180F) / MathHelper.PI; + + float deltaYaw = targetYaw - this.yRot; + while (deltaYaw < -180.0F) deltaYaw += 360.0F; + while (deltaYaw >= 180.0F) deltaYaw -= 360.0F; + + this.yRot += deltaYaw * 0.1F; + this.yBodyRot = this.yRot; + } + if (this.attackCharge > 0) { this.attackCharge--; } } + if (!this.world.isClientSide) { - byte chargeData = this.entityData.getByte(DATA_CHARGING); - byte chargeState = (byte) (this.attackCharge <= 10 ? 0 : 1); - if (chargeData != chargeState) { - this.entityData.set(DATA_CHARGING, chargeState); + byte isCharging = (byte)(this.attackCharge > 10 ? 1 : 0); + if (this.entityData.getByte(DATA_CHARGING) != isCharging) { + this.entityData.set(DATA_CHARGING, isCharging); } } } @@ -191,7 +201,6 @@ public class MobGhast extends MobFlying return false; } } - return true; } @@ -245,8 +254,10 @@ public class MobGhast extends MobFlying public boolean canSpawnHere() { return this.world.getDifficulty().canHostileMobsSpawn() && - this.random.nextInt(20) == 0 && + this.random.nextInt(30) == 0 && BlockTags.NETHER_MOBS_SPAWN.appliesTo(this.world.getBlockType(new TilePos(this.x, this.y - this.heightOffset - 1, this.z))) && + this.world.areBlocksLoaded(this.bb) && + this.world.getCubes(this, this.bb).isEmpty() && super.canSpawnHere(); } @@ -261,12 +272,34 @@ public class MobGhast extends MobFlying } @Override - public float calcBrightness(float partialTick) { - return 1; - } + public void onDeath(Entity killer) { + java.util.List storedDrops = new java.util.ArrayList<>(this.mobDrops); + this.mobDrops.clear(); - @Override - public byte calcLightIndex(float partialTick) { - return LightIndexHelper.lightIndex2i(15, 15); + super.onDeath(killer); + + this.mobDrops.addAll(storedDrops); + + if (!this.world.isClientSide) { + for (WeightedRandomLootObject lootObject : storedDrops) { + ItemStack dropStack = lootObject.getItemStack(this.random); + + if (dropStack != null && dropStack.stackSize > 0) { + if (killer instanceof Player) { + for (int i = 0; i < dropStack.stackSize; i++) { + ItemStack singleDrop = new ItemStack(dropStack.itemID, 1, dropStack.getMetadata()); + + EntityItemHoming homingItem = new EntityItemHoming(this.world, this.x, this.y, this.z, singleDrop, killer); + homingItem.xd = (this.random.nextFloat() - 0.5F) * 0.8F; + homingItem.yd = this.random.nextFloat() * 0.8F; + homingItem.zd = (this.random.nextFloat() - 0.5F) * 0.8F; + this.world.entityJoinedWorld(homingItem); + } + } else { + this.world.dropItem(new TilePos(this.x, this.y, this.z), dropStack); + } + } + } + } } -} +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java index b5ba3bd35..bb0386cfb 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java +++ b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java @@ -35,9 +35,11 @@ import net.minecraft.core.enums.ArtType; import net.minecraft.core.enums.EnumDropCause; import net.minecraft.core.enums.EnumSleepStatus; import net.minecraft.core.item.Item; -import net.minecraft.core.item.ItemBucket; +import net.minecraft.core.item.ItemArmor; import net.minecraft.core.item.ItemStack; import net.minecraft.core.item.Items; +import net.minecraft.core.item.tool.ItemTool; +import net.minecraft.core.item.tool.ItemToolShears; import net.minecraft.core.item.tool.ItemToolSword; import net.minecraft.core.lang.I18n; import net.minecraft.core.net.command.TextFormatting; @@ -47,6 +49,7 @@ import net.minecraft.core.player.inventory.container.Container; import net.minecraft.core.player.inventory.container.ContainerInventory; import net.minecraft.core.player.inventory.menu.MenuAbstract; import net.minecraft.core.player.inventory.menu.MenuInventory; +import net.minecraft.core.sound.SoundCategory; import net.minecraft.core.util.helper.DamageType; import net.minecraft.core.util.helper.DyeColor; import net.minecraft.core.util.helper.MathHelper; @@ -58,7 +61,6 @@ import net.minecraft.core.world.chunk.ChunkCoordinates; import net.minecraft.core.world.chunk.provider.ChunkProvider; import net.minecraft.core.world.pos.TilePos; import net.minecraft.core.world.pos.TilePosc; -import net.minecraft.core.world.type.tag.WorldTypeTags; import net.minecraft.core.world.weather.Weathers; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -131,6 +133,15 @@ public abstract class Player public int lastRenderTick = 0; public float wobbleTimer = 0; + public static final int ACID_CYCLE_MAX = 10; + private static final int ACID_POST_EXIT_DRAIN_TICKS = 20; + private static final int ACID_EXIT_BUFFER = 2; + + private int acidMeltTicks; + private int acidExitDelayLeft; + private int acidPostExitDrainTicksLeft; + private int acidPostExitPeak; + public final PlayerConfig playerConfig = new PlayerConfig(); public Player(World world) { @@ -252,6 +263,13 @@ public abstract class Player public void tick() { if (this.world.getDimension() == Dimension.NETHER) { addStat(Achievements.ENTER_NETHER, 1); + if (random.nextInt(20) == 0) { + int distance = 50; + world.playSoundEffect(this, SoundCategory.CAVE_SOUNDS, this.x + distance, this.y, this.z + distance, "ambient.cave.cave", 1.0F, 0.01F); + world.playSoundEffect(this, SoundCategory.CAVE_SOUNDS, this.x - distance, this.y, this.z - distance, "ambient.cave.cave", 1.0F, 0.01F); + world.playSoundEffect(this, SoundCategory.CAVE_SOUNDS, this.x + distance, this.y, this.z - distance, "ambient.cave.cave", 1.0F, 0.01F); + world.playSoundEffect(this, SoundCategory.CAVE_SOUNDS, this.x - distance, this.y, this.z + distance, "ambient.cave.cave", 1.0F, 0.01F); + } } this.xdO = this.xd; @@ -374,6 +392,8 @@ public abstract class Player this.cameraVelocityOld = this.cameraVelocity; super.onLivingUpdate(); + acidTick(); + this.speed = this.baseSpeed; this.flySpeed = this.baseFlySpeed; if (isSprinting()) { @@ -411,6 +431,202 @@ public abstract class Player } } } + + AABBd feetBox = new AABBd(this.bb.minX, this.bb.minY - 0.1D, this.bb.minZ, this.bb.maxX, this.bb.minY + 0.1D, this.bb.maxZ); + List platforms = this.world.getEntitiesWithinAABBExcludingEntity(this, feetBox); + + for (int i = 0; i < platforms.size(); i++) { + Entity platform = platforms.get(i); + + if (platform instanceof MobGhast) continue; + + if (platform.hasCollision() && this.bb.minY >= platform.bb.maxY - 0.25D) { + + if (this.yd < 0.0D) { + this.yd = 0.0D; + } + this.fallDistance = 0.0F; + + double deltaX = platform.x - platform.xo; + double deltaZ = platform.z - platform.zo; + double snapY = platform.bb.maxY - this.bb.minY; + + this.move(deltaX, snapY, deltaZ); + + this.onGround = true; + break; + } + } + } + + public void acidTick() { + if (!getGamemode().hasToolDurability()) { + this.acidMeltTicks = 0; + this.acidExitDelayLeft = 0; + this.acidPostExitPeak = 0; + this.acidPostExitDrainTicksLeft = 0; + return; + } + + final boolean physicallyInAcid = isInAcid(); + final int meltRate = Math.max(1, this.world.getGameRuleValue(GameRules.ACID_MELT_RATE)); + final boolean shouldTickRate = (this.tickCount % meltRate == 0); + + if (physicallyInAcid) { + this.acidExitDelayLeft = ACID_EXIT_BUFFER; + this.acidPostExitDrainTicksLeft = ACID_POST_EXIT_DRAIN_TICKS; + this.acidPostExitPeak = 0; + } + + final boolean applyAcidMeltAndDamage = physicallyInAcid || this.acidExitDelayLeft > 0; + + if (applyAcidMeltAndDamage) { + if (!physicallyInAcid && this.acidExitDelayLeft > 0) { + this.acidExitDelayLeft--; + if (this.acidExitDelayLeft == 0) { + this.acidPostExitPeak = this.acidMeltTicks; + } + } + + if (shouldTickRate) { + this.acidMeltTicks = Math.min(this.acidMeltTicks + 1, ACID_CYCLE_MAX); + + if (!this.world.isClientSide && isAlive()) { + processAcidDamageAndParticles(); + } + } + } else if (this.acidMeltTicks > 0) { + if (this.acidPostExitDrainTicksLeft > 0) { + this.acidPostExitDrainTicksLeft--; + if (this.acidPostExitDrainTicksLeft <= 0) { + this.acidMeltTicks = 0; + this.acidPostExitPeak = 0; + } + } + } + } + + /** True while physically in acid or during {@link #ACID_EXIT_BUFFER} post-exit melt/damage ticks. */ + public boolean isEffectiveInAcid() { + return isInAcid() || this.acidExitDelayLeft > 0; + } + + private void processAcidDamageAndParticles() { + final int acidIntensity = this.acidMeltTicks; + boolean meltedAny = false; + + for (int i = 0; i < this.inventory.mainInventory.length; i++) { + final @Nullable ItemStack stack = this.inventory.mainInventory[i]; + if (stack == null || !isMeltableHeldTool(stack)) { + continue; + } + + stack.damageItem(getAcidMeltDamage(stack, acidIntensity), this); + if (stack.stackSize <= 0) { + this.inventory.mainInventory[i] = null; + } + meltedAny = true; + } + + for (int i = 0; i < getNumArmorSlots(); i++) { + final @Nullable HumanArmorShape armorSlot = getArmorSlotByIndex(i); + if (armorSlot == null) { + continue; + } + + final @Nullable ItemStack armorItem = getItemInArmorSlot(armorSlot); + if (armorItem == null) { + continue; + } + + damageArmor(getAcidMeltDamage(armorItem, acidIntensity), armorSlot); + meltedAny = true; + } + + int acidExposureDamage = getAcidExposureArmorSlotCount(); + if (acidExposureDamage > 0) { + hurt(null, acidExposureDamage, DamageType.GENERIC); + } + + if (meltedAny || acidExposureDamage > 0) { + float fizzPitch = 0.6F + this.random.nextFloat() * 0.25F; + float bubblePitch = 0.7F + this.random.nextFloat() * 0.2F; + this.world.playSoundAtEntity(null, this, "random.fizz", 0.35F, fizzPitch); + this.world.playSoundAtEntity(null, this, "tile.acidbubble", 0.4F, bubblePitch); + + for (int i = 0; i < 6; i++) { + double offX = (this.random.nextDouble() - 0.5D) * (double) this.bbWidth; + double offY = this.random.nextDouble() * (double) this.bbHeight; + double offZ = (this.random.nextDouble() - 0.5D) * (double) this.bbWidth; + this.world.spawnParticle("acidBoiling", this.x + offX, this.bb.minY + offY, this.z + offZ, 0.0F, 0.02F, 0.0F, 0, false); + } + } + } + + public boolean shouldShowAcidVisualEffects() { + return isEffectiveInAcid() || this.acidMeltTicks > 0; + } + + public int getAcidHudBarFillTicks() { + if (isEffectiveInAcid() || this.acidPostExitPeak == 0) { + return this.acidMeltTicks; + } + if (this.acidPostExitDrainTicksLeft <= 0) { + return 0; + } + + return (this.acidPostExitPeak * this.acidPostExitDrainTicksLeft) / ACID_POST_EXIT_DRAIN_TICKS; + } + + private int getAcidExposureArmorSlotCount() { + int count = 0; + for (int i = 0; i < getNumArmorSlots(); i++) { + final @Nullable HumanArmorShape armorSlot = getArmorSlotByIndex(i); + if (armorSlot == null) { + continue; + } + final @Nullable ItemStack stack = getItemInArmorSlot(armorSlot); + if (!isHumanArmorItemCoveringSlot(stack)) { + count++; + } + } + return Math.max(0, count - 1); + } + + private static boolean isHumanArmorItemCoveringSlot(final @Nullable ItemStack stack) { + if (stack == null) { + return false; + } + if (!(stack.getItem() instanceof ItemArmor armor)) { + return false; + } + return armor.getArmorShape() instanceof HumanArmorShape; + } + + private boolean isMeltableHeldTool(final @NotNull ItemStack stack) { + final @NotNull Item item = stack.getItem(); + return item instanceof ItemTool || item instanceof ItemToolSword || item instanceof ItemToolShears; + } + + private int getAcidMeltDamage(final @NotNull ItemStack stack, final int acidIntensity) { + if (!stack.isItemStackDamageable()) { + return 1; + } + + final int base = Math.max(1, (int) Math.ceil(Math.sqrt(stack.getMaxDamage()) / 10.0D)); + + final int tier = Math.min(ACID_CYCLE_MAX, Math.max(1, acidIntensity)); + if (tier < 2 || ACID_CYCLE_MAX < 2) { + return base; + } + + float progress = (float) (tier - 1) / (float) (ACID_CYCLE_MAX - 1); + + float curve = (float) Math.sqrt(progress); + + final float multiplier = 1.0F + (curve * 0.45F); + + return Math.max(1, (int) Math.ceil(base * multiplier)); } @Override @@ -467,8 +683,8 @@ public abstract class Player } else if (UUID_SHIGN.equals(this.uuid) || this.username.equals("ShignBright")) { dropItem(new ItemStack(Items.SIGN_PAINTED, 1, DyeColor.PINK.itemMeta), true); } else if ((UUID_MELON.equals(this.uuid) || this.username.equals("MelonMojito")) || (UUID_WATERMELON.equals(this.uuid) || this.username.equals("WatermelonMojito"))) { - ItemStack melon = new ItemStack(Blocks.PUMPKIN, 1, this.random.nextInt(Short.MAX_VALUE / 2) + 1); - melon.setCustomName("Melon"); + ItemStack melon = new ItemStack(Blocks.PUMPKIN, 1); + melon.setCustomName("Melon Block?"); melon.setCustomColor((byte) TextFormatting.LIME.id); dropItem(melon, true); } @@ -659,7 +875,7 @@ public abstract class Player } @Override - public void push(Entity entity) { + public void push(@NotNull Entity entity) { if (this.noPhysics || !getGamemode().canInteract()) return; super.push(entity); } @@ -1421,6 +1637,45 @@ public abstract class Player } } + + //TODO Need to implement a native solution for distance/player oriented functionality + /** + * Handles the incoming ping from a nearby Thermal Vent. + * Categorizes the player into Close, Medium, or Far range based on maxRadius, + * playing a different sound for each tier. + */ + public void handleThermalPing(Player player, double ventCoordinateX, double ventCoordinateY, double ventCoordinateZ, double maxRadius) { + double distanceSquared = this.distanceToSqr(ventCoordinateX, ventCoordinateY, ventCoordinateZ); + double distance = Math.sqrt(distanceSquared); + + double oneFifthOfRadius = maxRadius * 0.2; + double threeFifthsOfRadius = maxRadius * 0.6; + + float randomizedPitch = 0.8F + (this.world.rand.nextFloat() - this.world.rand.nextFloat()) * 0.45F; + + if (distance <= oneFifthOfRadius) { + this.world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, + ventCoordinateX, ventCoordinateY, ventCoordinateZ, + "tile.crumble", 20.0F, randomizedPitch); + this.world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, + ventCoordinateX, ventCoordinateY, ventCoordinateZ, + "tile.deepboom", 20.0F, randomizedPitch); + } + else if (distance <= threeFifthsOfRadius) { + this.world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, + ventCoordinateX, ventCoordinateY, ventCoordinateZ, + "tile.deepcrumble", 20.0F, randomizedPitch); + this.world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, + ventCoordinateX, ventCoordinateY, ventCoordinateZ, + "tile.deepquietboom", 20.0F, randomizedPitch); + } + else { + this.world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, + ventCoordinateX, ventCoordinateY, ventCoordinateZ, + "tile.deepquietboom", 20.0F, randomizedPitch); + } + } + @Override public boolean canBreatheUnderwater() { return this.gamemode.hasInvulnerablePlayer(); diff --git a/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileArrowFlaming.java b/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileArrowFlaming.java new file mode 100644 index 000000000..1cedf70ab --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileArrowFlaming.java @@ -0,0 +1,130 @@ +package net.minecraft.core.entity.projectile; + +import net.minecraft.core.block.BlockLogicEmber; +import net.minecraft.core.block.Blocks; +import net.minecraft.core.block.Block; +import net.minecraft.core.block.BlockLogicTNT; +import net.minecraft.core.entity.Mob; +import net.minecraft.core.entity.monster.MobCreeper; +import net.minecraft.core.entity.monster.MobZombiePig; +import net.minecraft.core.item.ItemStack; +import net.minecraft.core.item.Items; +import net.minecraft.core.util.helper.DamageType; +import net.minecraft.core.util.helper.LightIndexHelper; +import net.minecraft.core.util.phys.HitResult; +import net.minecraft.core.world.World; +import org.jetbrains.annotations.NotNull; + + +public class ProjectileArrowFlaming extends ProjectileArrow { + public ProjectileArrowFlaming(World world) { + super(world, 4); + this.stack = new ItemStack(Items.AMMO_ARROW_FLAMING); + this.entityBrightness = 1.0F; + } + + public ProjectileArrowFlaming(World world, double x, double y, double z) { + super(world, x, y, z, 4); + this.stack = new ItemStack(Items.AMMO_ARROW_FLAMING); + this.entityBrightness = 1.0F; + } + + public ProjectileArrowFlaming(World world, Mob owner, boolean doesArrowBelongToPlayer) { + super(world, owner, doesArrowBelongToPlayer, 4); + this.stack = new ItemStack(Items.AMMO_ARROW_FLAMING); + this.entityBrightness = 1.0F; + } + + @Override + protected void initProjectile() { + super.initProjectile(); + this.damage = 6; + this.entityBrightness = 1.0F; + } + + @Override + public float getBrightness(float partialTick) { + return 10.0F; + } + + @Override + public float calcBrightness(float partialTick) { + return 1.0F; + } + + @Override + public byte calcLightIndex(float partialTick) { + return LightIndexHelper.setBlockLight(super.calcLightIndex(partialTick), 15); + } + + @Override + public void tick() { + world.spawnParticle("flame", this.x, this.y, this.z, this.xd * 0.05, this.yd * 0.05 - 0.1, this.zd * 0.05, 0, false); + world.spawnParticle("flame", this.x, this.y, this.z, this.xd * 0.05, this.yd * 0.05 - 0.1, this.zd * 0.05, 0, false); + world.spawnParticle("smoke", this.x, this.y, this.z, this.xd * 0.05, this.yd * 0.05 - 0.1, this.zd * 0.05, 0, false); + world.spawnParticle("smoke", this.x, this.y, this.z, this.xd * 0.05, this.yd * 0.05 - 0.1, this.zd * 0.05, 0, false); + super.tick(); + } + + @Override + public void onHit(@NotNull HitResult hitResult) { + if (hitResult instanceof HitResult.Entity hitEntity) { + if (hitEntity.entity instanceof MobZombiePig) { + hitEntity.entity.hurt(this.owner, this.damage, DamageType.COMBAT); + } else if (hitEntity.entity.hurt(this.owner, this.damage, DamageType.FIRE)) { + if (hitEntity.entity instanceof MobCreeper entityCreeper) { + entityCreeper.setTarget(entityCreeper); + } + hitEntity.entity.fireHurt(); + + if (!this.world.isClientSide) { + this.world.playSoundAtEntity(null, this, "random.drr", 1.0F, 1.2F / (this.random.nextFloat() * 0.2F + 0.9F)); + } + } + this.remove(); + } else if (hitResult instanceof HitResult.Tile hitTile && !this.world.isClientSide) { + int x = hitTile.tilePos.x(); + int y = hitTile.tilePos.y(); + int z = hitTile.tilePos.z(); + Block hitBlock = world.getBlockType(hitTile.tilePos); + + x += hitTile.side.offsetX(); + y += hitTile.side.offsetY(); + z += hitTile.side.offsetZ(); + + if (world.isAirBlock(x, y, z)) { + world.setBlockWithNotify(x, y, z, Blocks.FIRE.id()); + } + + if (hitBlock == Blocks.BRAZIER_INACTIVE) { + world.setBlockType(hitTile.tilePos, Blocks.BRAZIER_ACTIVE); + } + + if (hitBlock == Blocks.TNT) { + world.getBlockLogic(hitTile.tilePos, BlockLogicTNT.class).ignite(world, hitTile.tilePos, true); + } + + if (hitBlock == Blocks.EMBER) { + world.getBlockLogic(hitTile.tilePos, BlockLogicEmber.class).ignite(world, hitTile.tilePos, null); + } + if (hitBlock == Blocks.ICE) { + world.setBlockTypeNotify(hitTile.tilePos, Blocks.FLUID_WATER_STILL); + } + } + + this.remove(); + + super.onHit(hitResult); + } + + @Override + protected void inGroundAction() { + world.spawnParticle("explode", this.x, this.y, this.z, this.xd * 0.05, this.yd * 0.05 - 0.1, this.zd * 0.05, 0, false); + world.spawnParticle("explode", this.x, this.y, this.z, this.xd * 0.05, this.yd * 0.05 - 0.1, this.zd * 0.05, 0, false); + world.spawnParticle("ventsmoke", this.x, this.y, this.z, this.xd * 0.05, this.yd * 0.05 - 0.1, this.zd * 0.05, 0, false); + world.spawnParticle("ventsmoke", this.x, this.y, this.z, this.xd * 0.05, this.yd * 0.05 - 0.1, this.zd * 0.05, 0, false); + world.playSoundAtEntity(null, this, "random.fizz", 0.1f, (random.nextFloat() * 1.4F + 0.8F)); + + super.inGroundAction(); + } +} diff --git a/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileFireball.java b/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileFireball.java index 1746edc10..7f9171650 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileFireball.java +++ b/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileFireball.java @@ -4,6 +4,7 @@ import net.minecraft.core.achievement.Achievements; import net.minecraft.core.entity.Mob; import net.minecraft.core.entity.monster.MobGhast; import net.minecraft.core.entity.player.Player; +import net.minecraft.core.sound.SoundCategory; import net.minecraft.core.util.phys.HitResult; import net.minecraft.core.entity.Entity; import net.minecraft.core.util.helper.MathHelper; @@ -14,6 +15,7 @@ import org.joml.Vector3dc; public class ProjectileFireball extends Projectile { public static final double FIREBALL_SPEED = 1d; + public static final double DEFLECTED_SPEED = 2d; public ProjectileFireball(World world) { super(world); @@ -113,7 +115,9 @@ public class ProjectileFireball extends Projectile { this.owner = (Mob) entity; } if (lookAngle != null) { - setVelocity(lookAngle.x(), lookAngle.y(), lookAngle.z(), FIREBALL_SPEED); + world.playSoundEffect(entity, SoundCategory.WORLD_SOUNDS, this.x, this.y, this.z, "random.drr", 1.0F, 1.3F + this.random.nextFloat() * 0.4F); + world.playSoundEffect(entity, SoundCategory.WORLD_SOUNDS, this.x, this.y, this.z, "random.bow", 1.0F, 1.3F + this.random.nextFloat() * 0.4F); + setVelocity(lookAngle.x(), lookAngle.y(), lookAngle.z(), DEFLECTED_SPEED); } return true; } else { diff --git a/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityBoat.java b/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityBoat.java index f3a3b1df5..b5694f797 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityBoat.java +++ b/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityBoat.java @@ -321,7 +321,7 @@ public class EntityBoat extends Entity { int blockY = MathHelper.floor(this.y); int blockZ = MathHelper.floor(this.z + ((double) (i / 2) - 0.5D) * 0.8D); Block block = this.world.getBlock(blockX, blockY, blockZ); - if (block != null && block.hasTag(BlockTags.BOAT_BREAKS)) { + if (block.hasTag(BlockTags.BOAT_BREAKS)) { this.world.setBlockWithNotify(blockX, blockY, blockZ, 0); } } diff --git a/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java b/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java index fabb99dc7..620ebf182 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java +++ b/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java @@ -677,7 +677,7 @@ public class EntityMinecart extends Entity implements Container { } @Override - public void push(Entity entity) { + public void push(@NotNull Entity entity) { if (this.world.isClientSide) { return; } diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java b/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java index 201bb20eb..2d2785f6e 100644 --- a/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java +++ b/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java @@ -16,6 +16,7 @@ import net.minecraft.core.util.collection.NamespaceID; import net.minecraft.core.util.helper.Direction; import net.minecraft.core.util.helper.Side; import net.minecraft.core.util.phys.HitResult; +import net.minecraft.core.world.LevelListener; import net.minecraft.core.world.World; import net.minecraft.core.world.pos.TilePos; import net.minecraft.core.world.pos.TilePosc; @@ -77,6 +78,7 @@ public abstract class ItemBucket extends ItemFood implements IItemContainer { public static final NamespaceID STATE_EMPTY = new NamespaceID("minecraft", "empty"); public static final NamespaceID STATE_WATER = new NamespaceID("minecraft", "water"); public static final NamespaceID STATE_LAVA = new NamespaceID("minecraft", "lava"); + public static final NamespaceID STATE_ACID = new NamespaceID("minecraft", "acid"); public static final NamespaceID STATE_MILK = new NamespaceID("minecraft", "milk"); public static final NamespaceID STATE_ICECREAM = new NamespaceID("minecraft", "icecream"); @@ -100,6 +102,13 @@ public abstract class ItemBucket extends ItemFood implements IItemContainer { BlockLogicFluid::fizz )); + registerState(STATE_ACID, new BucketState( + "acid", + Blocks.FLUID_ACID_FLOWING, + BlockTags.IS_ACID, + "tile.acidbubble", + (world, tilePos) -> world.playBlockEvent(tilePos, LevelListener.EVENT_ACID_SPREAD, 0))); + registerState(STATE_MILK, new BucketState( "milk", 0, @@ -210,6 +219,11 @@ public abstract class ItemBucket extends ItemFood implements IItemContainer { } if (currentState.canPlace()) { + NamespaceID aimedFluid = getFluidStateAt(world, tilePos); + if (currentStateId.equals(aimedFluid) && getCharges(itemStack) < this.maxCharges) { + return itemStack; + } + HitResult hitResultNoFluid = player.rayCast(reachDistance, 1f, false, false, false); if (hitResultNoFluid instanceof HitResult.Tile hitTileNoFluid) { return tryPlaceFluid(itemStack, world, player, hitTileNoFluid); diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemFireStriker.java b/game/core/src/main/java/net/minecraft/core/item/ItemFireStriker.java index da56e8899..d68dc74dc 100644 --- a/game/core/src/main/java/net/minecraft/core/item/ItemFireStriker.java +++ b/game/core/src/main/java/net/minecraft/core/item/ItemFireStriker.java @@ -5,6 +5,7 @@ import net.minecraft.core.block.BlockLogicBrazier; import net.minecraft.core.block.BlockLogicFluid; import net.minecraft.core.block.BlockLogicTNT; import net.minecraft.core.block.entity.TileEntityActivator; +import net.minecraft.core.block.tag.BlockTags; import net.minecraft.core.entity.player.Player; import net.minecraft.core.item.material.ToolMaterial; import net.minecraft.core.sound.SoundCategory; @@ -29,10 +30,18 @@ public class ItemFireStriker extends Item { @Override public boolean onUseOnBlock(@NotNull ItemStack selfStack, @NotNull World world, @Nullable Player player, @NotNull TilePosc blockPos, @NotNull Side side, double xHit, double yHit) { - blockPos = blockPos.add(side.direction(), new TilePos()); - if (world.isAirBlock(blockPos)) { - if (world.setBlockTypeNotify(blockPos, Blocks.FIRE)) { - world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, (double) blockPos.x() + 0.5D, (double) blockPos.y() + 0.5D, (double) blockPos.z() + 0.5D, "fire.ignite", 1.0F, itemRand.nextFloat() * 0.4F + 0.8F); + Block clickedBlock = world.getBlockType(blockPos); + + TilePos firePos = blockPos.add(side.direction(), new TilePos()); + + if (world.isAirBlock(firePos)) { + Block fireToPlace = Blocks.FIRE; + if (clickedBlock.hasTag(BlockTags.INFINITE_BURN_SULFURIC)) { + fireToPlace = Blocks.FIRE_SULFURIC; + } + + if (world.setBlockTypeNotify(firePos, fireToPlace)) { + world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, (double) firePos.x() + 0.5D, (double) firePos.y() + 0.5D, (double) firePos.z() + 0.5D, "fire.ignite", 1.0F, itemRand.nextFloat() * 0.4F + 0.8F); selfStack.damageItem(1, player); return true; } diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemPaintBrush.java b/game/core/src/main/java/net/minecraft/core/item/ItemPaintBrush.java index 4fbc6bc9b..9f20a442d 100644 --- a/game/core/src/main/java/net/minecraft/core/item/ItemPaintBrush.java +++ b/game/core/src/main/java/net/minecraft/core/item/ItemPaintBrush.java @@ -169,4 +169,11 @@ public class ItemPaintBrush extends Item { tag.putInt("Color", color.itemMeta); } } + + @Override + public @NotNull String getLanguageKey(@NotNull ItemStack selfStack) { + DyeColor color = getColor(selfStack); + if (color != null) return super.getKey() + "." + color.colorID; + return super.getKey(); + } } diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemRubyglassGrowth.java b/game/core/src/main/java/net/minecraft/core/item/ItemRubyglassGrowth.java new file mode 100644 index 000000000..010c6701e --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/item/ItemRubyglassGrowth.java @@ -0,0 +1,66 @@ +package net.minecraft.core.item; + +import net.minecraft.core.block.Block; +import net.minecraft.core.block.Blocks; +import net.minecraft.core.block.entity.TileEntityActivator; +import net.minecraft.core.entity.player.Player; +import net.minecraft.core.enums.EnumBlockSoundEffectType; +import net.minecraft.core.util.helper.Direction; +import net.minecraft.core.util.helper.Side; +import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Random; + +import static net.minecraft.core.block.BlockLogicGrowthRubyglass.STATE_BUD; + +public class ItemRubyglassGrowth extends Item { + + public ItemRubyglassGrowth(@NotNull String translationKey, @NotNull String namespaceId, int id, Block block) { + super(translationKey, namespaceId, id); + this.maxStackSize = 64; + } + + @Override + public boolean onUseOnBlock(@NotNull ItemStack selfStack, @NotNull World world, @Nullable Player player, @NotNull TilePosc blockPos, @NotNull Side side, double xHit, double yHit) { + if (player == null) return false; + + TilePos placePos = new TilePos(blockPos); + + if (!world.canPlaceInsideBlock(placePos)) { + placePos = placePos.add(side.direction(), new TilePos()); + } + + if (!Blocks.RUBYGLASS_GROWTH.getLogic().canPlaceAt(world, placePos)) return false; + + if (world.setBlockTypeNotify(placePos, Blocks.RUBYGLASS_GROWTH)) { + Blocks.RUBYGLASS_GROWTH.getLogic().onPlacedByMob(world, placePos, side, player, xHit, yHit); + + world.playBlockSoundEffect(player, (float) placePos.x() + 0.5F, (float) placePos.y() + 0.5F, (float) placePos.z() + 0.5F, Blocks.RUBYGLASS_GROWTH, EnumBlockSoundEffectType.PLACE); + Blocks.RUBYGLASS_GROWTH.onPlacedOnSide(world, placePos, side, 0.5, 0.5); + + selfStack.consumeItem(player); + return true; + } + + return false; + } + + @Override + public void onUseByActivator(@NotNull ItemStack selfStack, @NotNull World world, @NotNull TileEntityActivator activator, @NotNull Random random, @NotNull TilePosc blockPos, @NotNull Direction direction, double offX, double offY, double offZ) { + TilePos placePos = new TilePos(blockPos); + + if (!world.canPlaceInsideBlock(placePos)) { + placePos = placePos.add(direction, new TilePos()); + } + + if (Blocks.RUBYGLASS_GROWTH.getLogic().canPlaceAt(world, placePos)) { + world.setBlockTypeDataNotify(placePos, Blocks.RUBYGLASS_GROWTH, STATE_BUD); + world.playBlockSoundEffect(null, (float) placePos.x() + 0.5F, (float) placePos.y() + 0.5F, (float) placePos.z() + 0.5F, Blocks.RUBYGLASS_GROWTH, EnumBlockSoundEffectType.PLACE); + selfStack.consumeItem(null); + } + } +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/item/Items.java b/game/core/src/main/java/net/minecraft/core/item/Items.java index 3141a025f..d99e64d24 100644 --- a/game/core/src/main/java/net/minecraft/core/item/Items.java +++ b/game/core/src/main/java/net/minecraft/core/item/Items.java @@ -210,7 +210,7 @@ public final class Items { public static Item DOUGH; public static Item WAND_NBT; // public static Item RUBYGLASS_DUST; - public static Item RUBYGLASS_CRYSTAL; + public static Item RUBYGLASS; public static Item TIMER; public static Item ARMOR_WOLF_LEATHER; @@ -220,6 +220,14 @@ public final class Items { public static Item ARMOR_WOLF_GOLD; public static Item ARMOR_WOLF_STEEL; + public static Item SULFUR; + public static Item AMMO_ARROW_FLAMING; + + public static Item STATUE_SLATE; + public static Item STATUE_PERMAFROST; + public static Item STATUE_NETHERRACK; + public static Item STATUE_GLOOMSTONE; + private static boolean hasInit = false; public static void init(){ if (hasInit) return; @@ -444,8 +452,8 @@ public final class Items { FOOD_VENISON_COOKED = (new ItemFood("food.venison.cooked", "minecraft:item/food_venison_cooked", 16551, 12, 8, true, 4)); DOUGH = (new Item("dough", "minecraft:item/dough", 16552)); WAND_NBT = new ItemWandNBT("wand.nbt", "minecraft:item/wand_nbt", 16553); -// RUBYGLASS_DUST = (new Item("rubyglass.crystal.cracked", "minecraft:item/rubyglass_crystal_cracked", 16554)); - RUBYGLASS_CRYSTAL = (new Item("rubyglass.crystal.pure", "minecraft:item/rubyglass_crystal_pure", 16555)); + + RUBYGLASS = (new Item("rubyglass", "minecraft:item/rubyglass_crystal", 16555)); ARMOR_WOLF_LEATHER = new ItemArmor<>("armor.wolf.leather", "minecraft:item/armor_wolf_leather", 16556, ArmorMaterial.LEATHER, WolfArmorShape.BODY); @@ -457,5 +465,14 @@ public final class Items { BUCKET_IRON = (new ItemBucketIron("bucket.iron", "minecraft:item/bucket_iron", 16562)); BUCKET_STEEL = (new ItemBucketSteel("bucket.steel", "minecraft:item/bucket_steel", 16563)); + + SULFUR = new Item("sulfur", "minecraft:item/sulfur", 16567); + AMMO_ARROW_FLAMING = new Item("ammo.arrow.flaming", "minecraft:item/ammo_arrow_flaming", 16568); + + STATUE_SLATE = new ItemStatue("statue.slate", "minecraft:item/statue_slate", 16571, Blocks.STATUE_SLATE_LOWER, Blocks.STATUE_SLATE_UPPER); + STATUE_PERMAFROST = new ItemStatue("statue.permafrost", "minecraft:item/statue_permafrost", 16572, Blocks.STATUE_PERMAFROST_LOWER, Blocks.STATUE_PERMAFROST_UPPER); + STATUE_NETHERRACK = new ItemStatue("statue.netherrack", "minecraft:item/statue_netherrack", 16573, Blocks.STATUE_NETHERRACK_LOWER, Blocks.STATUE_NETHERRACK_UPPER); + STATUE_GLOOMSTONE = new ItemStatue("statue.gloomstone", "minecraft:item/statue_gloomstone", 16574, Blocks.STATUE_GLOOMSTONE_LOWER, Blocks.STATUE_GLOOMSTONE_UPPER); + } } diff --git a/game/core/src/main/java/net/minecraft/core/item/material/ToolMaterial.java b/game/core/src/main/java/net/minecraft/core/item/material/ToolMaterial.java index 32919fec2..95768cb9f 100644 --- a/game/core/src/main/java/net/minecraft/core/item/material/ToolMaterial.java +++ b/game/core/src/main/java/net/minecraft/core/item/material/ToolMaterial.java @@ -7,7 +7,7 @@ public class ToolMaterial { public static final ToolMaterial iron = new ToolMaterial().setDurability(384).setEfficiency(6.0f, 8.0f).setMiningLevel(2); public static final ToolMaterial steel = new ToolMaterial().setDurability(4608).setEfficiency(7.0f, 14.0f).setMiningLevel(3); public static final ToolMaterial diamond = new ToolMaterial().setDurability(1536).setEfficiency(14.0f, 45.0f).setMiningLevel(3).setDamage(4).setBlockHitDelay(4); - public static final ToolMaterial gold = new ToolMaterial().setDurability(256).setEfficiency(7.0f, 12f).setMiningLevel(2).setSilkTouch(true); + public static final ToolMaterial gold = new ToolMaterial().setDurability(384).setEfficiency(7.0f, 12f).setMiningLevel(2).setSilkTouch(true).setBlockHitDelay(4); private int miningLevel; private int durability; diff --git a/game/core/src/main/java/net/minecraft/core/net/command/arguments/ArgumentTypeParticleId.java b/game/core/src/main/java/net/minecraft/core/net/command/arguments/ArgumentTypeParticleId.java index 38e49f8fb..359de42bf 100644 --- a/game/core/src/main/java/net/minecraft/core/net/command/arguments/ArgumentTypeParticleId.java +++ b/game/core/src/main/java/net/minecraft/core/net/command/arguments/ArgumentTypeParticleId.java @@ -51,6 +51,7 @@ public class ArgumentTypeParticleId implements ArgumentType { particleIds.add("ashmote"); particleIds.add("ventsmoke"); particleIds.add("rubyglassLightning"); + particleIds.add("acidBoiling"); } private static final List EXAMPLES = Arrays.asList("fireflyGreen", "explode", "soulflame"); diff --git a/game/core/src/main/java/net/minecraft/core/net/command/util/CommandHelper.java b/game/core/src/main/java/net/minecraft/core/net/command/util/CommandHelper.java index f2cec404d..00c9503b1 100644 --- a/game/core/src/main/java/net/minecraft/core/net/command/util/CommandHelper.java +++ b/game/core/src/main/java/net/minecraft/core/net/command/util/CommandHelper.java @@ -15,6 +15,7 @@ import net.minecraft.core.util.collection.NamespaceID; import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.world.WorldSource; import net.minecraft.core.world.generate.feature.*; +import net.minecraft.core.world.generate.feature.hanging.WorldFeatureHangingDungeon; import net.minecraft.core.world.generate.feature.tree.*; import net.minecraft.core.world.generate.feature.tree.spooner.*; import org.jetbrains.annotations.NotNull; @@ -211,6 +212,11 @@ public class CommandHelper { registerWorldFeatureClass(WorldFeatureSpoonerTreeRainforest.class); registerWorldFeatureClass(WorldFeatureSpoonerTreeRound.class); registerWorldFeatureClass(WorldFeatureSpoonerTreeStick.class); + + registerWorldFeatureClass(WorldFeatureHangingDungeon.Gloomstone.class, "HangingDungeonGloomstone"); + registerWorldFeatureClass(WorldFeatureHangingDungeon.Basalt.class, "HangingDungeonBasalt"); + registerWorldFeatureClass(WorldFeatureHangingDungeon.Netherrack.class, "HangingDungeonNetherrack"); + registerWorldFeatureClass(WorldFeatureHangingDungeon.Slate.class, "HangingDungeonSlate"); } public static void registerWorldFeatureClass(@NotNull final Class tClass) { diff --git a/game/core/src/main/java/net/minecraft/core/net/entity/NetEntityHandler.java b/game/core/src/main/java/net/minecraft/core/net/entity/NetEntityHandler.java index 18413628b..99a71308e 100644 --- a/game/core/src/main/java/net/minecraft/core/net/entity/NetEntityHandler.java +++ b/game/core/src/main/java/net/minecraft/core/net/entity/NetEntityHandler.java @@ -4,23 +4,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; -import net.minecraft.core.net.entity.entries.NetEntryAnimal; -import net.minecraft.core.net.entity.entries.NetEntryArrow; -import net.minecraft.core.net.entity.entries.NetEntryBoat; -import net.minecraft.core.net.entity.entries.NetEntryBobber; -import net.minecraft.core.net.entity.entries.NetEntryCannonball; -import net.minecraft.core.net.entity.entries.NetEntryEgg; -import net.minecraft.core.net.entity.entries.NetEntryFallingBlock; -import net.minecraft.core.net.entity.entries.NetEntryFireball; -import net.minecraft.core.net.entity.entries.NetEntryFirefly; -import net.minecraft.core.net.entity.entries.NetEntryItem; -import net.minecraft.core.net.entity.entries.NetEntryMinecart; -import net.minecraft.core.net.entity.entries.NetEntryPainting; -import net.minecraft.core.net.entity.entries.NetEntryPebble; -import net.minecraft.core.net.entity.entries.NetEntryPlayerServer; -import net.minecraft.core.net.entity.entries.NetEntrySnowball; -import net.minecraft.core.net.entity.entries.NetEntrySquid; -import net.minecraft.core.net.entity.entries.NetEntryPrimedTNT; +import net.minecraft.core.net.entity.entries.*; import net.minecraft.core.net.packet.Packet; import org.jetbrains.annotations.NotNull; @@ -150,5 +134,7 @@ public class NetEntityHandler { registerNetworkEntry(new NetEntryPrimedTNT(), 21); registerNetworkEntry(new NetEntryBobber(), 30); + + registerNetworkEntry(new NetEntryArrowFlaming(), 32); } } diff --git a/game/core/src/main/java/net/minecraft/core/net/entity/entries/NetEntryArrowFlaming.java b/game/core/src/main/java/net/minecraft/core/net/entity/entries/NetEntryArrowFlaming.java new file mode 100644 index 000000000..03f87625c --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/net/entity/entries/NetEntryArrowFlaming.java @@ -0,0 +1,55 @@ +package net.minecraft.core.net.entity.entries; + +import com.mojang.nbt.tags.CompoundTag; +import net.minecraft.core.entity.Entity; +import net.minecraft.core.entity.Mob; +import net.minecraft.core.entity.projectile.ProjectileArrowFlaming; +import net.minecraft.core.net.entity.EntityTracker; +import net.minecraft.core.net.entity.EntityTrackerEntry; +import net.minecraft.core.net.entity.ITrackedEntry; +import net.minecraft.core.net.entity.IVehicleEntry; +import net.minecraft.core.net.packet.PacketAddEntity; +import net.minecraft.core.world.World; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class NetEntryArrowFlaming implements IVehicleEntry, ITrackedEntry { + + public NetEntryArrowFlaming() { + } + + @Override + public @NotNull Class getAppliedClass() { + return ProjectileArrowFlaming.class; + } + + @Override + public int getTrackingDistance() { + return 64; + } + + @Override + public int getMovementPacketDelay() { + return 20; + } + + @Override + public boolean sendMotionUpdates() { + return false; + } + + @Override + public void onEntityTracked(EntityTracker tracker, EntityTrackerEntry trackerEntry, ProjectileArrowFlaming trackedObject) { + } + + @Override + public Entity getEntity(World world, double x, double y, double z, int metadata, boolean hasVelocity, double xd, double yd, double zd, Entity owner, @Nullable CompoundTag tag) { + return new ProjectileArrowFlaming(world, x, y, z); + } + + @Override + public PacketAddEntity getSpawnPacket(EntityTrackerEntry tracker, ProjectileArrowFlaming trackedObject) { + Mob entityliving = trackedObject.owner; + return new PacketAddEntity(trackedObject, 0, entityliving == null ? -1 : entityliving.id, trackedObject.xd, trackedObject.yd, trackedObject.zd); + } +} diff --git a/game/core/src/main/java/net/minecraft/core/player/inventory/CreativeBlocks.java b/game/core/src/main/java/net/minecraft/core/player/inventory/CreativeBlocks.java new file mode 100644 index 000000000..3382db5d9 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/player/inventory/CreativeBlocks.java @@ -0,0 +1,591 @@ +package net.minecraft.core.player.inventory; + +import net.minecraft.core.block.Block; +import net.minecraft.core.block.Blocks; +import net.minecraft.core.block.IPainted; +import net.minecraft.core.item.ItemStack; +import net.minecraft.core.util.helper.DyeColor; + +import java.util.List; + +public final class CreativeBlocks { + + private static final DyeColor[] RAINBOW_ORDER = { + DyeColor.RED, + DyeColor.ORANGE, + DyeColor.YELLOW, + DyeColor.LIME, + DyeColor.GREEN, + DyeColor.CYAN, + DyeColor.LIGHT_BLUE, + DyeColor.BLUE, + DyeColor.PURPLE, + DyeColor.MAGENTA, + DyeColor.PINK, + DyeColor.BROWN, + DyeColor.WHITE, + DyeColor.SILVER, + DyeColor.GRAY, + DyeColor.BLACK + }; + + public static void populate(List list) { + + addStoneTypes(list); + + addWoodTypes(list); + + //WOOL + addPainted(list, Blocks.WOOL, painted(Blocks.WOOL)); + + addNaturalTypes(list); + + addOrganicTypes(list); + + + //WORKSTATIONS + add(list, Blocks.WORKBENCH); + + add(list, Blocks.FURNACE_STONE_IDLE); + add(list, Blocks.FURNACE_BLAST_IDLE); + + add(list, Blocks.TROMMEL_IDLE); + + add(list, Blocks.CHEST_PLANKS_OAK); + addPainted(list, Blocks.CHEST_PLANKS_OAK_PAINTED, painted(Blocks.CHEST_PLANKS_OAK_PAINTED)); + + add(list, Blocks.BOOKSHELF_PLANKS_OAK); + add(list, Blocks.LADDER_OAK); + add(list, Blocks.TORCH_COAL); + + add(list, Blocks.GLASS); + add(list, Blocks.TRAPDOOR_GLASS); + + add(list, Blocks.GLASS_TINTED); + + add(list, Blocks.GLASS_STEEL); + + + addRedstoneTypes(list); + + addOreTypes(list); + + addStorageTypes(list); + + add(list, Blocks.PAPER_WALL); + add(list, Blocks.FENCE_PAPER_WALL); + + add(list, Blocks.FENCE_CHAINLINK); + add(list, Blocks.FENCE_STEEL); + + } + + public static void addStoneTypes(List list) { + // STONE + add(list, Blocks.STONE); + add(list, Blocks.MOSS_STONE); + + add(list, Blocks.COBBLE_STONE); + add(list, Blocks.STAIRS_COBBLE_STONE); + add(list, Blocks.SLAB_COBBLE_STONE); + add(list, Blocks.COBBLE_STONE_MOSSY); + + add(list, Blocks.BRICK_STONE); + add(list, Blocks.STAIRS_BRICK_STONE); + add(list, Blocks.SLAB_BRICK_STONE); + + add(list, Blocks.STONE_POLISHED); + add(list, Blocks.SLAB_STONE_POLISHED); + add(list, Blocks.STONE_CARVED); + + add(list, Blocks.BRICK_STONE_POLISHED); + add(list, Blocks.STAIRS_BRICK_STONE_POLISHED); + add(list, Blocks.SLAB_BRICK_STONE_POLISHED); + add(list, Blocks.BRICK_STONE_POLISHED_MOSSY); + + + //BASALT + add(list, Blocks.BASALT); + add(list, Blocks.MOSS_BASALT); + + add(list, Blocks.COBBLE_BASALT); + add(list, Blocks.STAIRS_COBBLE_BASALT); + add(list, Blocks.SLAB_COBBLE_BASALT); + add(list, Blocks.COBBLE_BASALT_MOSSY); + + add(list, Blocks.BRICK_BASALT); + add(list, Blocks.STAIRS_BRICK_BASALT); + add(list, Blocks.SLAB_BRICK_BASALT); + + add(list, Blocks.BASALT_POLISHED); + add(list, Blocks.SLAB_BASALT_POLISHED); + add(list, Blocks.BASALT_CARVED); + + + //LIMESTONE + add(list, Blocks.LIMESTONE); + add(list, Blocks.MOSS_LIMESTONE); + + add(list, Blocks.COBBLE_LIMESTONE); + add(list, Blocks.STAIRS_COBBLE_LIMESTONE); + add(list, Blocks.SLAB_COBBLE_LIMESTONE); + add(list, Blocks.COBBLE_LIMESTONE_MOSSY); + + add(list, Blocks.BRICK_LIMESTONE); + add(list, Blocks.STAIRS_BRICK_LIMESTONE); + add(list, Blocks.SLAB_BRICK_LIMESTONE); + + add(list, Blocks.LIMESTONE_POLISHED); + add(list, Blocks.SLAB_LIMESTONE_POLISHED); + add(list, Blocks.LIMESTONE_CARVED); + + + //GRANITE + add(list, Blocks.GRANITE); + add(list, Blocks.MOSS_GRANITE); + + add(list, Blocks.COBBLE_GRANITE); + add(list, Blocks.STAIRS_COBBLE_GRANITE); + add(list, Blocks.SLAB_COBBLE_GRANITE); + add(list, Blocks.COBBLE_GRANITE_MOSSY); + + add(list, Blocks.BRICK_GRANITE); + add(list, Blocks.STAIRS_BRICK_GRANITE); + add(list, Blocks.SLAB_BRICK_GRANITE); + + add(list, Blocks.GRANITE_POLISHED); + add(list, Blocks.SLAB_GRANITE_POLISHED); + add(list, Blocks.GRANITE_CARVED); + + + //PERMAFROST + add(list, Blocks.PERMAFROST); + + add(list, Blocks.COBBLE_PERMAFROST); + add(list, Blocks.STAIRS_COBBLE_PERMAFROST); + add(list, Blocks.SLAB_COBBLE_PERMAFROST); + + add(list, Blocks.BRICK_PERMAFROST); + add(list, Blocks.STAIRS_BRICK_PERMAFROST); + add(list, Blocks.SLAB_BRICK_PERMAFROST); + + add(list, Blocks.PERMAFROST_POLISHED); + add(list, Blocks.SLAB_PERMAFROST_POLISHED); + add(list, Blocks.PERMAFROST_CARVED); + + + //NETHERRACK + add(list, Blocks.NETHERRACK); + + add(list, Blocks.COBBLE_NETHERRACK); + add(list, Blocks.STAIRS_COBBLE_NETHERRACK); + add(list, Blocks.SLAB_COBBLE_NETHERRACK); + add(list, Blocks.COBBLE_NETHERRACK_CRYSTALLINE); + + add(list, Blocks.BRICK_NETHERRACK); + add(list, Blocks.STAIRS_BRICK_NETHERRACK); + add(list, Blocks.SLAB_BRICK_NETHERRACK); + + add(list, Blocks.NETHERRACK_POLISHED); + add(list, Blocks.SLAB_NETHERRACK_POLISHED); + add(list, Blocks.NETHERRACK_CARVED); + + + //GLOOMSTONE + add(list, Blocks.GLOOMSTONE); + + add(list, Blocks.COBBLE_GLOOMSTONE); + add(list, Blocks.STAIRS_COBBLE_GLOOMSTONE); + add(list, Blocks.SLAB_COBBLE_GLOOMSTONE); + + add(list, Blocks.BRICK_GLOOMSTONE); + add(list, Blocks.STAIRS_BRICK_GLOOMSTONE); + add(list, Blocks.SLAB_BRICK_GLOOMSTONE); + + add(list, Blocks.GLOOMSTONE_POLISHED); + add(list, Blocks.SLAB_GLOOMSTONE_POLISHED); + add(list, Blocks.GLOOMSTONE_CARVED); + + + //MARBLE + add(list, Blocks.MARBLE); + + add(list, Blocks.BRICK_MARBLE); + add(list, Blocks.STAIRS_BRICK_MARBLE); + add(list, Blocks.SLAB_BRICK_MARBLE); + + add(list, Blocks.PILLAR_MARBLE); + add(list, Blocks.CAPSTONE_MARBLE); + add(list, Blocks.SLAB_CAPSTONE_MARBLE); + + + //SLATE + add(list, Blocks.SLATE); + add(list, Blocks.LAYER_SLATE); + + add(list, Blocks.BRICK_SLATE); + add(list, Blocks.STAIRS_BRICK_SLATE); + add(list, Blocks.SLAB_BRICK_SLATE); + + add(list, Blocks.SLATE_POLISHED); + add(list, Blocks.SLAB_SLATE_POLISHED); + add(list, Blocks.SLATE_CARVED); + } + + public static void addWoodTypes(List list) { + add(list, Blocks.PLANKS_OAK); + addPainted(list, Blocks.PLANKS_OAK_PAINTED, painted(Blocks.PLANKS_OAK_PAINTED)); + + add(list, Blocks.STAIRS_PLANKS_OAK); + addPainted(list, Blocks.STAIRS_PLANKS_PAINTED, painted(Blocks.STAIRS_PLANKS_PAINTED)); + add(list, Blocks.SLAB_PLANKS_OAK); + addPainted(list, Blocks.SLAB_PLANKS_PAINTED, painted(Blocks.SLAB_PLANKS_PAINTED)); + + add(list, Blocks.FENCE_PLANKS_OAK); + addPainted(list, Blocks.FENCE_PLANKS_OAK_PAINTED, painted(Blocks.FENCE_PLANKS_OAK_PAINTED)); + + add(list, Blocks.FENCE_GATE_PLANKS_OAK); + addPainted(list, Blocks.FENCE_GATE_PLANKS_OAK_PAINTED, painted(Blocks.FENCE_GATE_PLANKS_OAK_PAINTED)); + + add(list, Blocks.TRAPDOOR_PLANKS_OAK); + addPainted(list, Blocks.TRAPDOOR_PLANKS_PAINTED, painted(Blocks.TRAPDOOR_PLANKS_PAINTED)); + } + + public static void addOrganicTypes(List list) { + //LOGS + add(list, Blocks.LOG_OAK); + add(list, Blocks.LOG_OAK_MOSSY); + add(list, Blocks.LOG_PINE); + add(list, Blocks.LOG_BIRCH); + add(list, Blocks.LOG_CHERRY); + add(list, Blocks.LOG_EUCALYPTUS); + add(list, Blocks.LOG_THORN); + add(list, Blocks.LOG_PALM); + add(list, Blocks.LOG_SCORCHED); + + + //LEAVES + add(list, Blocks.LEAVES_OAK); + add(list, Blocks.LAYER_LEAVES_OAK); + add(list, Blocks.LEAVES_OAK_RETRO); + add(list, Blocks.LEAVES_PINE); + add(list, Blocks.LEAVES_BIRCH); + add(list, Blocks.LEAVES_CHERRY); + add(list, Blocks.LEAVES_CHERRY_FLOWERING); + add(list, Blocks.LEAVES_EUCALYPTUS); + add(list, Blocks.LEAVES_THORN); + add(list, Blocks.LEAVES_PALM); + add(list, Blocks.LEAVES_SHRUB); + add(list, Blocks.LEAVES_CACAO); + + + //SAPLINGS + add(list, Blocks.SAPLING_OAK); + add(list, Blocks.SAPLING_OAK_RETRO); + add(list, Blocks.SAPLING_PINE); + add(list, Blocks.SAPLING_BIRCH); + add(list, Blocks.SAPLING_CHERRY); + add(list, Blocks.SAPLING_EUCALYPTUS); + add(list, Blocks.SAPLING_THORN); + add(list, Blocks.SAPLING_PALM); + add(list, Blocks.SAPLING_SHRUB); + add(list, Blocks.SAPLING_CACAO); + + + //FLOWERS + list.add(new ItemStack(Blocks.FLOWER_YELLOW, 1, 0)); +// list.add(new ItemStack(Blocks.FLOWER_YELLOW, 1, 32); +// list.add(new ItemStack(Blocks.FLOWER_YELLOW, 1, 64); +// list.add(new ItemStack(Blocks.FLOWER_YELLOW, 1, 96); + + list.add(new ItemStack(Blocks.FLOWER_RED, 1, 0)); +// list.add(new ItemStack(Blocks.FLOWER_RED, 1, 32); +// list.add(new ItemStack(Blocks.FLOWER_RED, 1, 64); +// list.add(new ItemStack(Blocks.FLOWER_RED, 1, 96); + + list.add(new ItemStack(Blocks.FLOWER_PINK, 1, 0)); +// list.add(new ItemStack(Blocks.FLOWER_PINK, 1, 32); +// list.add(new ItemStack(Blocks.FLOWER_PINK, 1, 64); +// list.add(new ItemStack(Blocks.FLOWER_PINK, 1, 96); + + list.add(new ItemStack(Blocks.FLOWER_PURPLE, 1, 0)); +// list.add(new ItemStack(Blocks.FLOWER_PURPLE, 1, 32); +// list.add(new ItemStack(Blocks.FLOWER_PURPLE, 1, 64); +// list.add(new ItemStack(Blocks.FLOWER_PURPLE, 1, 96); + + list.add(new ItemStack(Blocks.FLOWER_LIGHT_BLUE, 1, 0)); +// list.add(new ItemStack(Blocks.FLOWER_LIGHT_BLUE, 1, 32); +// list.add(new ItemStack(Blocks.FLOWER_LIGHT_BLUE, 1, 64); +// list.add(new ItemStack(Blocks.FLOWER_LIGHT_BLUE, 1, 96); + + list.add(new ItemStack(Blocks.FLOWER_ORANGE, 1, 0)); +// list.add(new ItemStack(Blocks.FLOWER_ORANGE, 1, 32); +// list.add(new ItemStack(Blocks.FLOWER_ORANGE, 1, 64); +// list.add(new ItemStack(Blocks.FLOWER_ORANGE, 1, 96); + + add(list, Blocks.MUSHROOM_BROWN); + add(list, Blocks.MUSHROOM_RED); + + //FOLIAGE + add(list, Blocks.TALLGRASS); + add(list, Blocks.TALLGRASS_FERN); + add(list, Blocks.DEADBUSH); + add(list, Blocks.SPINIFEX); + add(list, Blocks.ALGAE); + add(list, Blocks.CACTUS); + + add(list, Blocks.PUMPKIN); + add(list, Blocks.PUMPKIN_CARVED_IDLE); + add(list, Blocks.PUMPKIN_CARVED_ACTIVE); + + add(list, Blocks.BLOCK_SUGARCANE); + add(list, Blocks.BLOCK_SUGARCANE_BAKED); + + add(list, Blocks.SPONGE_DRY); + add(list, Blocks.SPONGE_WET); + + add(list, Blocks.PUMICE_DRY); + add(list, Blocks.PUMICE_WET); + + add(list, Blocks.COBWEB); + + add(list, Blocks.BONE_PILE); + add(list, Blocks.SOUL_CATCHER); + add(list, Blocks.BOULDER_MAGMATIC); + add(list, Blocks.BOULDER_SULFURIC); + } + + public static void addNaturalTypes(List list) { + add(list, Blocks.GRASS); + add(list, Blocks.GRASS_SCORCHED); + add(list, Blocks.GRASS_RETRO); + + add(list, Blocks.DIRT); + add(list, Blocks.PATH_DIRT); + add(list, Blocks.FARMLAND_DIRT); + + add(list, Blocks.DIRT_SCORCHED); + add(list, Blocks.DIRT_SCORCHED_RICH); + + add(list, Blocks.MUD); + add(list, Blocks.MUD_BAKED); + + add(list, Blocks.SAND); + + add(list, Blocks.SANDSTONE); + add(list, Blocks.STAIRS_SANDSTONE); + add(list, Blocks.SLAB_SANDSTONE); + + add(list, Blocks.BRICK_SANDSTONE); + add(list, Blocks.STAIRS_BRICK_SANDSTONE); + add(list, Blocks.SLAB_BRICK_SANDSTONE); + + add(list, Blocks.GRAVEL); + + add(list, Blocks.BRIMSAND); + + add(list, Blocks.BRIMSTONE); + add(list, Blocks.BRIMTHAW); + add(list, Blocks.STAIRS_BRIMSTONE); + add(list, Blocks.SLAB_BRIMSTONE); + + add(list, Blocks.BRICK_BRIMSTONE); + add(list, Blocks.STAIRS_BRICK_BRIMSTONE); + add(list, Blocks.SLAB_BRICK_BRIMSTONE); + + add(list, Blocks.SULFUR); + add(list, Blocks.SULFUR_HARDENED); + + add(list, Blocks.BLOCK_SNOW); + add(list, Blocks.LAYER_SNOW); + + add(list, Blocks.BLOCK_ASH); + add(list, Blocks.LAYER_ASH); + + add(list, Blocks.ICE); + add(list, Blocks.PERMAICE); + + add(list, Blocks.BLOCK_CLAY); + + add(list, Blocks.BRICK_CLAY); + add(list, Blocks.STAIRS_BRICK_CLAY); + add(list, Blocks.SLAB_BRICK_CLAY); + + add(list, Blocks.OBSIDIAN); + add(list, Blocks.BONESHALE); + add(list, Blocks.BEDROCK); + + add(list, Blocks.MAGMA); + add(list, Blocks.SOULSAND); + add(list, Blocks.SOULSCHIST); + + add(list, Blocks.GLOWSTONE); + + add(list, Blocks.THERMAL_VENT); + + add(list, Blocks.EMBER); + } + + public static void addRedstoneTypes(List list) { + add(list, Blocks.TORCH_REDSTONE_ACTIVE); + add(list, Blocks.LEVER_COBBLE_STONE); + + add(list, Blocks.BUTTON_STONE); + add(list, Blocks.BUTTON_PLANKS); + addPainted(list, Blocks.BUTTON_PLANKS_PAINTED, painted(Blocks.BUTTON_PLANKS_PAINTED)); + + add(list, Blocks.PRESSURE_PLATE_STONE); + add(list, Blocks.PRESSURE_PLATE_COBBLE_STONE); + add(list, Blocks.PRESSURE_PLATE_PLANKS_OAK); + addPainted(list, Blocks.PRESSURE_PLATE_PLANKS_OAK_PAINTED, painted(Blocks.PRESSURE_PLATE_PLANKS_OAK_PAINTED)); + + add(list, Blocks.PISTON_BASE); + add(list, Blocks.PISTON_BASE_STICKY); + add(list, Blocks.PISTON_BASE_STEEL); + + add(list, Blocks.DISPENSER_COBBLE_STONE); + add(list, Blocks.MOTION_SENSOR_IDLE); + add(list, Blocks.ACTIVATOR); + add(list, Blocks.MATCHER); + + add(list, Blocks.PUMPKIN_REDSTONE); + + add(list, Blocks.RUBYGLASS_COLUMN); + add(list, Blocks.RUBYGLASS_NODE); + add(list, Blocks.BLOCK_RUBYGLASS); + add(list, Blocks.CONDUIT); + add(list, Blocks.RUBYGLASS_GROWTH); + add(list, Blocks.RUBYGLASS_CRYSTAL); + + add(list, Blocks.BRAZIER_INACTIVE); + + add(list, Blocks.MESH); + add(list, Blocks.MESH_GOLD); + + add(list, Blocks.MOBSPAWNER); + add(list, Blocks.MOBSPAWNER_DEACTIVATED); + + add(list, Blocks.NOTEBLOCK); + add(list, Blocks.JUKEBOX); + + add(list, Blocks.RAIL); + add(list, Blocks.RAIL_POWERED); + add(list, Blocks.RAIL_DETECTOR); + + add(list, Blocks.TNT); + add(list, Blocks.SPIKES); + + add(list, Blocks.TRAPDOOR_IRON); + add(list, Blocks.TRAPDOOR_STEEL); + + addPainted(list, Blocks.LAMP_IDLE, painted(Blocks.LAMP_IDLE)); + } + + public static void addOreTypes(List list) { + add(list, Blocks.ORE_COAL_STONE); + add(list, Blocks.ORE_COAL_BASALT); + add(list, Blocks.ORE_COAL_LIMESTONE); + add(list, Blocks.ORE_COAL_GRANITE); + add(list, Blocks.ORE_COAL_PERMAFROST); + + add(list, Blocks.ORE_IRON_STONE); + add(list, Blocks.ORE_IRON_BASALT); + add(list, Blocks.ORE_IRON_LIMESTONE); + add(list, Blocks.ORE_IRON_GRANITE); + add(list, Blocks.ORE_IRON_PERMAFROST); + + add(list, Blocks.ORE_GOLD_STONE); + add(list, Blocks.ORE_GOLD_BASALT); + add(list, Blocks.ORE_GOLD_LIMESTONE); + add(list, Blocks.ORE_GOLD_GRANITE); + add(list, Blocks.ORE_GOLD_PERMAFROST); + + add(list, Blocks.ORE_LAPIS_STONE); + add(list, Blocks.ORE_LAPIS_BASALT); + add(list, Blocks.ORE_LAPIS_LIMESTONE); + add(list, Blocks.ORE_LAPIS_GRANITE); + add(list, Blocks.ORE_LAPIS_PERMAFROST); + + add(list, Blocks.ORE_REDSTONE_STONE); + add(list, Blocks.ORE_REDSTONE_BASALT); + add(list, Blocks.ORE_REDSTONE_LIMESTONE); + add(list, Blocks.ORE_REDSTONE_GRANITE); + add(list, Blocks.ORE_REDSTONE_PERMAFROST); + + add(list, Blocks.ORE_DIAMOND_STONE); + add(list, Blocks.ORE_DIAMOND_BASALT); + add(list, Blocks.ORE_DIAMOND_LIMESTONE); + add(list, Blocks.ORE_DIAMOND_GRANITE); + add(list, Blocks.ORE_DIAMOND_PERMAFROST); + + add(list, Blocks.ORE_NETHERCOAL_BASALT); + add(list, Blocks.ORE_NETHERCOAL_NETHERRACK); + add(list, Blocks.ORE_NETHERCOAL_GLOOMSTONE); + } + + public static void addStorageTypes(List list) { + add(list, Blocks.BLOCK_IRON); + add(list, Blocks.BLOCK_STEEL); + add(list, Blocks.BLOCK_GOLD); + add(list, Blocks.BLOCK_LAPIS); + add(list, Blocks.BLOCK_REDSTONE); + add(list, Blocks.BLOCK_DIAMOND); + add(list, Blocks.BLOCK_QUARTZ); + + add(list, Blocks.BLOCK_COAL); + add(list, Blocks.BLOCK_CHARCOAL); + add(list, Blocks.BLOCK_NETHER_COAL); + add(list, Blocks.BLOCK_OLIVINE); + + add(list, Blocks.BRICK_IRON); + add(list, Blocks.STAIRS_BRICK_IRON); + add(list, Blocks.SLAB_BRICK_IRON); + + add(list, Blocks.BRICK_STEEL); + add(list, Blocks.STAIRS_BRICK_STEEL); + add(list, Blocks.SLAB_BRICK_STEEL); + + add(list, Blocks.BRICK_GOLD); + add(list, Blocks.STAIRS_BRICK_GOLD); + add(list, Blocks.SLAB_BRICK_GOLD); + + add(list, Blocks.BRICK_LAPIS); + add(list, Blocks.STAIRS_BRICK_LAPIS); + add(list, Blocks.SLAB_BRICK_LAPIS); + + add(list, Blocks.BRICK_DIAMOND); + add(list, Blocks.STAIRS_BRICK_DIAMOND); + add(list, Blocks.SLAB_BRICK_DIAMOND); + + add(list, Blocks.BRICK_QUARTZ); + add(list, Blocks.STAIRS_BRICK_QUARTZ); + add(list, Blocks.SLAB_BRICK_QUARTZ); + + add(list, Blocks.BRICK_OLIVINE); + add(list, Blocks.STAIRS_BRICK_OLIVINE); + add(list, Blocks.SLAB_BRICK_OLIVINE); + + add(list, Blocks.BRICK_RUBYGLASS); + add(list, Blocks.STAIRS_BRICK_RUBYGLASS); + add(list, Blocks.SLAB_BRICK_RUBYGLASS); + + } + + private static void addPainted(List list, Block block, IPainted painted) { + for (DyeColor color : RAINBOW_ORDER) { + list.add(new ItemStack(block, 1, painted.toMetadata(color))); + } + } + + private static void add(List list, Block... blocks) { + for (Block block : blocks) { + list.add(new ItemStack(block)); + } + } + + private static IPainted painted(Block block) { + return (IPainted) block.getLogic(); + } + +} + diff --git a/game/core/src/main/java/net/minecraft/core/player/inventory/CreativeItems.java b/game/core/src/main/java/net/minecraft/core/player/inventory/CreativeItems.java new file mode 100644 index 000000000..959f19131 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/player/inventory/CreativeItems.java @@ -0,0 +1,331 @@ +package net.minecraft.core.player.inventory; + +import net.minecraft.core.item.Item; +import net.minecraft.core.item.ItemBucket; +import net.minecraft.core.item.ItemStack; +import net.minecraft.core.item.Items; +import net.minecraft.core.util.collection.NamespaceID; +import net.minecraft.core.util.helper.DyeColor; + +import java.util.List; + +public final class CreativeItems { + + private static final DyeColor[] RAINBOW_ORDER = { + DyeColor.RED, + DyeColor.ORANGE, + DyeColor.YELLOW, + DyeColor.LIME, + DyeColor.GREEN, + DyeColor.CYAN, + DyeColor.LIGHT_BLUE, + DyeColor.BLUE, + DyeColor.PURPLE, + DyeColor.MAGENTA, + DyeColor.PINK, + DyeColor.BROWN, + DyeColor.WHITE, + DyeColor.SILVER, + DyeColor.GRAY, + DyeColor.BLACK + }; + + private static void addBucketVariants(List out, Item item) { + if (item instanceof ItemBucket itemBucket) { + out.add(new ItemStack(item)); + for (NamespaceID stateId : ItemBucket.getRegisteredStateIds()) { + if (!ItemBucket.STATE_EMPTY.equals(stateId)) { + ItemStack itemStack = new ItemStack(item, 1); + ItemBucket.setState(itemStack, stateId); + ItemBucket.setCharges(itemStack, itemBucket.maxCharges); + out.add(itemStack); + } + } + } + } + + public static void populate(List out) { + + //TOOLS + out.add(new ItemStack(Items.TOOL_SHOVEL_WOOD)); + out.add(new ItemStack(Items.TOOL_PICKAXE_WOOD)); + out.add(new ItemStack(Items.TOOL_AXE_WOOD)); + out.add(new ItemStack(Items.TOOL_HOE_WOOD)); + out.add(new ItemStack(Items.TOOL_SWORD_WOOD)); + + out.add(new ItemStack(Items.TOOL_SHOVEL_STONE)); + out.add(new ItemStack(Items.TOOL_PICKAXE_STONE)); + out.add(new ItemStack(Items.TOOL_AXE_STONE)); + out.add(new ItemStack(Items.TOOL_HOE_STONE)); + out.add(new ItemStack(Items.TOOL_SWORD_STONE)); + + out.add(new ItemStack(Items.TOOL_SHOVEL_IRON)); + out.add(new ItemStack(Items.TOOL_PICKAXE_IRON)); + out.add(new ItemStack(Items.TOOL_AXE_IRON)); + out.add(new ItemStack(Items.TOOL_HOE_IRON)); + out.add(new ItemStack(Items.TOOL_SWORD_IRON)); + + out.add(new ItemStack(Items.TOOL_SHOVEL_GOLD)); + out.add(new ItemStack(Items.TOOL_PICKAXE_GOLD)); + out.add(new ItemStack(Items.TOOL_AXE_GOLD)); + out.add(new ItemStack(Items.TOOL_HOE_GOLD)); + out.add(new ItemStack(Items.TOOL_SWORD_GOLD)); + + out.add(new ItemStack(Items.TOOL_SHOVEL_DIAMOND)); + out.add(new ItemStack(Items.TOOL_PICKAXE_DIAMOND)); + out.add(new ItemStack(Items.TOOL_AXE_DIAMOND)); + out.add(new ItemStack(Items.TOOL_HOE_DIAMOND)); + out.add(new ItemStack(Items.TOOL_SWORD_DIAMOND)); + + out.add(new ItemStack(Items.TOOL_SHOVEL_STEEL)); + out.add(new ItemStack(Items.TOOL_PICKAXE_STEEL)); + out.add(new ItemStack(Items.TOOL_AXE_STEEL)); + out.add(new ItemStack(Items.TOOL_HOE_STEEL)); + out.add(new ItemStack(Items.TOOL_SWORD_STEEL)); + + + //MISC TOOLS + out.add(new ItemStack(Items.TOOL_FIRESTRIKER_IRON)); + out.add(new ItemStack(Items.TOOL_FIRESTRIKER_STEEL)); + + out.add(new ItemStack(Items.TOOL_SHEARS)); + out.add(new ItemStack(Items.TOOL_SHEARS_STEEL)); + + addBucketVariants(out, Items.BUCKET_IRON); + addBucketVariants(out, Items.BUCKET_STEEL); + + out.add(new ItemStack(Items.PAINTBRUSH)); + + out.add(new ItemStack(Items.TOOL_FISHINGROD)); + + out.add(new ItemStack(Items.TOOL_BOW)); + out.add(new ItemStack(Items.AMMO_ARROW)); + out.add(new ItemStack(Items.AMMO_ARROW_GOLD)); + out.add(new ItemStack(Items.AMMO_ARROW_PURPLE)); + out.add(new ItemStack(Items.AMMO_ARROW_FLAMING)); + + out.add(new ItemStack(Items.HANDCANNON_UNLOADED)); + out.add(new ItemStack(Items.AMMO_CHARGE_EXPLOSIVE)); + + out.add(new ItemStack(Items.AMMO_FIREBALL)); + + out.add(new ItemStack(Items.TOOL_COMPASS)); + out.add(new ItemStack(Items.TOOL_CLOCK)); + out.add(new ItemStack(Items.TOOL_CALENDAR)); + out.add(new ItemStack(Items.MAP)); + + out.add(new ItemStack(Items.ROPE)); + + out.add(new ItemStack(Items.LABEL)); + + out.add(new ItemStack(Items.WAND_MONSTER_SPAWNER)); + out.add(new ItemStack(Items.WAND_NBT)); + + + //ARMOR + out.add(new ItemStack(Items.ARMOR_HELMET_LEATHER)); + out.add(new ItemStack(Items.ARMOR_CHESTPLATE_LEATHER)); + out.add(new ItemStack(Items.ARMOR_LEGGINGS_LEATHER)); + out.add(new ItemStack(Items.ARMOR_BOOTS_LEATHER)); + + out.add(new ItemStack(Items.ARMOR_HELMET_CHAINMAIL)); + out.add(new ItemStack(Items.ARMOR_CHESTPLATE_CHAINMAIL)); + out.add(new ItemStack(Items.ARMOR_LEGGINGS_CHAINMAIL)); + out.add(new ItemStack(Items.ARMOR_BOOTS_CHAINMAIL)); + + out.add(new ItemStack(Items.ARMOR_HELMET_IRON)); + out.add(new ItemStack(Items.ARMOR_CHESTPLATE_IRON)); + out.add(new ItemStack(Items.ARMOR_LEGGINGS_IRON)); + out.add(new ItemStack(Items.ARMOR_BOOTS_IRON)); + + out.add(new ItemStack(Items.ARMOR_HELMET_GOLD)); + out.add(new ItemStack(Items.ARMOR_CHESTPLATE_GOLD)); + out.add(new ItemStack(Items.ARMOR_LEGGINGS_GOLD)); + out.add(new ItemStack(Items.ARMOR_BOOTS_GOLD)); + + out.add(new ItemStack(Items.ARMOR_HELMET_DIAMOND)); + out.add(new ItemStack(Items.ARMOR_CHESTPLATE_DIAMOND)); + out.add(new ItemStack(Items.ARMOR_LEGGINGS_DIAMOND)); + out.add(new ItemStack(Items.ARMOR_BOOTS_DIAMOND)); + + out.add(new ItemStack(Items.ARMOR_HELMET_STEEL)); + out.add(new ItemStack(Items.ARMOR_CHESTPLATE_STEEL)); + out.add(new ItemStack(Items.ARMOR_LEGGINGS_STEEL)); + out.add(new ItemStack(Items.ARMOR_BOOTS_STEEL)); + + out.add(new ItemStack(Items.ARMOR_QUIVER)); + out.add(new ItemStack(Items.ARMOR_QUIVER_GOLD)); + out.add(new ItemStack(Items.ARMOR_BOOTS_ICESKATES)); + + out.add(new ItemStack(Items.ARMOR_WOLF_LEATHER)); + out.add(new ItemStack(Items.ARMOR_WOLF_CHAINMAIL)); + out.add(new ItemStack(Items.ARMOR_WOLF_IRON)); + out.add(new ItemStack(Items.ARMOR_WOLF_GOLD)); + out.add(new ItemStack(Items.ARMOR_WOLF_DIAMOND)); + out.add(new ItemStack(Items.ARMOR_WOLF_STEEL)); + + + //FOOD + out.add(new ItemStack(Items.FOOD_APPLE)); + out.add(new ItemStack(Items.FOOD_APPLE_GOLD)); + + out.add(new ItemStack(Items.FOOD_CHERRY)); + + out.add(new ItemStack(Items.FOOD_PORKCHOP_RAW)); + out.add(new ItemStack(Items.FOOD_PORKCHOP_COOKED)); + + out.add(new ItemStack(Items.FOOD_VENISON_RAW)); + out.add(new ItemStack(Items.FOOD_VENISON_COOKED)); + + out.add(new ItemStack(Items.FOOD_FISH_RAW)); + out.add(new ItemStack(Items.FOOD_FISH_COOKED)); + + out.add(new ItemStack(Items.DUST_SUGAR)); + out.add(new ItemStack(Items.EGG_CHICKEN)); + + out.add(new ItemStack(Items.SEEDS_WHEAT)); + out.add(new ItemStack(Items.SEEDS_PUMPKIN)); + + out.add(new ItemStack(Items.WHEAT)); + out.add(new ItemStack(Items.DOUGH)); + out.add(new ItemStack(Items.FOOD_BREAD)); + + out.add(new ItemStack(Items.FOOD_COOKIE)); + out.add(new ItemStack(Items.FOOD_CAKE)); + out.add(new ItemStack(Items.FOOD_PUMPKIN_PIE)); + + out.add(new ItemStack(Items.BOWL)); + out.add(new ItemStack(Items.FOOD_STEW_MUSHROOM)); + + + //ORE + out.add(new ItemStack(Items.AMMO_PEBBLE)); + + out.add(new ItemStack(Items.COAL)); + out.add(new ItemStack(Items.COAL, 1, 1)); + out.add(new ItemStack(Items.NETHERCOAL)); + out.add(new ItemStack(Items.OLIVINE)); + + out.add(new ItemStack(Items.ORE_RAW_IRON)); + out.add(new ItemStack(Items.INGOT_IRON)); + + out.add(new ItemStack(Items.DIAMOND)); + + out.add(new ItemStack(Items.INGOT_STEEL_CRUDE)); + out.add(new ItemStack(Items.INGOT_STEEL)); + + out.add(new ItemStack(Items.ORE_RAW_GOLD)); + out.add(new ItemStack(Items.INGOT_GOLD)); + + out.add(new ItemStack(Items.DUST_REDSTONE)); + + out.add(new ItemStack(Items.REPEATER)); + + out.add(new ItemStack(Items.TIMER)); + + out.add(new ItemStack(Items.QUARTZ)); + + out.add(new ItemStack(Items.FLINT)); + out.add(new ItemStack(Items.CLAY)); + out.add(new ItemStack(Items.BRICK_CLAY)); + + out.add(new ItemStack(Items.DUST_GLOWSTONE)); + + out.add(new ItemStack(Items.RUBYGLASS)); + + out.add(new ItemStack(Items.SULFUR)); + + + //Materials + out.add(new ItemStack(Items.STICK)); + out.add(new ItemStack(Items.AMMO_SNOWBALL)); + out.add(new ItemStack(Items.SUGARCANE)); + out.add(new ItemStack(Items.PAPER)); + out.add(new ItemStack(Items.BOOK)); + for (DyeColor color : RAINBOW_ORDER) { + int meta = color.itemMeta; + out.add(new ItemStack(Items.DYE, 1, meta)); + } + + //Mob Drops + out.add(new ItemStack(Items.CLOTH)); + out.add(new ItemStack(Items.STRING)); + out.add(new ItemStack(Items.FEATHER_CHICKEN)); + out.add(new ItemStack(Items.GUNPOWDER)); + out.add(new ItemStack(Items.BONE)); + out.add(new ItemStack(Items.CHAINLINK)); + out.add(new ItemStack(Items.SLIMEBALL)); + out.add(new ItemStack(Items.LEATHER)); + + //Placeables + out.add(new ItemStack(Items.PAINTING)); + + out.add(new ItemStack(Items.DOOR_OAK)); + for (DyeColor color : RAINBOW_ORDER) { + int meta = color.itemMeta; + out.add(new ItemStack(Items.DOOR_OAK_PAINTED, 1, meta)); + } + + out.add(new ItemStack(Items.DOOR_GLASS)); + out.add(new ItemStack(Items.DOOR_IRON)); + out.add(new ItemStack(Items.DOOR_STEEL)); + + out.add(new ItemStack(Items.SIGN)); + for (DyeColor color : RAINBOW_ORDER) { + int meta = color.itemMeta; + out.add(new ItemStack(Items.SIGN_PAINTED, 1, meta)); + } + + out.add(new ItemStack(Items.FLAG)); + out.add(new ItemStack(Items.BED)); + out.add(new ItemStack(Items.SEAT)); + + out.add(new ItemStack(Items.BASKET)); + + out.add(new ItemStack(Items.JAR)); + + out.add(new ItemStack(Items.LANTERN_FIREFLY_GREEN)); + out.add(new ItemStack(Items.LANTERN_FIREFLY_BLUE)); + out.add(new ItemStack(Items.LANTERN_FIREFLY_ORANGE)); + out.add(new ItemStack(Items.LANTERN_FIREFLY_RED)); + + out.add(new ItemStack(Items.JAR_BUTTERFLY_BLUE)); + out.add(new ItemStack(Items.JAR_BUTTERFLY_ORANGE)); + out.add(new ItemStack(Items.JAR_BUTTERFLY_PINK)); + out.add(new ItemStack(Items.JAR_BUTTERFLY_SILVER)); + + out.add(new ItemStack(Items.STATUE_STONE)); + out.add(new ItemStack(Items.STATUE_BASALT)); + out.add(new ItemStack(Items.STATUE_LIMESTONE)); + out.add(new ItemStack(Items.STATUE_GRANITE)); + out.add(new ItemStack(Items.STATUE_PERMAFROST)); + out.add(new ItemStack(Items.STATUE_MARBLE)); + out.add(new ItemStack(Items.STATUE_SLATE)); + out.add(new ItemStack(Items.STATUE_NETHERRACK)); + out.add(new ItemStack(Items.STATUE_GLOOMSTONE)); + out.add(new ItemStack(Items.STATUE_PIGMAN)); + + out.add(new ItemStack(Items.SADDLE)); + + out.add(new ItemStack(Items.BOAT)); + + out.add(new ItemStack(Items.MINECART)); + out.add(new ItemStack(Items.MINECART_CHEST)); + out.add(new ItemStack(Items.MINECART_FURNACE)); + + // Records + out.add(new ItemStack(Items.RECORD_13)); + out.add(new ItemStack(Items.RECORD_CAT)); + + out.add(new ItemStack(Items.RECORD_BLOCKS)); + out.add(new ItemStack(Items.RECORD_CHIRP)); + out.add(new ItemStack(Items.RECORD_FAR)); + out.add(new ItemStack(Items.RECORD_MALL)); + out.add(new ItemStack(Items.RECORD_MELLOHI)); + out.add(new ItemStack(Items.RECORD_STAL)); + out.add(new ItemStack(Items.RECORD_STRAD)); + out.add(new ItemStack(Items.RECORD_WARD)); + out.add(new ItemStack(Items.RECORD_WAIT)); + out.add(new ItemStack(Items.RECORD_DOG)); + } +} diff --git a/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuInventoryCreative.java b/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuInventoryCreative.java index a721eea58..75b22c5cf 100644 --- a/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuInventoryCreative.java +++ b/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuInventoryCreative.java @@ -7,6 +7,8 @@ import net.minecraft.core.item.*; import net.minecraft.core.item.tag.ItemTags; import net.minecraft.core.lang.I18n; import net.minecraft.core.block.Blocks; +import net.minecraft.core.player.inventory.CreativeBlocks; +import net.minecraft.core.player.inventory.CreativeItems; import net.minecraft.core.player.inventory.container.ContainerInventory; import net.minecraft.core.player.inventory.slot.SlotCreative; import net.minecraft.core.util.collection.NamespaceID; @@ -124,7 +126,13 @@ public class MenuInventoryCreative extends MenuInventory static { - for (Block block : Blocks.blocksList) { + CreativeBlocks.populate(creativeItems); + CreativeItems.populate(creativeItems); + } + + // PREVIOUS IMPLEMENTATION: + + /*for (Block block : Blocks.blocksList) { if (block == null || block.hasTag(BlockTags.NOT_IN_CREATIVE_MENU)) continue; if (Block.hasLogicClass(block, IPainted.class)) { @@ -168,5 +176,5 @@ public class MenuInventoryCreative extends MenuInventory creativeItems.add(new ItemStack(item)); } } - } + }*/ } diff --git a/game/core/src/main/java/net/minecraft/core/sound/BlockSounds.java b/game/core/src/main/java/net/minecraft/core/sound/BlockSounds.java index f7e38683b..a4938201a 100644 --- a/game/core/src/main/java/net/minecraft/core/sound/BlockSounds.java +++ b/game/core/src/main/java/net/minecraft/core/sound/BlockSounds.java @@ -7,11 +7,18 @@ public abstract class BlockSounds public static final BlockSound GRAVEL = new BlockSound("step.gravel", "step.gravel", 1.0F, 1.0F); public static final BlockSound GRASS = new BlockSound("step.grass", "step.grass", 1.0F, 1.0F); public static final BlockSound STONE = new BlockSound("step.stone", "step.stone", 1.0F, 1.0F); - public static final BlockSound PERMAFROST = new BlockSound("step.permafrost", "step.permafrost", 1.0F, 1.0F); public static final BlockSound METAL = new BlockSound("step.stone", "step.stone", 1.0F, 1.5F); public static final BlockSound GLASS = new BlockSound("step.stone", "random.glass", 1.0F, 1.0F); public static final BlockSound CLOTH = new BlockSound("step.cloth", "step.cloth", 1.0F, 1.0F); public static final BlockSound SAND = new BlockSound("step.sand", "step.sand", 1.0F, 1.0F); public static final BlockSound FIRE = new BlockSound("", "random.fizz", 0.5F, 2.6F); + public static final BlockSound PERMAFROST = new BlockSound("step.permafrost", "step.permafrost", 1.0F, 1.0F); + public static final BlockSound ASH = new BlockSound("block.ash", "block.ash", 1.0F, 1.0F); + public static final BlockSound SOULSAND = new BlockSound("step.soulsand", "step.soulsand", 1.0F, 1.0F); + public static final BlockSound GLOOMSTONE = new BlockSound("step.gloomstone", "step.gloomstone", 1.0F, 1.0F); + public static final BlockSound BRIMSTONE = new BlockSound("step.brimstone", "step.brimstone", 1.0F, 1.0F); + public static final BlockSound CRYSTAL = new BlockSound("step.crystal", "step.crystal", 1.0F, 1.0F); + + } diff --git a/game/core/src/main/java/net/minecraft/core/util/helper/MathHelper.java b/game/core/src/main/java/net/minecraft/core/util/helper/MathHelper.java index f706e07a4..7abca18e0 100644 --- a/game/core/src/main/java/net/minecraft/core/util/helper/MathHelper.java +++ b/game/core/src/main/java/net/minecraft/core/util/helper/MathHelper.java @@ -4,6 +4,7 @@ package net.minecraft.core.util.helper; import net.minecraft.core.util.phys.HitResult; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.joml.Matrix2d; import org.joml.Vector3d; import org.joml.Vector3dc; import org.joml.primitives.AABBd; @@ -528,10 +529,48 @@ public class MathHelper { } } + public static @NotNull Matrix2d rotateVec2(double radians) { + return new Matrix2d(Math.cos(radians), -Math.sin(radians), Math.sin(radians), Math.cos(radians)); + } + static { SIN_TABLE = new float[0x10000]; for (int i = 0; i < 0x10000; i++) { SIN_TABLE[i] = (float) Math.sin(((double) i * Math.PI * 2D) / 65536D); } } + + /** + * Normalizes a degree angle to the range [-180, 180). + */ + public static float wrapDegrees(float value) { + value %= 360.0F; + + if (value >= 180.0F) { + value -= 360.0F; + } + + if (value < -180.0F) { + value += 360.0F; + } + + return value; + } + + /** + * Double version of wrapDegrees. + */ + public static double wrapDegrees(double value) { + value %= 360.0D; + + if (value >= 180.0D) { + value -= 360.0D; + } + + if (value < -180.0D) { + value += 360.0D; + } + + return value; + } } diff --git a/game/core/src/main/java/net/minecraft/core/world/LevelListener.java b/game/core/src/main/java/net/minecraft/core/world/LevelListener.java index 9312da9e5..96a6e15e7 100644 --- a/game/core/src/main/java/net/minecraft/core/world/LevelListener.java +++ b/game/core/src/main/java/net/minecraft/core/world/LevelListener.java @@ -62,6 +62,10 @@ public interface LevelListener * Bit 7: Unused (Reserved)
*/ int EVENT_CONDUIT_SURFACE_PARTICLES = 1009; + /** + * data: unused + */ + int EVENT_ACID_SPREAD = 1010; /** * Redraw block in singleplayer and send block change packet in multiplayer.
diff --git a/game/core/src/main/java/net/minecraft/core/world/World.java b/game/core/src/main/java/net/minecraft/core/world/World.java index 5f83f8b14..c3968a005 100644 --- a/game/core/src/main/java/net/minecraft/core/world/World.java +++ b/game/core/src/main/java/net/minecraft/core/world/World.java @@ -1,6 +1,7 @@ package net.minecraft.core.world; import com.mojang.logging.LogUtils; +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; @@ -47,6 +48,7 @@ import net.minecraft.core.world.chunk.provider.ChunkProvider; import net.minecraft.core.world.config.spawning.SpawnerConfig; import net.minecraft.core.world.lighting.LightingEngine; import net.minecraft.core.world.lighting.LightingEngineLegacy; +import net.minecraft.core.world.particle.ParticleEmitterRegistry; import net.minecraft.core.world.pathfinder.Path; import net.minecraft.core.world.pathfinder.PathFinder; import net.minecraft.core.world.pos.*; @@ -113,11 +115,14 @@ public abstract class World implements MutableWorldSource { public final @NotNull List<@NotNull AABBdc> collidingBoundingBoxes = new ObjectArrayList<>(); private final @NotNull List<@NotNull LevelListener> listeners = new ObjectArrayList<>(); - private final @NotNull Set<@NotNull ChunkPosc> positionsToUpdate = new ObjectOpenHashSet<>(); + private final @NotNull LongOpenHashSet positionsToUpdate = new LongOpenHashSet(); private final @NotNull List<@NotNull Entity> entityBuffer = new ObjectArrayList<>(); private final @NotNull Set<@NotNull NextTickListEntry> immediatelyUpdatedPositions = new ObjectOpenHashSet<>(); + public final ParticleEmitterRegistry particleEmitters = new ParticleEmitterRegistry(); + public final @NotNull Random rand = new Random(); + private final AABBd workingBox = new AABBd(); public final @NotNull Dimension dimension; public final boolean isNewWorld; @@ -638,7 +643,7 @@ public abstract class World implements MutableWorldSource { public boolean setBlockTypeDataEntity(final @NotNull TilePosc tilePos, final @NotNull Block block, final int data, final @NotNull TileEntity entity) { if (!tilePos.inBounds(this)) return false; - + final var c = this.getChunk(tilePos); final var ctp = new ChunkTilePos(tilePos); final var prevBlock = c.getBlock(ctp); @@ -742,6 +747,11 @@ public abstract class World implements MutableWorldSource { public boolean setBlockTypeNotify(final @NotNull TilePosc tilePos, final @NotNull Block block) { if (this.setBlockType(tilePos, block)) { this.notifyBlockChange(tilePos, block); + + TilePos pos = new TilePos(tilePos); + this.scheduleLightingUpdate(LightLayer.Block, pos); + this.scheduleLightingUpdate(LightLayer.Sky, pos); + return true; } @@ -765,6 +775,11 @@ public abstract class World implements MutableWorldSource { public boolean setBlockTypeDataNotify(final @NotNull TilePosc tilePos, final @NotNull Block block, final int data) { if (this.setBlockTypeData(tilePos, block, data)) { this.notifyBlockChange(tilePos, block); + + TilePos pos = new TilePos(tilePos); + this.scheduleLightingUpdate(LightLayer.Block, pos); + this.scheduleLightingUpdate(LightLayer.Sky, pos); + return true; } @@ -846,7 +861,7 @@ public abstract class World implements MutableWorldSource { * or the block at the given position if null. */ public void notifyBlocksInRadiusOfNeighborChange( - final int radius, + final int radius, final @NotNull TilePosc tilePos, final @Nullable Block block ) { if (this.noNeighborUpdate || this.isClientSide) return; @@ -1122,6 +1137,7 @@ public abstract class World implements MutableWorldSource { return hitResult; } } + final Vector3d startCopy = new Vector3d(start2); for (int l1 = 200; l1-- >= 0; ) { if (!start2.isFinite()) { return null; @@ -1200,7 +1216,6 @@ public abstract class World implements MutableWorldSource { start2.y += d7 * d5; start2.z = d2; } - final Vector3d startCopy = new Vector3d(start2); blockStart.x = (int) (startCopy.x = MathHelper.floor(start2.x())); if (byte0 == 5) { blockStart.x--; @@ -1249,6 +1264,13 @@ public abstract class World implements MutableWorldSource { } } + public void playSoundEffectAtTile(@Nullable final Entity player, final SoundCategory category, TilePosc tilePosc, final String soundPath, + final float volume, final float pitch) { + for (final LevelListener listener : this.listeners) { + listener.playSound(player, soundPath, category, tilePosc.x(), tilePosc.y(), tilePosc.z(), volume, pitch); + } + } + public void playBlockSoundEffect(@Nullable final Entity player, final double x, final double y, final double z, final @NotNull Block block, final EnumBlockSoundEffectType soundType) { final BlockSound sound = block.getSound(); if (sound == null) return; @@ -1415,7 +1437,7 @@ public abstract class World implements MutableWorldSource { } final double radius = 0.25D; - final List entities = this.getEntitiesWithinAABBExcludingEntity(entity, MathHelper.aabbGrow(aabb, radius, radius, radius, new AABBd())); + final List entities = this.getEntitiesWithinAABBExcludingEntity(entity, MathHelper.aabbGrow(aabb, radius, radius, radius, workingBox)); for (final Entity e : entities) { final AABBdc entityBB = e.getCollisionAABB(); if (entityBB != null && entityBB.intersectsAABB((AABBd) aabb)) { @@ -1454,7 +1476,7 @@ public abstract class World implements MutableWorldSource { } final double d = 0.25D; - final List list = this.getEntitiesWithinAABBExcludingEntity(entity, MathHelper.aabbGrow(aabb, d, d, d, new AABBd())); + final List list = this.getEntitiesWithinAABBExcludingEntity(entity, MathHelper.aabbGrow(aabb, d, d, d, workingBox)); for (int j2 = 0; j2 < list.size(); j2++) { final AABBdc collisionBB = list.get(j2).getCollisionAABB(); if (collisionBB != null && collisionBB.intersectsAABB((AABBd) aabb)) { @@ -2199,8 +2221,8 @@ public abstract class World implements MutableWorldSource { final byte radius = 9; for (int x = -radius; x <= radius; x++) { for (int z = -radius; z <= radius; z++) { - this.positionsToUpdate.add(new ChunkPos(x + playerChunkX, z + playerChunkZ)); - } + long packedChunkPos = ((long) (x + playerChunkX) & 0xFFFFFFFFL) | (((long) (z + playerChunkZ) & 0xFFFFFFFFL) << 32); + this.positionsToUpdate.add(packedChunkPos);} } } @@ -2210,13 +2232,19 @@ public abstract class World implements MutableWorldSource { ChunkTilePos chunkTileQueryPos = new ChunkTilePos(); TilePos tileQueryPos = new TilePos(); final int randomTicks = this.getGameRuleValue(GameRules.RANDOM_TICK_SPEED); - for (final ChunkPosc chunkPos : this.positionsToUpdate) { - final int chunkBlockX = chunkPos.x() * Chunk.CHUNK_SIZE_X; - final int chunkBlockZ = chunkPos.z() * Chunk.CHUNK_SIZE_Z; - if (!this.isChunkLoaded(chunkPos)) { + it.unimi.dsi.fastutil.longs.LongIterator iterator = this.positionsToUpdate.iterator(); + while (iterator.hasNext()) { + long packedPos = iterator.nextLong(); + int cX = (int) packedPos; // Unpack X + int cZ = (int) (packedPos >> 32); // Unpack Z + + final int chunkBlockX = cX * Chunk.CHUNK_SIZE_X; + final int chunkBlockZ = cZ * Chunk.CHUNK_SIZE_Z; + + if (!this.isChunkLoaded(cX, cZ)) { continue; } - final Chunk chunk = this.getChunk(chunkPos); + final Chunk chunk = this.getChunkFromChunkCoords(cX, cZ); this.updateLCG = this.updateLCG * 3 + 0x3c6ef35f; int randVal = this.updateLCG >> 2; int blockX = randVal & (Chunk.CHUNK_SIZE_X - 1); @@ -2292,18 +2320,18 @@ public abstract class World implements MutableWorldSource { public void randomDisplayUpdates(final @NotNull TilePos tilePos) { final int radius = 16; - final @NotNull Random random = new Random(); - + final @NotNull Random random = this.rand; final TilePos randomPos = new TilePos(); for (int i = 0; i < ANIMATION_TICKS_PER_TICK; i++) { tilePos.add( - this.rand.nextInt(radius) - this.rand.nextInt(radius), - this.rand.nextInt(radius) - this.rand.nextInt(radius), - this.rand.nextInt(radius) - this.rand.nextInt(radius), - randomPos); + random.nextInt(radius) - random.nextInt(radius), + random.nextInt(radius) - random.nextInt(radius), + random.nextInt(radius) - random.nextInt(radius), + randomPos + ); - final @Nullable Block block = this.getBlockType(randomPos); - if (block != null) { + if (this.isBlockLoaded(randomPos)) { + final @Nullable Block block = this.getBlockType(randomPos); block.animationTick(this, randomPos, random); } } @@ -2539,12 +2567,12 @@ public abstract class World implements MutableWorldSource { } public boolean hasNeighborSignal(final @NotNull TilePosc tilePos) { + TilePos queryPos = new TilePos(); for (final @NotNull Side side : Side.sides) { - if (this.hasSignal(tilePos.add(side.direction(), new TilePos()), side)) { + if (this.hasSignal(tilePos.add(side.direction(), queryPos), side)) { return true; } } - return false; } @@ -2585,6 +2613,19 @@ public abstract class World implements MutableWorldSource { return entityplayer; } + public List getPlayersWithinRange(final double x, final double y, final double z, final double radius) { + List playersInRange = new ArrayList<>(); + final double rSquared = radius * radius; + + for (final Player player : this.players) { + if (player.distanceToSqr(x, y, z) <= rSquared) { + playersInRange.add(player); + } + } + + return playersInRange; + } + public Player getPlayerEntityByName(final String s) { for (final Player player : this.players) { @@ -2968,4 +3009,8 @@ public abstract class World implements MutableWorldSource { public int renderDistance() { return 12; } + + public int getParticleRenderDistance() { + return 1; //chunks + } } diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/Biome.java b/game/core/src/main/java/net/minecraft/core/world/biome/Biome.java index 28ade554b..3464bea6f 100644 --- a/game/core/src/main/java/net/minecraft/core/world/biome/Biome.java +++ b/game/core/src/main/java/net/minecraft/core/world/biome/Biome.java @@ -50,6 +50,7 @@ public class Biome public float defaultHumidity = 0.5f; public float defaultVariety = 0.5f; private @NotNull SurfaceProperties surfaceProperties; + private @Nullable String registryKey; public Biome(final @NotNull String key) { this.translationKey = "biome." + key; @@ -181,6 +182,14 @@ public class Biome } } + void bindRegistryKey(final @NotNull String key) { + this.registryKey = key; + } + + public @Nullable String getRegistryKey() { + return this.registryKey; + } + public boolean hasTag(final @NotNull Tag tag) { return tag.appliesTo(this); } diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/Biomes.java b/game/core/src/main/java/net/minecraft/core/world/biome/Biomes.java index 6553f0b42..3389965b3 100644 --- a/game/core/src/main/java/net/minecraft/core/world/biome/Biomes.java +++ b/game/core/src/main/java/net/minecraft/core/world/biome/Biomes.java @@ -216,7 +216,7 @@ public class Biomes { .withSurfaceProperties( new SurfaceProperties.Builder() .withTopBlock(Blocks.BRIMSAND) - .withFillerBlock(Blocks.BRIMSAND) + .withFillerBlock(Blocks.BRIMSTONE) .build() ) ); @@ -227,8 +227,8 @@ public class Biomes { .withBlockedWeathers(Weathers.OVERWORLD_RAIN, Weathers.OVERWORLD_SNOW, Weathers.OVERWORLD_STORM, Weathers.OVERWORLD_FOG) .withSurfaceProperties( new SurfaceProperties.Builder() - .withTopBlock(Blocks.BRIMSAND) - .withFillerBlock(Blocks.BRIMSAND) + .withTopBlock(Blocks.BRIMSTONE) + .withFillerBlock(Blocks.BRIMSTONE) .build() ) .withTags(BiomeTags.HAS_SULFUR_POOLS) @@ -298,6 +298,8 @@ public class Biomes { ) ); + + public static final @NotNull Biome DRIFT_DRIFT = register( "minecraft:drift.drift", new BiomeDrift("drift.drift") @@ -379,6 +381,7 @@ public class Biomes { ); public static @NotNull Biome register(final @NotNull String key, final @NotNull Biome biome) { + biome.bindRegistryKey(key); Registries.BIOMES.register(key, biome); return biome; } diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderNether.java b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderNether.java index c17d7b859..199476ffc 100644 --- a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderNether.java +++ b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderNether.java @@ -3,46 +3,44 @@ package net.minecraft.core.world.biome.provider; import net.minecraft.core.world.World; import net.minecraft.core.world.biome.Biome; import net.minecraft.core.world.biome.Biomes; +import net.minecraft.core.world.biome.data.BiomeRange; +import net.minecraft.core.world.biome.data.BiomeRangeMap; import net.minecraft.core.world.noise.FractalNoise2D; import net.minecraft.core.world.noise.FractalNoise3D; import net.minecraft.core.world.noise.SimplexNoise; -import net.minecraft.core.world.type.WorldTypes; import org.jetbrains.annotations.NotNull; import java.util.Arrays; +import java.util.Set; + +public final class BiomeProviderNether extends BiomeProvider { + public static final BiomeRangeMap brm = new BiomeRangeMap(); + private static Biome[] biomes; + + private static final double NETHER_BIOME_PATCH_SIZE_FRACTION = 0.75; + private static final double BIOME_STRETCH_FACTOR = 2.0 * NETHER_BIOME_PATCH_SIZE_FRACTION; + + private static final double TEMP_SCALE = 0.025 / BIOME_STRETCH_FACTOR; + private static final double DOWNFALL_SCALE = 0.05 / BIOME_STRETCH_FACTOR; + private static final double NOISE_SCALE = 0.25F / BIOME_STRETCH_FACTOR; -public final class BiomeProviderNether - extends BiomeProvider -{ - public static final Biome[] BIOMES_ORDER = { - Biomes.NETHER_OLD_WORLD, - Biomes.NETHER_CRYSTAL_PLAINS, - Biomes.NETHER_CRYSTAL_FOREST, - Biomes.NETHER_SHELF, - Biomes.NETHER_CRAG, - Biomes.NETHER_SULFUR_POOLS, - Biomes.NETHER_VOLCANIC_ISLANDS, - }; - - private static final double TEMP_SCALE = 0.025; - private static final double DOWNFALL_SCALE = 0.05; - private static final double NOISE_SCALE = 0.25; private final FractalNoise2D temperatureNoise; private final FractalNoise2D downfallNoise; private final FractalNoise2D fuzzinessNoise; - public BiomeProviderNether(final @NotNull World world) - { - super(world); + static { + init(); + } - final long seed = world.getRandomSeed(); - this.temperatureNoise = new FractalNoise3D<>(SimplexNoise.genOctaves(seed * 9871, 4)); - this.downfallNoise = new FractalNoise3D<>(SimplexNoise.genOctaves(seed * 39811, 4)); - this.fuzzinessNoise = new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 543321, 4)); + public BiomeProviderNether(@NotNull World world) { + super(world); + long seed = world.getRandomSeed(); + this.temperatureNoise = new FractalNoise3D<>(SimplexNoise.genOctaves(seed * 9871L, 4)); + this.downfallNoise = new FractalNoise3D<>(SimplexNoise.genOctaves(seed * 39811L, 4)); + this.fuzzinessNoise = new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 543321L, 4)); } - @Override - public Biome[] getBiomes(Biome[] biomes, double[] temperatures, double[] humidities, double[] varieties, final int x, final int y, final int z, final int xSize, final int ySize, final int zSize) { + public Biome[] getBiomes(Biome[] biomes, double[] temperatures, double[] humidities, double[] varieties, int x, int y, int z, int xSize, int ySize, int zSize) { if (biomes == null || biomes.length < xSize * ySize * zSize) { biomes = new Biome[xSize * ySize * zSize]; } @@ -93,102 +91,131 @@ public final class BiomeProviderNether temperatures[xx * zSize + zz] = temperature; humidities[xx * zSize + zz] = downfall; + double variety = varieties[xx * zSize + zz]; - for (int yy = 0; yy < ySize; yy++) { - biomes[yy * xSize * zSize + zz * xSize + xx] = this.lookupBiome(temperature, downfall, 0.0, 0.0); + for (int yy = 0; yy < ySize; ++yy) { + double actualY = (double) y + yy; + double altitude = actualY / 128.0; + altitude = Math.max(0.0, Math.min(1.0, altitude)); + + biomes[yy * xSize * zSize + zz * xSize + xx] = this.lookupBiome(temperature, downfall, altitude, variety); } } } - return biomes; } - @Override - public double[] getTemperatures(double[] temperatures, final int x, final int z, final int xSize, final int zSize) { + public double[] getTemperatures(double[] temperatures, int x, int z, int xSize, int zSize) { if (temperatures == null || temperatures.length < xSize * zSize) { temperatures = new double[xSize * zSize]; } - this.temperatureNoise.setLacunarity(0.25).getRegion(temperatures, x, z, xSize, xSize, TEMP_SCALE, TEMP_SCALE); - final double @NotNull [] noises = this.fuzzinessNoise.setLacunarity(10.0 / 17.0).getRegion(null, x, z, xSize, zSize, NOISE_SCALE, NOISE_SCALE); + this.temperatureNoise.setLacunarity(0.25F).getRegion(temperatures, x, z, xSize, xSize, TEMP_SCALE, TEMP_SCALE); + double[] noises = this.fuzzinessNoise.setLacunarity(0.5882352941176471).getRegion(null, x, z, xSize, zSize, NOISE_SCALE, NOISE_SCALE); int i = 0; - for (int xx = 0; xx < xSize; xx++) { - for (int zz = 0; zz < zSize; zz++) { - final double a = noises[i] * 1.1 + 0.5; - final double b = 0.01; - final double c = 1.0 - b; + for (int xx = 0; xx < xSize; ++xx) { + for (int zz = 0; zz < zSize; ++zz) { + double a = noises[i] * 1.1 + 0.5; + double b = 0.01; + double c = 0.99; double temperature = (temperatures[i] * 0.15 + 0.7) * c + a * b; temperature = 1.0 - (1.0 - temperature) * (1.0 - temperature); - - if (temperature < 0.0) { - temperature = 0.0; - } - if (temperature > 1.0) { - temperature = 1.0; - } - - temperatures[i++] = temperature; + temperatures[i++] = Math.max(0.0, Math.min(1.0, temperature)); } } - return temperatures; } - @Override - public double[] getHumidities(double[] humidities, final int x, final int z, final int xSize, final int zSize) { + public double[] getHumidities(double[] humidities, int x, int z, int xSize, int zSize) { if (humidities == null || humidities.length < xSize * zSize) { humidities = new double[xSize * zSize]; } - return this.downfallNoise.setLacunarity(0.5).getRegion(humidities, x, z, xSize, zSize, DOWNFALL_SCALE, DOWNFALL_SCALE); + return this.downfallNoise.setLacunarity(0.5F).getRegion(humidities, x, z, xSize, zSize, DOWNFALL_SCALE, DOWNFALL_SCALE); } - @Override - public double[] getVarieties(double[] varieties, final int x, final int z, final int xSize, final int zSize) { + public double[] getVarieties(double[] varieties, int x, int z, int xSize, int zSize) { if (varieties == null || varieties.length < xSize * zSize) { varieties = new double[xSize * zSize]; } - Arrays.fill(varieties, 0.0); + Arrays.fill(varieties, 0.0F); return varieties; } - @Override public double[] getBiomenesses(double[] biomenesses, int x, int y, int z, int xSize, int ySize, int zSize) { - if (biomenesses == null || biomenesses.length < xSize * ySize * zSize) - { + if (biomenesses == null || biomenesses.length < xSize * ySize * zSize) { biomenesses = new double[xSize * ySize * zSize]; } - Arrays.fill(biomenesses, 1.0f); - + Arrays.fill(biomenesses, 1.0F); return biomenesses; } - @Override public Biome lookupBiome(double temperature, double humidity, double altitude, double variety) { + return brm.lookupBiome(temperature, humidity, altitude, variety); + } - if (temperature <= 0.2) { - return Biomes.NETHER_OLD_WORLD; - } - if (temperature < 0.65) { - return humidity < 0.1 ? Biomes.NETHER_CRYSTAL_PLAINS : Biomes.NETHER_CRYSTAL_FOREST; - } - - if (temperature <= 0.75) { - return Biomes.NETHER_SHELF; - } - - if(humidity > 0.85) { - return Biomes.NETHER_SULFUR_POOLS; - } - if(temperature >= 0.95 && humidity < 0.1) { - return Biomes.NETHER_VOLCANIC_ISLANDS; - } - return Biomes.NETHER_CRAG; + public static void init() { + brm.clear(); + + // Hot Biomes + brm.addRange(Biomes.NETHER_VOLCANIC_ISLANDS, new BiomeRange( + 0.95, 1.0, + 0.0, 1.0, + 0.5, 1.0, + 0.0, 1.0)); + brm.addRange(Biomes.NETHER_CRAG, new BiomeRange( + 0.75, 0.95, + 0.0, 0.85, + 0.5, 1.0, + 0.0, 1.0)); + brm.addRange(Biomes.NETHER_SULFUR_POOLS, new BiomeRange( + 0.75, 0.95, + 0.85, 1.0, + 0.5, 1.0, + 0.0, 1.0)); + + // Mid/Warm Biome + brm.addRange(Biomes.NETHER_SHELF, new BiomeRange( + 0.70, 0.75, + 0.0, 1.0, + 0.5, 1.0, + 0.0, 1.0)); + + // Mid/Cool Biomes + brm.addRange(Biomes.NETHER_CRYSTAL_FOREST, new BiomeRange( + 0.45, 0.70, + 0.1, 1.0, + 0.5, 1.0, + 0.0, 1.0)); + brm.addRange(Biomes.NETHER_CRYSTAL_PLAINS, new BiomeRange( + 0.45, 0.70, + 0.0, 0.1, + 0.5, 1.0, + 0.0, 1.0)); + + // Coldest Biome + brm.addRange(Biomes.NETHER_OLD_WORLD, new BiomeRange( + 0.0, 0.45, + 0.0, 1.0, + 0.50, 1.0, + 0.0, 1.0)); + + // Underground Desert + brm.addRange(Biomes.NETHER_OLD_WORLD_DESERT, new BiomeRange( + 0.0, 1.0, + 0.0, 1.0, + 0.0, 0.5, + 0.0, 1.0)); + + brm.lock(); + + Set allBiomes = brm.allBiomes(); + biomes = allBiomes.toArray(new Biome[0]); } public static Biome[] allBiomes() { - return BIOMES_ORDER; + return biomes; } -} +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/Chunk.java b/game/core/src/main/java/net/minecraft/core/world/chunk/Chunk.java index 467d406c1..8f2d70dfe 100644 --- a/game/core/src/main/java/net/minecraft/core/world/chunk/Chunk.java +++ b/game/core/src/main/java/net/minecraft/core/world/chunk/Chunk.java @@ -569,6 +569,7 @@ public class Chunk { } public void removeEntityAtIndex(@NotNull Entity entity, int index) { + this.isModified = true; index = MathHelper.clamp(index, 0, CHUNK_SECTIONS - 1); getSection(index).removeEntity(entity); } diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/RubyglassFloeLargeFeature.java b/game/core/src/main/java/net/minecraft/core/world/generate/RubyglassFloeLargeFeature.java new file mode 100644 index 000000000..39cb00389 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/world/generate/RubyglassFloeLargeFeature.java @@ -0,0 +1,85 @@ +package net.minecraft.core.world.generate; + +import net.minecraft.core.block.Blocks; +import net.minecraft.core.util.helper.MathHelper; +import net.minecraft.core.world.World; +import net.minecraft.core.world.biome.Biome; +import net.minecraft.core.world.biome.Biomes; +import net.minecraft.core.world.generate.chunk.ChunkGeneratorResult; +import net.minecraft.core.world.noise.FractalNoise2D; +import net.minecraft.core.world.noise.ImprovedPerlinNoise; +import net.minecraft.core.world.noise.Noise2D; +import net.minecraft.core.world.noise.WorleyNoise; +import net.minecraft.core.world.noise.operator.Normalize2D; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.type.WorldType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Random; + +public class RubyglassFloeLargeFeature extends LargeFeature { + private @Nullable WorleyNoise chunkNoise = null; + private @Nullable Noise2D gapNoise = null; + private @Nullable Noise2D scaleNoise = null; + private @Nullable World lastWorld = null; + + public RubyglassFloeLargeFeature() { + } + + protected void doGeneration(@NotNull World world, @NotNull Random random, int chunkX, int chunkZ, int baseChunkX, int baseChunkZ, @NotNull ChunkGeneratorResult result) { + if (this.chunkNoise == null || this.gapNoise == null || this.scaleNoise == null || this.lastWorld != world) { + this.chunkNoise = new WorleyNoise(new Random(world.getRandomSeed())); + this.gapNoise = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 4)); + this.scaleNoise = new Normalize2D<>(new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 2))); + this.lastWorld = world; + } + + WorldType worldType = world.getWorldType(); + int oceanY = worldType.getMinY(world) + worldType.getOceanY(); + TilePos tilePos = new TilePos(); + WorleyNoise.Result worleyResult = new WorleyNoise.Result(); + + for (int x = 0; x < 16; ++x) { + for (int z = 0; z < 16; ++z) { + tilePos.set(16 * baseChunkX + x, oceanY, 16 * baseChunkZ + z); + Biome biome = world.getBlockBiome(tilePos); + if (biome == Biomes.NETHER_CRYSTAL_FOREST || biome == Biomes.NETHER_CRYSTAL_PLAINS) { + + double sampleX = (double) baseChunkX + (double) x / 16.0; + double sampleZ = (double) baseChunkZ + (double) z / 16.0; + this.chunkNoise.getValue(sampleX, sampleZ, worleyResult); + + double lineScale = 15.0; + double lineWidth = this.gapNoise.getValue((double) (baseChunkX * 16 + x) / lineScale, (double) (baseChunkZ * 16 + z) / lineScale) / 2.0 + 0.5; + double edgeThreshold = 0.8 + lineWidth * 0.05; + + if (MathHelper.unsignedMod(worleyResult.index, 15.0F) != 0.0 && worleyResult.distance <= edgeThreshold) { + + double thicknessVariation = this.scaleNoise.getValue((double) x / 10.0, (double) z / 10.0); + int depth = (int) (thicknessVariation * 6.0); + for (int y = oceanY - (depth + 2); y < oceanY; ++y) { + this.trySetBlock(result, x, y, z, Blocks.COBBLE_NETHERRACK_CRYSTALLINE.id()); + } + + for (int y = oceanY; y < oceanY + depth; ++y) { + this.trySetBlock(result, x, y, z, Blocks.COBBLE_NETHERRACK.id()); + } + } + } + } + } + } + + private void trySetBlock(@NotNull ChunkGeneratorResult result, int x, int y, int z, int id) { + int current = result.getBlock(x, y, z); + if (current == Blocks.RUBYGLASS_CRYSTAL.id() || current == Blocks.FLUID_WATER_STILL.id() || current == Blocks.AIR.id()) { + result.setBlock(x, y, z, id); + } + } + + @Override + public int getRadiusChunk() { + return 0; + } +} diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkDecorationBuilder.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkDecorationBuilder.java index ad4d89526..7259cfe1b 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkDecorationBuilder.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkDecorationBuilder.java @@ -6,8 +6,8 @@ import net.minecraft.core.world.chunk.Chunk; import net.minecraft.core.world.generate.feature.WorldFeatureInterface; import net.minecraft.core.world.pos.TilePos; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.Arrays; import java.util.Random; public class ChunkDecorationBuilder implements ChunkDecoration @@ -16,6 +16,13 @@ public class ChunkDecorationBuilder implements ChunkDecoration private @NotNull PlacementMethod placementMethod = PlacementMethods.OncePerChunk; private @NotNull Biome[] biomeMask = new Biome[]{}; private @NotNull PositionSelector positionSelector = PositionSelectors.SurfaceBlock; + + private final TilePos scratchPos = new TilePos(); + private @Nullable PlaceableFeature cachedPlaceable; + private int cachedMinY; + private int cachedMaxY; + private int cachedRangeY; + public ChunkDecorationBuilder(final @NotNull WorldFeatureInterface worldFeature){ this.worldFeature = worldFeature; } @@ -38,13 +45,34 @@ public class ChunkDecorationBuilder implements ChunkDecoration @Override public void placeDecoration(@NotNull World world, @NotNull Chunk chunk, int worldX, int worldZ, int minY, int maxY, int rangeY, @NotNull Random rand) { + if (this.biomeMask.length != 0) { + int checkY = minY + (maxY - minY) / 2; + checkY = Math.max(world.getWorldType().getMinY(world), Math.min(world.getWorldType().getMaxY(world) - 1, checkY)); - if(biomeMask.length > 0){ - if(!Arrays.asList(biomeMask).contains(world.getBlockBiome(new TilePos(worldX, minY, worldZ)))){ + this.scratchPos.set(worldX, checkY, worldZ); + final Biome here = world.getBlockBiome(this.scratchPos); + if (!this.biomeMaskContains(here)) { return; } } - placementMethod.placeFeature(new PlaceableFeature(this.worldFeature, this.positionSelector, minY, maxY, rangeY), world, chunk, rand); + if (this.cachedPlaceable == null || minY != this.cachedMinY || maxY != this.cachedMaxY || rangeY != this.cachedRangeY) { + this.cachedPlaceable = new PlaceableFeature(this.worldFeature, this.positionSelector, minY, maxY, rangeY); + this.cachedMinY = minY; + this.cachedMaxY = maxY; + this.cachedRangeY = rangeY; + } + + this.placementMethod.placeFeature(this.cachedPlaceable, world, chunk, rand); + } + + private boolean biomeMaskContains(@NotNull Biome biome) { + final Biome[] mask = this.biomeMask; + for (int i = 0, n = mask.length; i < n; i++) { + if (mask[i] == biome) { + return true; + } + } + return false; } } diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkFeatureDecorator.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkFeatureDecorator.java index ba47c0510..ba54249c7 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkFeatureDecorator.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkFeatureDecorator.java @@ -1,21 +1,36 @@ package net.minecraft.core.world.generate.chunk; +import com.mojang.logging.LogUtils; +import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import net.minecraft.core.block.BlockLogicFallingBlock; import net.minecraft.core.util.HardIllegalArgumentException; import net.minecraft.core.util.collection.NamespaceID; import net.minecraft.core.world.World; import net.minecraft.core.world.chunk.Chunk; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; import java.util.Random; public abstract class ChunkFeatureDecorator - implements ChunkDecorator { + implements ChunkDecorator { + private static final @NotNull Logger LOGGER = LogUtils.getLogger(); + private boolean initialized = false; private final @NotNull World world; - private final @NotNull Object2IntMap decorations = new Object2IntOpenHashMap<>(); + + private final @NotNull Object2IntMap decorations = new Object2IntLinkedOpenHashMap<>(); + + private ChunkDecoration @Nullable [] decorationArray; + private int @Nullable [] decorationSeedArray; + + private boolean seedConstantsInitialized = false; + private long seedMultiplierA; + private long seedMultiplierB; + + private final @NotNull Random sharedRand = new Random(); public ChunkFeatureDecorator(final @NotNull World world) { this.world = world; @@ -41,39 +56,82 @@ public abstract class ChunkFeatureDecorator public final @NotNull ChunkFeatureDecorator register(final @NotNull NamespaceID id, final @NotNull ChunkDecoration decoration) { this.decorations.put(decoration, id.toString().hashCode()); - + this.decorationArray = null; + this.decorationSeedArray = null; return this; } + private void bakeDecorations() { + final int n = this.decorations.size(); + final ChunkDecoration[] decoArr = new ChunkDecoration[n]; + final int[] seedArr = new int[n]; + + int i = 0; + for (final Object2IntMap.Entry entry : this.decorations.object2IntEntrySet()) { + decoArr[i] = entry.getKey(); + seedArr[i] = entry.getIntValue(); + i++; + } + + this.decorationArray = decoArr; + this.decorationSeedArray = seedArr; + } + @Override public final void decorate(final @NotNull Chunk chunk) { this.world.scheduledUpdatesAreImmediate = true; BlockLogicFallingBlock.fallInstantly = true; - final int chunkX = chunk.pos.x; - final int chunkZ = chunk.pos.z; - final int worldX = chunkX * 16; - final int worldZ = chunkZ * 16; - - final int minY = this.world.getWorldType().getMinY(world); - final int maxY = this.world.getWorldType().getMaxY(world); - final int rangeY = (maxY + 1) - minY; - - final @NotNull Random rand = new Random(this.world.getRandomSeed()); - final long a = (rand.nextLong() / 2L) * 2L + 1L; - final long b = (rand.nextLong() / 2L) * 2L + 1L; - - for (final @NotNull ChunkDecoration decoration : this.decorations.keySet()) { - final int decorationSeed = this.decorations.getInt(decoration); - rand.setSeed((long) chunkX * a + (long) chunkZ * b ^ this.world.getRandomSeed() ^ decorationSeed); - decoration.placeDecoration(this.world, chunk, worldX, worldZ, minY, maxY, rangeY, rand); + try { + final int chunkX = chunk.pos.x; + final int chunkZ = chunk.pos.z; + final int worldX = chunkX * 16; + final int worldZ = chunkZ * 16; + + final int minY = this.world.getWorldType().getMinY(world); + final int maxY = this.world.getWorldType().getMaxY(world); + final int rangeY = (maxY + 1) - minY; + + final long worldSeed = this.world.getRandomSeed(); + if (!this.seedConstantsInitialized) { + final Random seedRand = new Random(worldSeed); + this.seedMultiplierA = (seedRand.nextLong() / 2L) * 2L + 1L; + this.seedMultiplierB = (seedRand.nextLong() / 2L) * 2L + 1L; + this.seedConstantsInitialized = true; + } + + if (this.decorationArray == null || this.decorationSeedArray == null) { + this.bakeDecorations(); + } + + final ChunkDecoration[] decoArr = this.decorationArray; + final int[] seedArr = this.decorationSeedArray; + final long a = this.seedMultiplierA; + final long b = this.seedMultiplierB; + final Random rand = this.sharedRand; + + for (int i = 0, n = decoArr.length; i < n; i++) { + assert seedArr != null; + rand.setSeed((long) chunkX * a + (long) chunkZ * b ^ worldSeed ^ seedArr[i]); + try { + decoArr[i].placeDecoration(this.world, chunk, worldX, worldZ, minY, maxY, rangeY, rand); + } catch (final Throwable t) { + LOGGER.error("Decoration {} failed at chunk ({}, {}); continuing with remaining decorations.", + i, chunkX, chunkZ, t); + } + } + + try { + this.postDecorate(this.world, chunk); + } catch (final Throwable t) { + LOGGER.error("postDecorate failed at chunk ({}, {}).", chunkX, chunkZ, t); + } + + } finally { + BlockLogicFallingBlock.fallInstantly = false; + this.world.scheduledUpdatesAreImmediate = false; } - - this.postDecorate(this.world, chunk); - - BlockLogicFallingBlock.fallInstantly = false; - this.world.scheduledUpdatesAreImmediate = false; } public abstract void postDecorate(final @NotNull World world, final @NotNull Chunk chunk); -} +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkDecoratorNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkDecoratorNether.java index 7a9f1af6c..bc07f6874 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkDecoratorNether.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkDecoratorNether.java @@ -1,7 +1,8 @@ package net.minecraft.core.world.generate.chunk.perlin.nether; +import net.minecraft.core.block.Block; import net.minecraft.core.block.BlockLogicOreNetherCoal; -import net.minecraft.core.block.BlockLogicOreRubyglass; +import net.minecraft.core.block.BlockLogicNodeRubyglass; import net.minecraft.core.block.Blocks; import net.minecraft.core.world.World; import net.minecraft.core.world.biome.Biome; @@ -10,7 +11,6 @@ import net.minecraft.core.world.biome.Biomes; import net.minecraft.core.world.chunk.Chunk; import net.minecraft.core.world.generate.chunk.*; import net.minecraft.core.world.generate.feature.*; -import net.minecraft.core.world.generate.feature.tree.WorldFeatureBoneshaleTree; import net.minecraft.core.world.noise.FractalNoise2D; import net.minecraft.core.world.noise.ImprovedPerlinNoise; import net.minecraft.core.world.noise.WorleyNoise; @@ -23,279 +23,299 @@ public class ChunkDecoratorNether extends ChunkFeatureDecorator { private final @NotNull FractalNoise2D crystalDensityNoise; private final @NotNull WorleyNoise pillarNoise; - private final @NotNull WorleyNoise.Result worleyResult; + public ChunkDecoratorNether(@NotNull World world) { super(world); this.pillarNoise = new WorleyNoise(new Random(world.getRandomSeed())); this.crystalDensityNoise = new FractalNoise2D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 8, 74)); - this.worleyResult = new WorleyNoise.Result(); + } + + private TilePos selectPillarPosition(@NotNull Chunk chunk, @NotNull Random random) { + int x = chunk.pos.x() * 16 + random.nextInt(16); + int z = chunk.pos.z() * 16 + random.nextInt(16); + int y = 200; + + WorleyNoise.Result result = new WorleyNoise.Result(); + this.pillarNoise.getValue(x >> 5, z >> 5, result); + + int xPillar = (int) (result.center.x * 32.0D); + int zPillar = (int) (result.center.y * 32.0D); + + return new TilePos(xPillar, y, zPillar); } @Override public void registerDecorations() { - this.register("minecraft:decoration/nether/default/speleothems", - new ChunkDecorationBuilder(new WorldFeatureSpeleothems(12, true, 12, true)) + // Rubyglass Features + this.register("minecraft:decoration/nether/default/rubyglass_crystal_ceiling", (new ChunkDecorationBuilder(new WorldFeatureRubyglassCrystalline(true, 20, 15))) + .withBiomeMask(new Biome[]{Biomes.NETHER_CRYSTAL_FOREST}) + .withPositionSelector(PositionSelectors.UpperHeightRangeUniform) + .withPlacementMethod((feature, world, chunk, random) -> { + int x = chunk.pos.x * 16; + int z = chunk.pos.z * 16; + int density = (int) ((this.crystalDensityNoise.getValue((double) x * (double) 0.5F, (double) z * (double) 0.5F) - (double) 6.0F + (double) 30.0F) / (double) 6.0F); + + for (int i = 0; i < density + 4; ++i) { + feature.placeFeature(world, chunk, random); + } + })); + + this.register("minecraft:decoration/nether/default/rubyglass_crystal_floor", (new ChunkDecorationBuilder(new WorldFeatureRubyglassCrystalline(false, 20, 30))) + .withBiomeMask(new Biome[]{Biomes.NETHER_CRYSTAL_FOREST}) + .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) + .withPlacementMethod((feature, world, chunk, random) -> { + int x = chunk.pos.x * 16; + int z = chunk.pos.z * 16; + int density = (int) ((this.crystalDensityNoise.getValue((double) x * (double) 0.5F, (double) z * (double) 0.5F) - (double) 6.0F + (double) 30.0F) / (double) 6.0F); + + for (int i = 0; i < density + 4; ++i) { + feature.placeFeature(world, chunk, random); + } + })); + + this.register("minecraft:decoration/nether/default/rubyglass_crystal_floor_2", (new ChunkDecorationBuilder(new WorldFeatureRubyglassCrystalline(false, 15, 25))) + .withBiomeMask(new Biome[]{Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRYSTAL_PLAINS}) + .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(4))); + + this.register("minecraft:decoration/nether/default/rubyglass_node", (new ChunkDecorationBuilder(new WorldFeatureOre(BlockLogicNodeRubyglass.variantMap, 5))) + .withBiomeMask(new Biome[]{Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRYSTAL_PLAINS}) + .withPositionSelector(PositionSelectors.HeightRangeUniform) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(10))); + + this.register("minecraft:decoration/nether/default/rubyglass_bud_patch", (new ChunkDecorationBuilder(new WorldFeatureRubyglassGrowthPatch(0.0F))) + .withBiomeMask(new Biome[]{Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRYSTAL_PLAINS}) + .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(100))); + + this.register("minecraft:decoration/nether/default/rubyglass_growth_patch", (new ChunkDecorationBuilder(new WorldFeatureRubyglassGrowthPatch())) + .withBiomeMask(new Biome[]{Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRYSTAL_PLAINS}) + .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(100))); + + // Wall Scatter Features + this.register("minecraft:decoration/nether/default/scatter_crystalline", (new ChunkDecorationBuilder(new WorldFeaturePerlinVein(Blocks.COBBLE_NETHERRACK_CRYSTALLINE, Blocks.COBBLE_NETHERRACK, 0.06, 0.045))) + .withBiomeMask(new Biome[]{Biomes.NETHER_CRYSTAL_PLAINS, Biomes.NETHER_CRYSTAL_FOREST}) + .withPositionSelector(PositionSelectors.MinY) + .withPlacementMethod(PlaceableFeature::placeFeature)); + + this.register("minecraft:decoration/nether/default/clump_crystalline", (new ChunkDecorationBuilder(new WorldFeatureWallClump(Blocks.COBBLE_NETHERRACK_CRYSTALLINE, Blocks.COBBLE_NETHERRACK, 1))) + .withBiomeMask(new Biome[]{Biomes.NETHER_CRYSTAL_PLAINS, Biomes.NETHER_CRYSTAL_FOREST}) + .withPositionSelector(PositionSelectors.HeightRangeUniform) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(500))); + + this.register("minecraft:decoration/nether/default/clump_brimthaw", (new ChunkDecorationBuilder(new WorldFeatureWallClump(Blocks.BRIMTHAW, Blocks.BRIMSTONE, 1))) + .withBiomeMask(new Biome[]{Biomes.NETHER_SULFUR_POOLS}) + .withPositionSelector(PositionSelectors.HeightRangeUniform) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(1000))); + + // Water Features + this.register("minecraft:decoration/nether/default/water_spring", (new ChunkDecorationBuilder(new WorldFeatureNetherSpring(Blocks.FLUID_WATER_FLOWING.id()))) + .withBiomeMask(new Biome[]{Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRYSTAL_PLAINS}) + .withPositionSelector(PositionSelectors.HeightRangeBiasedTop) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(16))); + + // Lava Features + this.register("minecraft:decoration/nether/default/lava_spring", (new ChunkDecorationBuilder(new WorldFeatureNetherSpring(Blocks.FLUID_LAVA_FLOWING.id()))) + .withBiomeMask(new Biome[]{Biomes.NETHER_VOLCANIC_ISLANDS, Biomes.NETHER_CRAG, Biomes.NETHER_SHELF}) + .withPositionSelector(PositionSelectors.HeightRangeUniform) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(16))); + + this.register("minecraft:decoration/nether/default/lava_spring_2", (new ChunkDecorationBuilder(new WorldFeatureNetherSpring(Blocks.FLUID_LAVA_FLOWING.id()))) + .withBiomeMask(new Biome[]{Biomes.NETHER_VOLCANIC_ISLANDS}) + .withPositionSelector(PositionSelectors.HeightRangeUniform) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(16))); + + this.register("minecraft:decoration/nether/default/lava_lake", (new ChunkDecorationBuilder(new WorldFeatureLake(Blocks.FLUID_LAVA_STILL.id()))) + .withBiomeMask(new Biome[]{Biomes.NETHER_VOLCANIC_ISLANDS, Biomes.NETHER_CRAG, Biomes.NETHER_CRYSTAL_PLAINS, Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_SHELF, Biomes.NETHER_SULFUR_POOLS}) .withPositionSelector(PositionSelectors.UpperHeightRangeUniform) - .withPlacementMethod(new PlacementMethod.TriesPerChunk(4)) - ); - this.register("minecraft:decoration/nether/default/lava_lake", - new ChunkDecorationBuilder(new WorldFeatureLake(Blocks.FLUID_LAVA_STILL.id())) - .withPositionSelector(PositionSelectors.UpperHeightRangeUniform) - .withPlacementMethod(new PlacementMethod.ChanceToPlace(4)) - ); - this.register("minecraft:decoration/nether/default/rubyglass_crystal_ceiling", - new ChunkDecorationBuilder(new WorldFeatureRubyglassCrystal(true)) - .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FOREST}) - .withPositionSelector(PositionSelectors.UpperHeightRangeUniform) - .withPlacementMethod(((feature, world, chunk, random) -> { - int x = chunk.pos.x * 16; - int z = chunk.pos.z * 16; - int density = (int) ((this.crystalDensityNoise.getValue(x * 0.5, z * 0.5) - 6D + 30D) / 6D); - - for (int i = 0; i < density + 4; i++) { - feature.placeFeature(world, chunk, random); - } - })) - ); - - this.register("minecraft:decoration/nether/default/rubyglass_crystal_floor", - new ChunkDecorationBuilder(new WorldFeatureRubyglassCrystal(false, 25, 50)) - .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FOREST}) - .withPositionSelector(PositionSelectors.UpperHeightRangeUniform) - .withPlacementMethod(((feature, world, chunk, random) -> { - int x = chunk.pos.x * 16; - int z = chunk.pos.z * 16; - int density = (int) ((this.crystalDensityNoise.getValue(x * 0.5, z * 0.5) - 6D + 30D) / 6D); - - for (int i = 0; i < density + 4; i++) { - feature.placeFeature(world, chunk, random); - } - })) - ); - - this.register("minecraft:decoration/nether/default/rubyglass_crystal_floor_2", - new ChunkDecorationBuilder(new WorldFeatureRubyglassCrystal(false, 20, 30)) - .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRYSTAL_PLAINS}) - .withPositionSelector(PositionSelectors.UpperHeightRangeUniform) - .withPlacementMethod(new PlacementMethod.TriesPerChunk(4)) - ); - - this.register("minecraft:decoration/nether/default/rubyglass_node", - new ChunkDecorationBuilder(new WorldFeatureOre(BlockLogicOreRubyglass.variantMap, 5)) - .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRYSTAL_PLAINS}) - .withPositionSelector(PositionSelectors.HeightRangeUniform) - .withPlacementMethod(new PlacementMethod.TriesPerChunk(10)) - ); - - this.register("minecraft:decoration/nether/default/rubyglass_sprout_patch", - new ChunkDecorationBuilder(new WorldFeatureRubyglassSproutPatch()) - .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRYSTAL_PLAINS}) - .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) - .withPlacementMethod(new PlacementMethod.TriesPerChunk(20)) - ); - - this.register("minecraft:decoration/nether/default/nether_water_spring", - new ChunkDecorationBuilder(new WorldFeatureNetherSpring(Blocks.FLUID_WATER_FLOWING.id())) - .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRYSTAL_PLAINS, Biomes.NETHER_OLD_WORLD }) - .withPositionSelector(PositionSelectors.HeightRangeBiasedTop) - .withPlacementMethod(new PlacementMethod.TriesPerChunk(30)) - ); - - this.register("minecraft:decoration/nether/default/nether_lava_spring", - new ChunkDecorationBuilder(new WorldFeatureNetherSpring(Blocks.FLUID_LAVA_FLOWING.id())) - .withBiomeMask(new Biome[]{ Biomes.NETHER_VOLCANIC_ISLANDS, Biomes.NETHER_SULFUR_POOLS, Biomes.NETHER_CRAG, Biomes.NETHER_SHELF }) - .withPositionSelector(PositionSelectors.HeightRangeBiasedTop) - .withPlacementMethod(new PlacementMethod.TriesPerChunk(30)) - ); - - this.register("minecraft:decoration/nether/default/nether_lava_spring_2", - new ChunkDecorationBuilder(new WorldFeatureNetherSpring(Blocks.FLUID_LAVA_FLOWING.id())) - .withBiomeMask(new Biome[]{ Biomes.NETHER_VOLCANIC_ISLANDS }) - .withPositionSelector(PositionSelectors.HeightRangeBiasedTop) - .withPlacementMethod(new PlacementMethod.TriesPerChunk(20)) - ); - - this.register("minecraft:decoration/nether/default/pillar_netherrack", - new ChunkDecorationBuilder(new WorldFeaturePillar(Blocks.NETHERRACK.id(), false)) - .withBiomeMask(new Biome[]{ Biomes.NETHER_CRYSTAL_PLAINS, Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRAG, Biomes.NETHER_SHELF }) - .withPositionSelector(((world, chunk, random, minY, maxY, rangeY) -> { - int x = (chunk.pos.x() * 16) + random.nextInt(16); - int z = (chunk.pos.z() * 16) + random.nextInt(16); - int y = 200; - - double scale = 0.5; - - this.pillarNoise.getValue( - Math.floor(x / 32F), - Math.floor(z / 32F), - this.worleyResult - ); - - int xPillar = (int) (this.worleyResult.center.x * 32); - int zPillar = (int) (this.worleyResult.center.y * 32); - - return new TilePos(xPillar, y, zPillar); - })) - .withPlacementMethod(new PlacementMethod.ChanceToPlace(4)) - ); - - this.register("minecraft:decoration/nether/default/pillar_cobble_basalt", - new ChunkDecorationBuilder(new WorldFeaturePillar(Blocks.COBBLE_BASALT.id(), true)) - .withBiomeMask(new Biome[]{ Biomes.NETHER_SULFUR_POOLS, Biomes.NETHER_VOLCANIC_ISLANDS }) - .withPositionSelector(((world, chunk, random, minY, maxY, rangeY) -> { - int x = (chunk.pos.x() * 16) + random.nextInt(16); - int z = (chunk.pos.z() * 16) + random.nextInt(16); - int y = 200; - - double scale = 0.5; - - this.pillarNoise.getValue( - Math.floor(x / 32F), - Math.floor(z / 32F), - this.worleyResult - ); - - int xPillar = (int) (this.worleyResult.center.x * 32); - int zPillar = (int) (this.worleyResult.center.y * 32); - - return new TilePos(xPillar, y, zPillar); - })) - .withPlacementMethod(new PlacementMethod.TriesPerChunk(4)) - ); - - this.register("minecraft:decoration/nether/default/boulder", - new ChunkDecorationBuilder(new WorldFeatureMagmaBoulder()) - .withBiomeMask(new Biome[]{ Biomes.NETHER_SULFUR_POOLS, Biomes.NETHER_VOLCANIC_ISLANDS }) - .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) - .withPlacementMethod(new PlacementMethod.TriesPerChunk(2)) - ); - - this.register("minecraft:decoration/nether/default/sulfur_pool_terrace", - new ChunkDecorationBuilder(new WorldFeatureTerrace(Blocks.FLUID_WATER_STILL, Blocks.BRIMSAND)) - .withBiomeMask(new Biome[]{ Biomes.NETHER_SULFUR_POOLS }) - .withPositionSelector(PositionSelectors.MinY) - .withPlacementMethod(PlacementMethods.OncePerChunk) - ); - - this.register("minecraft:decoration/nether/default/lava_pool_terrace", - new ChunkDecorationBuilder(new WorldFeatureTerrace(Blocks.FLUID_LAVA_STILL, Blocks.COBBLE_BASALT, 4, 4)) - .withBiomeMask(new Biome[]{ Biomes.NETHER_VOLCANIC_ISLANDS }) - .withPositionSelector(PositionSelectors.MinY) - .withPlacementMethod(new PlacementMethod.ChanceToPlace(3)) - ); - - this.register("minecraft:decoration/nether/default/sulfur_pool_floor_vent", - new ChunkDecorationBuilder(new WorldFeatureFloorVent()) - .withBiomeMask(new Biome[]{ Biomes.NETHER_SULFUR_POOLS }) - .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) - .withPlacementMethod(new PlacementMethod.TriesPerChunk(12)) - ); - - this.register("minecraft:decoration/nether/default/sulfur_pool_spire", - new ChunkDecorationBuilder(new WorldFeatureThermalSpire()) - .withBiomeMask(new Biome[]{ Biomes.NETHER_SULFUR_POOLS }) - .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) - .withPlacementMethod(new PlacementMethod.TriesPerChunk(8)) - ); - - this.register("minecraft:decoration/nether/default/nether_coal_ore", - new ChunkDecorationBuilder(new WorldFeatureOre(BlockLogicOreNetherCoal.variantMap, 12)) - .withPositionSelector(PositionSelectors.HeightRangeUniform) - .withPlacementMethod(new PlacementMethod.TriesPerChunk(10)) - ); - - this.register("minecraft:decoration/nether/default/nether_coal_ore_2", - new ChunkDecorationBuilder(new WorldFeatureOre(BlockLogicOreNetherCoal.variantMap, 12)) - .withBiomeMask(new Biome[]{ Biomes.NETHER_VOLCANIC_ISLANDS }) - .withPositionSelector(PositionSelectors.HeightRangeUniform) - .withPlacementMethod(new PlacementMethod.TriesPerChunk(20)) - ); - - this.register("minecraft:decoration/nether/default/glowstone_1", - new ChunkDecorationBuilder(new WorldFeatureGlowstone()) - .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) - .withPlacementMethod(((feature, world, chunk, random) -> { - int max = random.nextInt(random.nextInt(10) + 1); - for (int i = 0; i < max; i++) { - feature.placeFeature(world, chunk, random); - } - })) - ); - - this.register("minecraft:decoration/nether/default/glowstone_2", - new ChunkDecorationBuilder(new WorldFeatureGlowstone()) - .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) - .withPlacementMethod(new PlacementMethod.TriesPerChunk(10)) - ); - - this.register("minecraft:decoration/nether/default/patch_fire_1", - new ChunkDecorationBuilder(new WorldFeatureFire()) - .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) - .withPlacementMethod(new PlacementMethod.TriesPerChunk(4)) - ); - - this.register("minecraft:decoration/nether/default/patch_fire_2", - new ChunkDecorationBuilder(new WorldFeatureFire()) - .withBiomeMask(new Biome[]{ Biomes.NETHER_VOLCANIC_ISLANDS }) - .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) - .withPlacementMethod(new PlacementMethod.TriesPerChunk(4)) - ); - - this.register("minecraft:decoration/nether/default/old_world_patch_bone_pile", - new ChunkDecorationBuilder(new WorldFeatureNetherPatch(Blocks.BONE_PILE.id())) - .withBiomeMask(new Biome[]{ Biomes.NETHER_OLD_WORLD, Biomes.NETHER_OLD_WORLD_DESERT }) - .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) - .withPlacementMethod(new PlacementMethod.TriesPerChunk(4)) - ); - - this.register("minecraft:decoration/nether/default/patch_bone_pile", - new ChunkDecorationBuilder(new WorldFeatureNetherPatch(Blocks.BONE_PILE.id())) - .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) - .withPlacementMethod(new PlacementMethod.TriesPerChunk(1)) - ); - - this.register("minecraft:decoration/nether/default/patch_soul_catcher", - new ChunkDecorationBuilder(new WorldFeatureNetherPatch(Blocks.SOULCATCHER.id())) - .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) - .withPlacementMethod(new PlacementMethod.TriesPerChunk(2)) - ); - - this.register("minecraft:decoration/nether/default/boneshale_tree", - new ChunkDecorationBuilder(((world, random, tilePos) -> { - //todo refactor how spooner trees are instantiated - WorldFeature wf = new WorldFeatureBoneshaleTree(0, Blocks.LOG_PETRIFIED.id()); - wf.init(1.0D, 1.0D, 1.0D); - return wf.place(world, random, tilePos); - })) - .withBiomeMask(new Biome[]{ Biomes.NETHER_OLD_WORLD }) - .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) - .withPlacementMethod(new PlacementMethod.TriesPerChunk(4)) - ); + .withPlacementMethod(new PlacementMethod.ChanceToPlace(4))); + + this.register("minecraft:decoration/nether/default/lava_pool_terrace", (new ChunkDecorationBuilder(new WorldFeatureTerrace(Blocks.FLUID_LAVA_STILL, Blocks.BRIMSTONE, 4, 4))) + .withBiomeMask(new Biome[]{Biomes.NETHER_VOLCANIC_ISLANDS}) + .withPositionSelector(PositionSelectors.MinY) + .withPlacementMethod(new PlacementMethod.ChanceToPlace(3))); + + this.register("minecraft:decoration/nether/default/boulder_magma", (new ChunkDecorationBuilder(new WorldFeatureTerrace(Blocks.FLUID_LAVA_STILL, Blocks.BRIMSTONE, 4, 4))) + .withBiomeMask(new Biome[]{Biomes.NETHER_VOLCANIC_ISLANDS}) + .withPositionSelector(PositionSelectors.MinY) + .withPlacementMethod(new PlacementMethod.ChanceToPlace(3))); + + this.register("minecraft:decoration/nether/default/acid_spring", (new ChunkDecorationBuilder(new WorldFeatureNetherSpring(Blocks.FLUID_ACID_FLOWING.id()))) + .withBiomeMask(new Biome[]{Biomes.NETHER_SULFUR_POOLS}) + .withPositionSelector(PositionSelectors.HeightRangeUniform) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(16))); + + // Pillar Features + this.register("minecraft:decoration/nether/default/pillar_netherrack", (new ChunkDecorationBuilder(new WorldFeaturePillar(Blocks.RUBYGLASS_COLUMN.id(), false))) + .withBiomeMask(new Biome[]{Biomes.NETHER_CRYSTAL_PLAINS, Biomes.NETHER_CRYSTAL_FOREST}) + .withPositionSelector((world, chunk, random, minY, maxY, rangeY) -> selectPillarPosition(chunk, random)) + .withPlacementMethod(new PlacementMethod.ChanceToPlace(8))); + + this.register("minecraft:decoration/nether/default/pillar_netherrack_2", (new ChunkDecorationBuilder(new WorldFeaturePillar(Blocks.COBBLE_NETHERRACK.id(), false))) + .withBiomeMask(new Biome[]{Biomes.NETHER_CRYSTAL_PLAINS, Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_CRAG, Biomes.NETHER_SHELF}) + .withPositionSelector((world, chunk, random, minY, maxY, rangeY) -> selectPillarPosition(chunk, random)) + .withPlacementMethod(new PlacementMethod.ChanceToPlace(4))); + + this.register("minecraft:decoration/nether/default/pillar_cobble_basalt", (new ChunkDecorationBuilder(new WorldFeaturePillar(Blocks.BRIMSTONE.id(), true))) + .withBiomeMask(new Biome[]{Biomes.NETHER_VOLCANIC_ISLANDS, Biomes.NETHER_SULFUR_POOLS}) + .withPositionSelector((world, chunk, random, minY, maxY, rangeY) -> selectPillarPosition(chunk, random)) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(4))); + + this.register("minecraft:decoration/nether/default/pillar_slate", (new ChunkDecorationBuilder(new WorldFeaturePillar(Blocks.SLATE.id(), true))) + .withBiomeMask(new Biome[]{Biomes.NETHER_OLD_WORLD}) + .withPositionSelector((world, chunk, random, minY, maxY, rangeY) -> selectPillarPosition(chunk, random)) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(4))); + + // Nether biome features + this.register("minecraft:decoration/nether/default/boulder_magma", new ChunkDecorationBuilder(new WorldFeatureBoulderMagma()) + .withBiomeMask(new Biome[]{Biomes.NETHER_VOLCANIC_ISLANDS}) + .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(2))); + + this.register("minecraft:decoration/nether/default/sulfur_pool_terrace", new ChunkDecorationBuilder(new WorldFeatureTerrace(Blocks.FLUID_ACID_FLOWING, Blocks.BRIMSAND)) + .withBiomeMask(new Biome[]{Biomes.NETHER_SULFUR_POOLS}) + .withPositionSelector(PositionSelectors.MinY) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(3))); + + this.register("minecraft:decoration/nether/default/floor_vent", new ChunkDecorationBuilder(new WorldFeatureFloorVent()) + .withBiomeMask(new Biome[]{Biomes.NETHER_VOLCANIC_ISLANDS, Biomes.NETHER_SULFUR_POOLS}) + .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(12))); + + this.register("minecraft:decoration/nether/default/volcanic_islands_spire", new ChunkDecorationBuilder(new WorldFeatureSpireVent()) + .withBiomeMask(new Biome[]{Biomes.NETHER_VOLCANIC_ISLANDS}) + .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(8))); + + this.register("minecraft:decoration/nether/default/sulfur_pool_boulder", new ChunkDecorationBuilder(new WorldFeatureBoulderGlowstone(Blocks.GLOWSTONE, Blocks.FIRE_SULFURIC, 1)) + .withBiomeMask(new Biome[]{Biomes.NETHER_SULFUR_POOLS}) + .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(12))); + + this.register("minecraft:decoration/nether/default/nether_roof_spire", new ChunkDecorationBuilder(new WorldFeatureRoofSpire(Blocks.COBBLE_NETHERRACK)) + .withBiomeMask(new Biome[]{Biomes.NETHER_CRAG, Biomes.NETHER_SHELF}) + .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(2))); + + this.register("minecraft:decoration/nether/default/volcano_roof_spire", new ChunkDecorationBuilder(new WorldFeatureRoofSpire(Blocks.BRIMSTONE)) + .withBiomeMask(new Biome[]{Biomes.NETHER_VOLCANIC_ISLANDS}) + .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(2))); + + this.register("minecraft:decoration/nether/default/sulfur_roof_spire", new ChunkDecorationBuilder(new WorldFeatureRoofSpire(Blocks.SULFUR)) + .withBiomeMask(new Biome[]{Biomes.NETHER_SULFUR_POOLS}) + .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(2))); + + this.register("minecraft:decoration/nether/default/oldworld_roof_spire", new ChunkDecorationBuilder(new WorldFeatureRoofSpire(Blocks.SLATE)) + .withBiomeMask(new Biome[]{Biomes.NETHER_OLD_WORLD}) + .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(2))); + + // Ore Features + this.register("minecraft:decoration/nether/default/nether_coal_ore", (new ChunkDecorationBuilder(new WorldFeatureOre(BlockLogicOreNetherCoal.variantMap, 12))) + .withPositionSelector(PositionSelectors.HeightRangeUniform) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(10))); + + this.register("minecraft:decoration/nether/default/nether_coal_ore_2", (new ChunkDecorationBuilder(new WorldFeatureOre(BlockLogicOreNetherCoal.variantMap, 12))) + .withBiomeMask(new Biome[]{Biomes.NETHER_VOLCANIC_ISLANDS}) + .withPositionSelector(PositionSelectors.HeightRangeUniform) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(20))); + + this.register("minecraft:decoration/nether/default/nether_coal_ore_3", (new ChunkDecorationBuilder(new WorldFeatureOre(BlockLogicOreNetherCoal.variantMap, 16))) + .withBiomeMask(new Biome[]{Biomes.NETHER_CRAG, Biomes.NETHER_SHELF}) + .withPositionSelector(PositionSelectors.HeightRangeUniform) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(10))); + + // Glowstone Features + this.register("minecraft:decoration/nether/default/glowstone_1", (new ChunkDecorationBuilder(new WorldFeatureGlowstone())) + .withBiomeMask(new Biome[]{Biomes.NETHER_VOLCANIC_ISLANDS, Biomes.NETHER_CRAG, Biomes.NETHER_CRYSTAL_PLAINS, Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_SHELF, Biomes.NETHER_SULFUR_POOLS}) + .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) + .withPlacementMethod((feature, world, chunk, random) -> { + int max = random.nextInt(random.nextInt(10) + 1); + + for (int i = 0; i < max; ++i) { + feature.placeFeature(world, chunk, random); + } + })); + + this.register("minecraft:decoration/nether/default/glowstone_2", (new ChunkDecorationBuilder(new WorldFeatureGlowstone())) + .withBiomeMask(new Biome[]{Biomes.NETHER_VOLCANIC_ISLANDS, Biomes.NETHER_CRAG, Biomes.NETHER_CRYSTAL_PLAINS, Biomes.NETHER_CRYSTAL_FOREST, Biomes.NETHER_SHELF, Biomes.NETHER_SULFUR_POOLS}) + .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(10))); + + this.register("minecraft:decoration/nether/default/glowstone_sulfur", (new ChunkDecorationBuilder(new WorldFeatureGlowstone())) + .withBiomeMask(new Biome[]{Biomes.NETHER_SULFUR_POOLS}) + .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(20))); + + // Fire Features + this.register("minecraft:decoration/nether/default/patch_fire", (new ChunkDecorationBuilder(new WorldFeatureFire())) + .withBiomeMask(new Biome[]{Biomes.NETHER_CRAG, Biomes.NETHER_SHELF}) + .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(16))); + + this.register("minecraft:decoration/nether/default/patch_fire_volcanic", (new ChunkDecorationBuilder(new WorldFeatureFire(Blocks.FIRE, Blocks.NETHERRACK))) + .withBiomeMask(new Biome[]{Biomes.NETHER_VOLCANIC_ISLANDS}) + .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(24))); + + this.register("minecraft:decoration/nether/default/patch_fire_sulfuric", (new ChunkDecorationBuilder(new WorldFeatureFire())) + .withBiomeMask(new Biome[]{Biomes.NETHER_SULFUR_POOLS}) + .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(32))); + + this.register("minecraft:decoration/nether/default/scatter", (new ChunkDecorationBuilder(new WorldFeatureNetherScatter())) + .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(32))); + + this.register("minecraft:decoration/nether/default/patch_soul_catcher", (new ChunkDecorationBuilder(new WorldFeatureSoulCatcherPatch())) + .withPositionSelector(PositionSelectors.HeightRangeUniformFromOcean) + .withPlacementMethod(new PlacementMethod.TriesPerChunk(2))); + + this.register("minecraft:decoration/nether/default/pebbles", (world, chunk, worldX, worldZ, minY, maxY, rangeY, rand) -> { + for (int i = 0; i < 16; ++i) { + int xx = worldX + rand.nextInt(16) + 8; + int yy = 64 + rand.nextInt(128); + int zz = worldZ + rand.nextInt(16) + 8; + (new WorldFeaturePebbles(Blocks.OVERLAY_PEBBLES, 16, true)).place(world, rand, xx, yy, zz); + } + }); + } + + private static boolean isRubyglassAshSupportForbidden(final @NotNull Block block) { + return block == Blocks.RUBYGLASS_NODE + || block == Blocks.RUBYGLASS_COLUMN + || block == Blocks.RUBYGLASS_GROWTH; } @Override public void postDecorate(@NotNull World world, @NotNull Chunk chunk) { TilePos queryPose = new TilePos(); - int oceanY = world.getWorldType().getOceanY(); int worldX = chunk.pos.x() * 16; int worldZ = chunk.pos.z() * 16; - int midY = oceanY + (world.getWorldType().getMaxY(world) - oceanY) / 2; - for (int dx = worldX; dx < worldX + 16; dx++) { - for (int dz = worldZ; dz < worldZ + 16; dz++) { - int dy = midY; - while (world.isAirBlock(queryPose.set(dx, dy, dz))) { - dy--; - } - dy++; - Biome localBiome = world.getBlockBiome(queryPose.set(dx, dy, dz)); + int startY = world.getWorldType().getMaxY(world); - if (localBiome.hasTag(BiomeTags.HAS_SURFACE_ASH) && dy > 0 && dy < world.getHeightBlocks()) { - if (world.isAirBlock(queryPose.set(dx, dy, dz)) && world.getBlockMaterial(queryPose.set(dx, dy - 1, dz)).blocksMotion()) { - world.setBlockType(queryPose.set(dx, dy, dz), Blocks.LAYER_ASH); + for (int dx = worldX; dx < worldX + 16; ++dx) { + for (int dz = worldZ; dz < worldZ + 16; ++dz) { + for (int dy = startY; dy > world.getWorldType().getOceanY(); --dy) { + queryPose.set(dx, dy, dz); + + if (world.isAirBlock(queryPose)) { + Block blockBelow = world.getBlock(dx, dy - 1, dz); + + if (blockBelow != Blocks.OBSIDIAN && blockBelow.getMaterial().blocksMotion() + && !isRubyglassAshSupportForbidden(blockBelow)) { + + Biome localBiome = world.getBlockBiome(queryPose); + if (localBiome.hasTag(BiomeTags.HAS_SURFACE_ASH)) { + world.setBlockType(queryPose, Blocks.LAYER_ASH); + } + } } } } - } } } diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkGeneratorNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkGeneratorNether.java index 159e90c92..5ba7fd264 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkGeneratorNether.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkGeneratorNether.java @@ -17,6 +17,7 @@ public class ChunkGeneratorNether { new CavesLargeFeature(64, 256), new LavaFloeLargeFeature(), + new RubyglassFloeLargeFeature(), new ShelfLargeFeature() } ); diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/DensityGeneratorNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/DensityGeneratorNether.java index e5b822b5a..095d6727c 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/DensityGeneratorNether.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/DensityGeneratorNether.java @@ -15,7 +15,7 @@ public class DensityGeneratorNether private final @NotNull Noise3D maxLimitNoise; private final @NotNull Noise3D mainNoise; - public DensityGeneratorNether(World world) { + public DensityGeneratorNether(@NotNull World world) { this.world = world; this.minLimitNoise = new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 16, 0)); @@ -38,7 +38,10 @@ public class DensityGeneratorNether int quarterYSize = ((terrainHeight / 4) / 8) + 1; int threeQuarterYSize = ((int) (terrainHeight * 0.75f) / 8) + 1; - double[] densityMapArray = new double[xSize * ySize * zSize]; + final int outerSize = xSize * ySize * zSize; + + // Allocate a fresh array locally for thread safety + double[] densityMapArray = new double[outerSize]; double[] biomeDensityMap = this.generateDensityMap(xSize, threeQuarterYSize, zSize, x, y, z); for (int dx = 0; dx < xSize; dx++) { @@ -53,8 +56,13 @@ public class DensityGeneratorNether return densityMapArray; } - private double[] generateDensityMap(int xSize, int ySize, int zSize, int x, int y, int z) { - double[] densityMapArray = new double[xSize * ySize * zSize]; + private double @NotNull[] generateDensityMap(int xSize, int ySize, int zSize, int x, int y, int z) { + final int innerSize = xSize * ySize * zSize; + + double[] densityMapArray = new double[innerSize]; + double[] mainNoiseArray = new double[innerSize]; + double[] minLimitArray = new double[innerSize]; + double[] maxLimitArray = new double[innerSize]; final double mainNoiseScaleX = 80.0; final double mainNoiseScaleY = 60.0; @@ -66,10 +74,12 @@ public class DensityGeneratorNether final double upperLimitScale = 512.0; final double lowerLimitScale = 512.0; - double[] mainNoiseArray = this.mainNoise.getRegion(null, x, y, z, xSize, ySize, zSize, coordScale / mainNoiseScaleX, heightScale / mainNoiseScaleY, coordScale / mainNoiseScaleZ); - double[] minLimitArray = this.minLimitNoise.getRegion(null, x, y, z, xSize, ySize, zSize, coordScale, heightScale, coordScale); - double[] maxLimitArray = this.maxLimitNoise.getRegion(null, x, y, z, xSize, ySize, zSize, coordScale, heightScale, coordScale); + this.mainNoise.getRegion(mainNoiseArray, x, y, z, xSize, ySize, zSize, coordScale / mainNoiseScaleX, heightScale / mainNoiseScaleY, coordScale / mainNoiseScaleZ); + this.minLimitNoise.getRegion(minLimitArray, x, y, z, xSize, ySize, zSize, coordScale, heightScale, coordScale); + this.maxLimitNoise.getRegion(maxLimitArray, x, y, z, xSize, ySize, zSize, coordScale, heightScale, coordScale); + int mainIndex = 0; + double[] densityOffsetArray = new double[ySize]; for (int dy = 0; dy < ySize; dy++) { densityOffsetArray[dy] = Math.cos(((double) dy * Math.PI * 6D) / (double) ySize) * 2D; @@ -110,9 +120,7 @@ public class DensityGeneratorNether densityMapArray[mainIndex] = density; mainIndex++; } - } - } return densityMapArray; diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/SurfaceGeneratorNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/SurfaceGeneratorNether.java index cc925031c..9f48d9c37 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/SurfaceGeneratorNether.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/SurfaceGeneratorNether.java @@ -14,8 +14,7 @@ import org.jetbrains.annotations.NotNull; import java.util.Random; -public class SurfaceGeneratorNether - implements SurfaceGenerator { +public class SurfaceGeneratorNether implements SurfaceGenerator { private final @NotNull World world; private final @NotNull FractalNoise3D beachNoise; @@ -24,7 +23,22 @@ public class SurfaceGeneratorNether private final boolean generateStoneVariants = true; + // Cache common block IDs to avoid lookups + private final short soulSandId = (short) Blocks.SOULSAND.id(); + private final short sulfurId = (short) Blocks.SULFUR.id(); + private final short sulfurHardenedId = (short) Blocks.SULFUR_HARDENED.id(); + private final short brimsandId = (short) Blocks.BRIMSAND.id(); + private final short brimstoneId = (short) Blocks.BRIMSTONE.id(); + private final short netherrackId = (short) Blocks.NETHERRACK.id(); + private final short cobbleNetherrackId = (short) Blocks.COBBLE_NETHERRACK.id(); + private final short cobbleNetherrackCrystallineId = (short) Blocks.COBBLE_NETHERRACK_CRYSTALLINE.id(); + private final short cobbleGloomstoneId = (short) Blocks.COBBLE_GLOOMSTONE.id(); + private final short glowstoneId = (short) Blocks.GLOWSTONE.id(); + private final short ashId = (short) Blocks.BLOCK_ASH.id(); + private final short slateId = (short) Blocks.SLATE.id(); + public SurfaceGeneratorNether(@NotNull World world) { + super(); this.world = world; this.beachNoise = new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(world.getRandomSeed(), 4, 40)); @@ -40,65 +54,70 @@ public class SurfaceGeneratorNether int chunkX = chunk.pos.x; int chunkZ = chunk.pos.z; + // Precompute + int absoluteOceanY = minY + oceanY; + int chunkWorldX = chunkX * Chunk.CHUNK_SIZE_X; + int chunkWorldZ = chunkZ * Chunk.CHUNK_SIZE_Z; + int oceanBlock = this.world.getWorldType().getOceanBlockIds()[0]; int worldFillBlock = this.world.getWorldType().getFillerBlockId(); Random rand = new Random((long) chunkX * 0x4F9939F508L + (long) chunkZ * 0x1EF1565BD5L); double beachScale = 0.03125D; - double[] sandBeachNoise = this.beachNoise.getRegion(null, chunkX * 16, chunkZ * 16, 0.0D, 16, 16, 1, beachScale, beachScale, 1.0D); - double[] gravelBeachNoise = this.beachNoise.getRegion(null, chunkX * 16, 109.0134D, chunkZ * 16, 16, 1, 16, beachScale, 1.0D, beachScale); - double[] soilThicknessNoise = this.soilNoise.getRegion(null, chunkX * 16, chunkZ * 16, 0.0D, 16, 16, 1, beachScale * 2D, beachScale * 2D, beachScale * 2D); + double[] sandBeachNoise = this.beachNoise.getRegion(null, chunkWorldX, chunkWorldZ, 0.0D, 16, 16, 1, beachScale, beachScale, 1.0D); + double[] gravelBeachNoise = this.beachNoise.getRegion(null, chunkWorldX, 109.0134D, chunkWorldZ, 16, 1, 16, beachScale, 1.0D, beachScale); + double[] soilThicknessNoise = this.soilNoise.getRegion(null, chunkWorldX, chunkWorldZ, 0.0D, 16, 16, 1, beachScale * 2D, beachScale * 2D, beachScale * 2D); - double[] stoneLayerNoiseBasalt = null; +/* double[] stoneLayerNoiseBasalt = null; double[] stoneLayerNoiseNetherrack = null; double[] stoneLayerNoiseGloomstone = null; if (this.generateStoneVariants) { stoneLayerNoiseBasalt = this.soilNoise.getRegion(null, chunkX * Chunk.CHUNK_SIZE_X, chunkZ * Chunk.CHUNK_SIZE_Z, 0.0D, Chunk.CHUNK_SIZE_X, Chunk.CHUNK_SIZE_Z, 1, beachScale * 4D, beachScale * 4D, beachScale * 4D); stoneLayerNoiseNetherrack = this.mainNoise.getRegion(null, chunkX * Chunk.CHUNK_SIZE_X, chunkZ * Chunk.CHUNK_SIZE_Z, 0.0D, Chunk.CHUNK_SIZE_X, Chunk.CHUNK_SIZE_Z, 1, beachScale * 4D, beachScale * 4D, beachScale * 4D); stoneLayerNoiseGloomstone = this.beachNoise.getRegion(null, chunkX * Chunk.CHUNK_SIZE_X, chunkZ * Chunk.CHUNK_SIZE_Z, 0.0D, Chunk.CHUNK_SIZE_X, Chunk.CHUNK_SIZE_Z, 1, beachScale * 4D, beachScale * 4D, beachScale * 4D); - } + }*/ + for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { - boolean generateSoulSandBeach = sandBeachNoise[z + x * 16] + rand.nextDouble() * 0.2D > 0.0D; - boolean generateGravelBeach = gravelBeachNoise[z + x * 16] + rand.nextDouble() * 0.2D > 0.0D; - int soilThickness = (int) (soilThicknessNoise[z + x * 16] / 3D + 3D + rand.nextDouble() * 0.25D); - - boolean generateBasaltLayer = false; - boolean generateNetherrackLayer = false; - boolean generateGloomstoneLayer = false; - - int basaltThicknessLevel = 0; - int netherrackThicknessLevel = 0; - int gloomstoneThicknessLevel = 0; - - if (this.generateStoneVariants) { - generateBasaltLayer = stoneLayerNoiseBasalt[z + (x * Chunk.CHUNK_SIZE_Z)] + rand.nextDouble() * 0.2D > 0D; - generateNetherrackLayer = stoneLayerNoiseNetherrack[z + (x * Chunk.CHUNK_SIZE_Z)] + rand.nextDouble() * 0.2D > 2D; - generateGloomstoneLayer = stoneLayerNoiseGloomstone[z + (x * Chunk.CHUNK_SIZE_Z)] + rand.nextDouble() * 0.2D > 3D; - basaltThicknessLevel = (int)(stoneLayerNoiseBasalt[z + x] + rand.nextDouble() * 0.5D); - netherrackThicknessLevel = (int)(stoneLayerNoiseNetherrack[z + x] + rand.nextDouble() * 0.5D); - gloomstoneThicknessLevel = (int)(stoneLayerNoiseGloomstone[z + x] + rand.nextDouble() * 0.5D); - } + int noiseIndex = z + x * 16; + boolean generateSoulSandBeach = sandBeachNoise[noiseIndex] + rand.nextDouble() * 0.2D > 0.0D; + boolean generateGravelBeach = gravelBeachNoise[noiseIndex] + rand.nextDouble() * 0.2D > 0.0D; + int soilThickness = (int) (soilThicknessNoise[noiseIndex] / 3D + 3D + rand.nextDouble() * 0.25D); int currentLayerDepth = -1; short topBlock = -1; short fillerBlock = -1; Biome lastBiome = null; + int worldX = chunkWorldX + x; + int worldZ = chunkWorldZ + z; + + short cachedBiomeTopBlock = -1; + short cachedBiomeFillerBlock = -1; + boolean cachedBiomeGeneratesSulfur = false; + int cachedBiomeStoneBlockId = worldFillBlock; for (int y = maxY; y >= minY; y--) { Biome biome = chunk.getBlockBiome(x, y, z); - if (biome == null) - biome = this.world.getBiomeProvider().getBiome(chunkX * Chunk.CHUNK_SIZE_X + x, y >> 3, chunkZ * Chunk.CHUNK_SIZE_Z + z); + if (biome == null) { + biome = this.world.getBiomeProvider().getBiome(worldX, y >> 3, worldZ); + } + + if (biome != lastBiome) { + cachedBiomeTopBlock = (short) biome.getSurfaceProperties().getTopBlock().id(); + cachedBiomeFillerBlock = (short) biome.getSurfaceProperties().getFillerBlock().id(); + cachedBiomeGeneratesSulfur = biome.hasTag(BiomeTags.HAS_SULFUR_POOLS); + cachedBiomeStoneBlockId = computeBiomeStoneBlock(biome, worldFillBlock); + lastBiome = biome; + } int block = result.getBlock(x, y, z); - if ((biome != lastBiome || topBlock == -1 || fillerBlock == -1) && block == 0) { - topBlock = (short) biome.getSurfaceProperties().getTopBlock().id(); - fillerBlock = (short) biome.getSurfaceProperties().getFillerBlock().id(); + if ((topBlock == -1 || fillerBlock == -1) && block == 0) { + topBlock = cachedBiomeTopBlock; + fillerBlock = cachedBiomeFillerBlock; } - lastBiome = biome; // reset the currently generating surface thickness to -1 if encountered air if (block == 0) { @@ -116,38 +135,36 @@ public class SurfaceGeneratorNether // if soil thickness is below 0, generate a stone basin where there is no top block layer if (soilThickness <= 0) { topBlock = 0; - fillerBlock = (short) Blocks.NETHERRACK.id(); + if (biome == Biomes.NETHER_VOLCANIC_ISLANDS) { + fillerBlock = brimsandId; + } else if (biome == Biomes.NETHER_SULFUR_POOLS) { + fillerBlock = sulfurId; + } else if (biome == Biomes.NETHER_OLD_WORLD || biome == Biomes.NETHER_OLD_WORLD_DESERT) { + fillerBlock = cobbleGloomstoneId; + } else { + fillerBlock = netherrackId; + } } else { - boolean biomeGeneratesSulfur = biome.hasTag(BiomeTags.HAS_SULFUR_POOLS); - - if (y >= minY + oceanY - 4 && y <= minY + oceanY + 1) { - // Generate coastlines - topBlock = (short) biome.getSurfaceProperties().getTopBlock().id(); - fillerBlock = (short) biome.getSurfaceProperties().getFillerBlock().id(); - if (generateGravelBeach) { - topBlock = (short) Blocks.GRAVEL.id(); - fillerBlock = (short) Blocks.GRAVEL.id(); - } if (generateSoulSandBeach) { - topBlock = (short) Blocks.SOULSAND.id(); - fillerBlock = (short) Blocks.SOULSAND.id(); - } - } else if (y <= oceanY) { - if (biomeGeneratesSulfur) { - topBlock = (short) Blocks.BRIMSAND.id(); - fillerBlock = (short) Blocks.BRIMSAND.id(); + if (y >= absoluteOceanY - 4 && y <= absoluteOceanY + 1) { + topBlock = cachedBiomeTopBlock; + fillerBlock = cachedBiomeFillerBlock; + if (generateGravelBeach || generateSoulSandBeach) { + topBlock = soulSandId; + fillerBlock = soulSandId; } + } else if (y <= oceanY && cachedBiomeGeneratesSulfur) { + topBlock = sulfurId; + fillerBlock = sulfurHardenedId; } } - // failsafe so that if a basin is generated under the ocean, the ocean is not replaced with air - if (y < minY + oceanY && topBlock == 0) { + if (y < absoluteOceanY && topBlock == 0) { topBlock = (short) oceanBlock; } - // if a new surface layer has been chosen to be generated, set the current layer depth to the generated soil thickness level and begin generating downwards - currentLayerDepth = soilThickness+2; - // set block at index to designated surface block above ocean level - if (y >= minY + oceanY - 1) { + currentLayerDepth = soilThickness + 2; + + if (y >= absoluteOceanY - 1) { result.setBlock(x, y, z, topBlock); } else { // if the block is below ocean level, set it to the chosen filler block @@ -156,45 +173,40 @@ public class SurfaceGeneratorNether continue; } - if (this.generateStoneVariants) { - if (currentLayerDepth <= 0) { - if (y >= (minY + basaltThicknessLevel - rand.nextInt(3)) && y <= (maxY - basaltThicknessLevel + rand.nextInt(3))) { - if (generateBasaltLayer) { - result.setBlock(x, y, z, Blocks.COBBLE_BASALT.id()); - continue; - } - } - if (y >= (minY + netherrackThicknessLevel - rand.nextInt(3)) && y <= (maxY - netherrackThicknessLevel + rand.nextInt(3))) { - if (generateNetherrackLayer) { - result.setBlock(x, y, z, Blocks.NETHERRACK.id()); - continue; - } - } - if (y >= (minY + gloomstoneThicknessLevel - rand.nextInt(3)) && y <= (maxY - gloomstoneThicknessLevel + rand.nextInt(3))) { - if (generateGloomstoneLayer) { - result.setBlock(x, y, z, Blocks.COBBLE_GLOOMSTONE.id()); - continue; - } - } - continue; - } - } - - // fill blocks with filler block until current layer level = -1 or air is encountered if (currentLayerDepth > 0) { - currentLayerDepth--; result.setBlock(x, y, z, fillerBlock); + currentLayerDepth--; + } + + if (currentLayerDepth == 0 && biome == Biomes.NETHER_OLD_WORLD && fillerBlock == ashId) { + currentLayerDepth = rand.nextInt(8) + 2; + fillerBlock = slateId; } - if(currentLayerDepth == 0) - { - if(biome.hasTag(BiomeTags.HAS_SULFUR_POOLS) && fillerBlock == Blocks.BRIMSAND.id()) { - currentLayerDepth = rand.nextInt(4) + 2; - fillerBlock = (short)Blocks.BRIMSAND.id(); + if (this.generateStoneVariants && currentLayerDepth <= 0) { + int stoneBlockId = cachedBiomeStoneBlockId; + // Crag/shelf is the only biome with a randomized variant per block. + if (biome == Biomes.NETHER_CRAG || biome == Biomes.NETHER_SHELF) { + stoneBlockId = (rand.nextInt(2) == 0) ? netherrackId : cobbleNetherrackId; } + result.setBlock(x, y, z, stoneBlockId); } } } } } -} + + private int computeBiomeStoneBlock(Biome biome, int worldFillBlock) { + if (biome == Biomes.NETHER_VOLCANIC_ISLANDS) { + return brimsandId; + } else if (biome == Biomes.NETHER_SULFUR_POOLS) { + return brimstoneId; + } else if (biome == Biomes.NETHER_CRYSTAL_PLAINS || biome == Biomes.NETHER_CRYSTAL_FOREST) { + return cobbleNetherrackId; + } else if (biome == Biomes.NETHER_OLD_WORLD || biome == Biomes.NETHER_OLD_WORLD_DESERT) { + return cobbleGloomstoneId; + } + // Crag/Shelf use a randomized choice per block, so callers handle them separately. + return worldFillBlock; + } +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/TerrainGeneratorNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/TerrainGeneratorNether.java index 296323d8b..6c0280e47 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/TerrainGeneratorNether.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/TerrainGeneratorNether.java @@ -1,100 +1,111 @@ package net.minecraft.core.world.generate.chunk.perlin.nether; -import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; -import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.minecraft.core.block.Blocks; import net.minecraft.core.world.World; import net.minecraft.core.world.biome.Biome; -import net.minecraft.core.world.biome.BiomeTags; import net.minecraft.core.world.biome.Biomes; import net.minecraft.core.world.chunk.Chunk; -import net.minecraft.core.world.chunk.ChunkSection; import net.minecraft.core.world.generate.chunk.perlin.DensityGenerator; import net.minecraft.core.world.generate.chunk.perlin.TerrainGeneratorLerp; -import net.minecraft.core.world.noise.FractalNoise3D; -import net.minecraft.core.world.noise.ImprovedPerlinNoise; -import net.minecraft.core.world.noise.Noise3D; -import net.minecraft.core.world.type.WorldType; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -public class TerrainGeneratorNether - extends TerrainGeneratorLerp { - private final DensityGenerator densityGenerator; +public class TerrainGeneratorNether extends TerrainGeneratorLerp { + private static final int OCEAN_FLUID_UNCACHED = -1; - private final int lastX = Integer.MIN_VALUE; - private final int lastZ = Integer.MIN_VALUE; - private @Nullable Biome lastBiome = null; - private final Object2IntMap fluidLookup = new Object2IntArrayMap<>(); -// private int lastChunkX = Integer.MIN_VALUE; -// private int lastChunkZ = Integer.MIN_VALUE; -// private final @NotNull Noise3D noise = new FractalNoise3D<>(ImprovedPerlinNoise.genOctaves(0L, 4, 0)); -// private final double @NotNull [] cache = new double[Chunk.CHUNK_SIZE_X * Chunk.CHUNK_SIZE_Z * (Chunk.CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y)]; + private final DensityGenerator densityGenerator; private final int minY; private final int maxY; + private final int quarterHeight; + private final int bedrockId; + private final int airId; + private final int rubyglassId; + private final int waterId; + private final int oceanY; + private final int fillerBlockId; + private final int lavaId; + private final int cobbleNetherrackId; + private final int obsidianId; + + private final ThreadLocal oceanFluidByXZ = ThreadLocal.withInitial(() -> new int[256]); + private final ThreadLocal lastChunk = new ThreadLocal<>();; public TerrainGeneratorNether(@NotNull World world) { super(world); this.densityGenerator = new DensityGeneratorNether(world); - this.fluidLookup.put(Biomes.NETHER_VOLCANIC_ISLANDS, Blocks.FLUID_LAVA_STILL.id()); - this.fluidLookup.put(Biomes.NETHER_SULFUR_POOLS, Blocks.FLUID_LAVA_STILL.id()); - this.fluidLookup.put(Biomes.NETHER_CRAG, Blocks.FLUID_LAVA_STILL.id()); - this.fluidLookup.put(Biomes.NETHER_SHELF, Blocks.COBBLE_NETHERRACK.id()); - this.fluidLookup.put(Biomes.NETHER_CRYSTAL_FOREST, Blocks.FLUID_WATER_STILL.id()); - this.fluidLookup.put(Biomes.NETHER_CRYSTAL_PLAINS, Blocks.FLUID_WATER_STILL.id()); - this.fluidLookup.put(Biomes.NETHER_OLD_WORLD, Blocks.FLUID_WATER_STILL.id()); - this.fluidLookup.put(Biomes.NETHER_OLD_WORLD_DESERT, Blocks.FLUID_WATER_STILL.id()); - this.minY = world.getWorldType().getMinY(world); this.maxY = world.getWorldType().getMaxY(world); + this.quarterHeight = this.maxY / 4; + + // Cache block IDs to avoid repeated lookups to the Block objects themselves. + this.bedrockId = Blocks.BEDROCK.id(); + this.airId = Blocks.AIR.id(); + this.rubyglassId = Blocks.RUBYGLASS_CRYSTAL.id(); + this.waterId = Blocks.FLUID_WATER_STILL.id(); + this.lavaId = Blocks.FLUID_LAVA_STILL.id(); + this.cobbleNetherrackId = Blocks.COBBLE_NETHERRACK.id(); + this.obsidianId = Blocks.OBSIDIAN.id(); + this.oceanY = world.getWorldType().getOceanY(); + this.fillerBlockId = world.getWorldType().getFillerBlockId(); } - @Override - protected int getBlockAt(@NotNull Chunk chunk, int x, int y, int z, double density) { - if (this.lastX != x || this.lastZ != z) { - this.lastBiome = chunk.getBlockBiome(x, 0, z); + private int getFluidForBiome(Biome biome) { + if (biome == Biomes.NETHER_VOLCANIC_ISLANDS || biome == Biomes.NETHER_SULFUR_POOLS || biome == Biomes.NETHER_CRAG) { + return this.lavaId; + } else if (biome == Biomes.NETHER_CRYSTAL_FOREST || biome == Biomes.NETHER_CRYSTAL_PLAINS) { + return this.waterId; + } else if (biome == Biomes.NETHER_SHELF) { + return this.cobbleNetherrackId; + } else if (biome == Biomes.NETHER_OLD_WORLD) { + return this.obsidianId; } + return 0; + } - WorldType type = this.world.getWorldType(); - int quarterHeight = maxY / 4; + private int getCachedOceanFluid(@NotNull Chunk chunk, int x, int z) { + int[] cache = this.oceanFluidByXZ.get(); - if (y < quarterHeight) { - return 0; - } else if (y >= maxY - this.rand.nextInt(5)) { - return Blocks.BEDROCK.id(); - } else if (y <= quarterHeight + this.rand.nextInt(5)) { - return Blocks.BEDROCK.id(); - } else if (density > 0.0) { -// Disabled crystalline netherrack veins -// if (this.lastBiome != null && this.lastBiome.hasTag(BiomeTags.HAS_CRYSTAL_VEINS)) { -// int sizeY = Chunk.CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y; -// -// if (this.lastChunkX != chunk.pos.x || this.lastChunkZ != chunk.pos.z) { -// this.lastChunkX = chunk.pos.x; -// this.lastChunkZ = chunk.pos.z; -// this.noise.getRegion(this.cache, chunk.pos.x * Chunk.CHUNK_SIZE_X, 0, chunk.pos.z * Chunk.CHUNK_SIZE_Z, Chunk.CHUNK_SIZE_X, Chunk.CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z, 0.2, 0.2, 0.2); -// } -// -// // YZX ordering -// final double d = ((this.cache[(x * Chunk.CHUNK_SIZE_Z * sizeY) + (z * sizeY) + y])); -// if (d > -1 && d < 2) { -// return Blocks.COBBLE_NETHERRACK_CRYSTALLINE.id(); -// } -// } - - return type.getFillerBlockId(); - } else if (y < type.getOceanY()) { - return this.fluidLookup.getOrDefault(this.lastBiome, 0); + if (chunk != this.lastChunk.get()) { + java.util.Arrays.fill(cache, OCEAN_FLUID_UNCACHED); + this.lastChunk.set(chunk); } - return 0; + final int idx = (x << 4) | z; + int cached = cache[idx]; + if (cached == OCEAN_FLUID_UNCACHED) { + cached = this.getFluidForBiome(chunk.getBlockBiome(x, this.oceanY, z)); + cache[idx] = cached; + } + return cached; + } + + @Override + protected int getBlockAt(@NotNull Chunk chunk, int x, int y, int z, double density) { + if (y < this.quarterHeight) { + return this.bedrockId; + } else if (y >= this.maxY - this.rand.nextInt(10)) { + return this.bedrockId; + } else if (y <= this.quarterHeight + this.rand.nextInt(10)) { + return this.bedrockId; + } else if (density > 0.0) { + return this.fillerBlockId; + } else if (y < this.oceanY) { + final int fluidId = this.getCachedOceanFluid(chunk, x, z); + + if (fluidId == this.waterId && y == this.oceanY - 1) { + return this.rubyglassId; + } + + return fluidId; + } else { + return this.airId; + } } @Override public @NotNull DensityGenerator getDensityGenerator() { return this.densityGenerator; } -} +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java index 68869919e..08ede7be9 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java @@ -1,5 +1,6 @@ package net.minecraft.core.world.generate.chunk.perlin.overworld; +import com.mojang.logging.LogUtils; import net.minecraft.core.block.BlockLogicLeavesBase; import net.minecraft.core.block.BlockLogicMoss; import net.minecraft.core.block.BlockLogicOreCoal; @@ -21,17 +22,29 @@ import net.minecraft.core.world.biome.overworld.BiomeOutback; import net.minecraft.core.world.chunk.Chunk; import net.minecraft.core.world.generate.chunk.ChunkDecorator; import net.minecraft.core.world.generate.feature.*; +import net.minecraft.core.world.pos.TilePos; import net.minecraft.core.world.type.tag.WorldTypeTags; import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; import java.util.Random; public class ChunkDecoratorOverworld implements ChunkDecorator { + private static final @NotNull Logger LOGGER = LogUtils.getLogger(); + private final @NotNull World world; private final @NotNull FractalNoise2D treeDensityNoise; private final int treeDensityOverride; + private static void runStep(@NotNull String name, int chunkX, int chunkZ, @NotNull Runnable action) { + try { + action.run(); + } catch (final Throwable t) { + LOGGER.error("Decoration step '{}' failed at chunk ({}, {}); continuing.", name, chunkX, chunkZ, t); + } + } + protected ChunkDecoratorOverworld(@NotNull World world, int treeDensityOverride) { this.world = world; this.treeDensityOverride = treeDensityOverride; @@ -46,8 +59,12 @@ public class ChunkDecoratorOverworld @Override public void decorate(@NotNull Chunk chunk) { this.world.scheduledUpdatesAreImmediate = true; - int chunkX = chunk.pos.x; - int chunkZ = chunk.pos.z; + BlockLogicFallingBlock.fallInstantly = true; + + final int chunkX = chunk.pos.x; + final int chunkZ = chunk.pos.z; + + try { int minY = this.world.getWorldType().getMinY(world); int maxY = this.world.getWorldType().getMaxY(world); @@ -55,7 +72,6 @@ public class ChunkDecoratorOverworld float oreHeightModifier = rangeY / 128f; - BlockLogicFallingBlock.fallInstantly = true; int x = chunkX * 16; int z = chunkZ * 16; int y = this.world.getHeightValue(x + 16, z + 16); @@ -67,6 +83,7 @@ public class ChunkDecoratorOverworld Random swampRand = new Random((long) chunkX * l1 + (long) chunkZ * l2 ^ this.world.getRandomSeed()); // Water pass for swamps + try { if (biome.hasTag(BiomeTags.HAS_SURFACE_WATER)) { for (int dx = 0; dx < 16; dx++) { for (int dz = 0; dz < 16; dz++) { @@ -95,7 +112,9 @@ public class ChunkDecoratorOverworld } } } + } catch (final Throwable t) { LOGGER.error("Decoration step 'swamp_water' failed at chunk ({}, {}); continuing.", chunkX, chunkZ, t); } + try { int lakeChance = 4; if (biome == Biomes.OVERWORLD_SWAMPLAND) lakeChance = 2; @@ -119,6 +138,9 @@ public class ChunkDecoratorOverworld new WorldFeatureLake(Blocks.FLUID_LAVA_STILL.id()).place(this.world, rand, xf, yf, zf); } } + } catch (final Throwable t) { LOGGER.error("Decoration step 'lakes' failed at chunk ({}, {}); continuing.", chunkX, chunkZ, t); } + + try { for (int k1 = 0; k1 < (8 * oreHeightModifier); k1++) { int j5 = x + rand.nextInt(16) + 8; int k8 = minY + rand.nextInt(rangeY); @@ -148,7 +170,9 @@ public class ChunkDecoratorOverworld new WorldFeatureDungeon(Blocks.COBBLE_BASALT.id(), Blocks.COBBLE_BASALT_MOSSY.id(), null).place(this.world, rand, j5, k8, j11); } } + } catch (final Throwable t) { LOGGER.error("Decoration step 'dungeons' failed at chunk ({}, {}); continuing.", chunkX, chunkZ, t); } + try { for (int k1 = 0; k1 < 1; k1++) { int j5 = x + rand.nextInt(16) + 8; int j11 = z + rand.nextInt(16) + 8; @@ -164,7 +188,9 @@ public class ChunkDecoratorOverworld (new WorldFeatureLabyrinth()).place(this.world, lRand, j5, k8, j11); } } + } catch (final Throwable t) { LOGGER.error("Decoration step 'labyrinth' failed at chunk ({}, {}); continuing.", chunkX, chunkZ, t); } + try { for (int i2 = 0; i2 < (20 * oreHeightModifier); i2++) { int k5 = x + rand.nextInt(16); int l8 = minY + rand.nextInt(rangeY); @@ -186,71 +212,83 @@ public class ChunkDecoratorOverworld (new WorldFeaturePermaice(32 + rand.nextInt(32), Blocks.PERMAFROST)).place(this.world, rand, j7, k10, j13); } } + } catch (final Throwable t) { LOGGER.error("Decoration step 'clay_dirt_permaice' failed at chunk ({}, {}); continuing.", chunkX, chunkZ, t); } + try { for (int j2 = 0; j2 < (20 * oreHeightModifier); j2++) { int l5 = x + rand.nextInt(16); int i9 = minY + rand.nextInt(rangeY); int l11 = z + rand.nextInt(16); - (new WorldFeatureOre(Blocks.DIRT.id(), 32)).place(this.world, rand, l5, i9, l11); + TilePos queryPos = new TilePos(l5, i9, l11); + (new WorldFeatureOre(Blocks.DIRT.id(), 32)).place(this.world, rand, queryPos); } for (int k2 = 0; k2 < (10 * oreHeightModifier); k2++) { int i6 = x + rand.nextInt(16); int j9 = minY + rand.nextInt(rangeY); int i12 = z + rand.nextInt(16); - (new WorldFeatureOre(Blocks.GRAVEL.id(), 32)).place(this.world, rand, i6, j9, i12); + TilePos queryPos = new TilePos(i6, j9, i12); + (new WorldFeatureOre(Blocks.GRAVEL.id(), 32)).place(this.world, rand, queryPos); } for (int i3 = 0; i3 < (20 * oreHeightModifier); i3++) { int j6 = x + rand.nextInt(16); int k9 = minY + rand.nextInt(rangeY); int j12 = z + rand.nextInt(16); - new WorldFeatureOre(BlockLogicOreCoal.variantMap, 16).place(this.world, rand, j6, k9, j12); + TilePos queryPos = new TilePos(j6, k9, j12); + new WorldFeatureOre(BlockLogicOreCoal.variantMap, 16).place(this.world, rand, queryPos); } for (int j3 = 0; j3 < (20 * oreHeightModifier); j3++) { int k6 = x + rand.nextInt(16); int l9 = minY + rand.nextInt(rangeY / 2); int k12 = z + rand.nextInt(16); - (new WorldFeatureOre(BlockLogicOreIron.variantMap, 8)).place(this.world, rand, k6, l9, k12); + TilePos queryPos = new TilePos(k6, l9, k12); + (new WorldFeatureOre(BlockLogicOreIron.variantMap, 8)).place(this.world, rand, queryPos); } for (int k3 = 0; k3 < (2 * oreHeightModifier); k3++) { int l6 = x + rand.nextInt(16); int i10 = minY + rand.nextInt(rangeY / 4); int l12 = z + rand.nextInt(16); - (new WorldFeatureOre(BlockLogicOreGold.variantMap, 8)).place(this.world, rand, l6, i10, l12); + TilePos queryPos = new TilePos(l6, i10, l12); + (new WorldFeatureOre(BlockLogicOreGold.variantMap, 8)).place(this.world, rand, queryPos); } for (int l3 = 0; l3 < (8 * oreHeightModifier); l3++) { int i7 = x + rand.nextInt(16); int j10 = minY + rand.nextInt(rangeY / 8); int i13 = z + rand.nextInt(16); - (new WorldFeatureOre(BlockLogicOreRedstone.variantMap, 7)).place(this.world, rand, i7, j10, i13); + TilePos queryPos = new TilePos(i7, j10, i13); + (new WorldFeatureOre(BlockLogicOreRedstone.variantMap, 7)).place(this.world, rand, queryPos); } for (int i4 = 0; i4 < oreHeightModifier; i4++) { int j7 = x + rand.nextInt(16); int k10 = minY + rand.nextInt(rangeY / 8); int j13 = z + rand.nextInt(16); - (new WorldFeatureOre(BlockLogicOreDiamond.variantMap, 7)).place(this.world, rand, j7, k10, j13); + TilePos queryPos = new TilePos(j7, k10, j13); + (new WorldFeatureOre(BlockLogicOreDiamond.variantMap, 7)).place(this.world, rand, queryPos); } for (int i4 = 0; i4 < oreHeightModifier; i4++) { int j7 = x + rand.nextInt(16); int k10 = minY + rand.nextInt(rangeY / 2); int j13 = z + rand.nextInt(16); - (new WorldFeatureMoss(BlockLogicMoss.variantMap, 32)).place(this.world, rand, j7, k10, j13); + TilePos queryPos = new TilePos(j7, k10, j13); + (new WorldFeatureMoss(BlockLogicMoss.variantMap, 32)).place(this.world, rand, queryPos); } for (int j4 = 0; j4 < oreHeightModifier; j4++) { int k7 = x + rand.nextInt(16); int l10 = minY + rand.nextInt(rangeY / 8) + rand.nextInt(rangeY / 8); int k13 = z + rand.nextInt(16); - (new WorldFeatureOre(BlockLogicOreLapis.variantMap, 6)).place(this.world, rand, k7, l10, k13); + TilePos queryPos = new TilePos(k7, l10, k13); + (new WorldFeatureOre(BlockLogicOreLapis.variantMap, 6)).place(this.world, rand, queryPos); } + } catch (final Throwable t) { LOGGER.error("Decoration step 'ores' failed at chunk ({}, {}); continuing.", chunkX, chunkZ, t); } - + try { double d = 0.5D; int k4 = (int) ((this.treeDensityNoise.getValue((double) x * d, (double) z * d) / 8D + rand.nextDouble() * 4D + 4D) / 3D); int treeDensity = 0; @@ -300,15 +338,24 @@ public class ChunkDecoratorOverworld try { BlockLogicLeavesBase.enableDecay = false; for (int i11 = 0; i11 < treeDensity; i11++) { - int l13 = x + rand.nextInt(16) + 8; - int j14 = z + rand.nextInt(16) + 8; - WorldFeature feature = biome.getTreeFeature(rand); - feature.init(1.0D, 1.0D, 1.0D); - feature.place(this.world, rand, l13, this.world.getHeightValue(l13, j14), j14); + // Per-tree try/catch: a single bad placement (e.g. NPE inside a tree feature) + // would otherwise abort the rest of the forest and produce visible cutoffs. + try { + int l13 = x + rand.nextInt(16) + 8; + int j14 = z + rand.nextInt(16) + 8; + WorldFeature feature = biome.getTreeFeature(rand); + feature.init(1.0D, 1.0D, 1.0D); + feature.place(this.world, rand, l13, this.world.getHeightValue(l13, j14), j14); + } catch (final Throwable treeT) { + LOGGER.error("Tree placement #{} failed at chunk ({}, {}); continuing.", i11, chunkX, chunkZ, treeT); + } } } finally { BlockLogicLeavesBase.enableDecay = true; } + } catch (final Throwable t) { LOGGER.error("Decoration step 'trees' failed at chunk ({}, {}); continuing.", chunkX, chunkZ, t); } + + try { byte byteReeds = 0; if (biome == Biomes.OVERWORLD_RAINFOREST) { byteReeds = 1; @@ -363,7 +410,9 @@ public class ChunkDecoratorOverworld int j24 = z + rand.nextInt(16) + 8; (new WorldFeatureFlowers(blockId, 128, true)).place(this.world, rand, l19, k22, j24); } + } catch (final Throwable t) { LOGGER.error("Decoration step 'reeds_orchids_meadows' failed at chunk ({}, {}); continuing.", chunkX, chunkZ, t); } + try { byte byteBluebells = 0; if (biome == Biomes.OVERWORLD_FOREST) { byteBluebells = 2; @@ -435,7 +484,9 @@ public class ChunkDecoratorOverworld int k19 = z + rand.nextInt(16) + 8; (new WorldFeatureFlowers(Blocks.FLOWER_YELLOW.id(), 64, true)).place(this.world, rand, k14, l16, k19); } + } catch (final Throwable t) { LOGGER.error("Decoration step 'flowers_blue_orange_yellow' failed at chunk ({}, {}); continuing.", chunkX, chunkZ, t); } + try { byte byte1 = 0; if (biome == Biomes.OVERWORLD_FOREST) { byte1 = 2; @@ -502,7 +553,9 @@ public class ChunkDecoratorOverworld int l22 = z + rand.nextInt(16) + 8; (new WorldFeatureDeadBush(Blocks.DEADBUSH.id())).place(this.world, rand, i17, i20, l22); } + } catch (final Throwable t) { LOGGER.error("Decoration step 'tallgrass_spinifex_deadbush' failed at chunk ({}, {}); continuing.", chunkX, chunkZ, t); } + try { if (rand.nextInt(2) == 0) { int j15 = x + rand.nextInt(16) + 8; int j17 = minY + rand.nextInt(rangeY); @@ -554,7 +607,9 @@ public class ChunkDecoratorOverworld int k24 = z + rand.nextInt(16) + 8; (new WorldFeatureCactus()).place(this.world, rand, k21, j23, k24); } + } catch (final Throwable t) { LOGGER.error("Decoration step 'mushrooms_pumpkin_sponge_cactus' failed at chunk ({}, {}); continuing.", chunkX, chunkZ, t); } + try { for (int l18 = 0; l18 < 50; l18++) { int l21 = x + rand.nextInt(16) + 8; int k23 = minY + rand.nextInt(rand.nextInt(rangeY - (rangeY / 16)) + (rangeY / 16)); @@ -568,7 +623,9 @@ public class ChunkDecoratorOverworld int i25 = z + rand.nextInt(16) + 8; (new WorldFeatureLiquid(Blocks.FLUID_LAVA_FLOWING.id())).place(this.world, rand, i22, l23, i25); } + } catch (final Throwable t) { LOGGER.error("Decoration step 'liquids' failed at chunk ({}, {}); continuing.", chunkX, chunkZ, t); } + try { int numPebbles = 0; if (biome == Biomes.OVERWORLD_FOREST) { numPebbles = 2; @@ -598,31 +655,104 @@ public class ChunkDecoratorOverworld final int zz = z + rand.nextInt(16) + 8; new WorldFeaturePebbles(Blocks.OVERLAY_PEBBLES, 16, true).place(this.world, rand, xx, yy, zz); } + } catch (final Throwable t) { LOGGER.error("Decoration step 'pebbles' failed at chunk ({}, {}); continuing.", chunkX, chunkZ, t); } - int oceanY = this.world.getWorldType().getOceanY(); - for (int dx = x + 8; dx < x + 8 + 16; dx++) { - for (int dz = z + 8; dz < z + 8 + 16; dz++) { - int dy = this.world.getHeightValue(dx, dz); - Biome localBiome = this.world.getBlockBiome(dx, dy, dz); - - if ((localBiome.hasTag(BiomeTags.HAS_SURFACE_SNOW) || this.world.getWorldType().hasTag(WorldTypeTags.ENDLESS_SNOW)) && - dy > 0 && dy < this.world.getHeightBlocks()) - { - if (this.world.isAirBlock(dx, dy, dz) && this.world.getBlockMaterial(dx, dy - 1, dz).blocksMotion()) { - this.world.setBlockWithNotify(dx, dy, dz, Blocks.LAYER_SNOW.id()); + // Snow/ice pass + final int oceanY = this.world.getWorldType().getOceanY(); + try { + for (int dx = x + 8; dx < x + 8 + 16; dx++) { + for (int dz = z + 8; dz < z + 8 + 16; dz++) { + try { + applySnowAndIceForColumn(dx, dz, oceanY); + } catch (final Throwable colT) { + LOGGER.error("Snow/ice column ({}, {}) failed at chunk ({}, {}); continuing.", dx, dz, chunkX, chunkZ, colT); } } - if ((localBiome.hasTag(BiomeTags.HAS_SURFACE_ICE) || this.world.getWorldType().hasTag(WorldTypeTags.ENDLESS_SNOW)) && - (this.world.getBlockId(dx, oceanY - 1, dz) == Blocks.FLUID_WATER_STILL.id() || this.world.getBlockId(dx, oceanY - 1, dz) == Blocks.FLUID_WATER_FLOWING.id()) - ) { - this.world.setBlockWithNotify(dx, oceanY - 1, dz, Blocks.ICE.id()); - } + } + } catch (final Throwable t) { LOGGER.error("Decoration step 'snow_ice' failed at chunk ({}, {}); continuing.", chunkX, chunkZ, t); } + // Spillover re-snow pass + try { + for (int dx = x; dx < x + 32; dx++) { + for (int dz = z; dz < z + 32; dz++) { + final int ownerChunkX = (dx - 8) >> 4; + final int ownerChunkZ = (dz - 8) >> 4; + if (ownerChunkX == chunkX && ownerChunkZ == chunkZ) { continue; } + if (!this.world.isChunkLoaded(ownerChunkX, ownerChunkZ)) { continue; } + final Chunk owner = this.world.getChunkFromChunkCoords(ownerChunkX, ownerChunkZ); + if (!owner.isTerrainPopulated) { continue; } + final int physicalChunkX = dx >> 4; + final int physicalChunkZ = dz >> 4; + if (!this.world.isChunkLoaded(physicalChunkX, physicalChunkZ)) { continue; } + try { + applySnowAndIceForColumn(dx, dz, oceanY); + } catch (final Throwable colT) { + LOGGER.error("Spillover snow/ice column ({}, {}) failed at chunk ({}, {}); continuing.", dx, dz, chunkX, chunkZ, colT); + } + } } + } catch (final Throwable t) { LOGGER.error("Decoration step 'snow_ice_spillover' failed at chunk ({}, {}); continuing.", chunkX, chunkZ, t); } + } finally { + BlockLogicFallingBlock.fallInstantly = false; + this.world.scheduledUpdatesAreImmediate = false; } + } - BlockLogicFallingBlock.fallInstantly = false; - this.world.scheduledUpdatesAreImmediate = false; + /** + * Places snow on the topmost surface of the column AND on the ground beneath any + * tree canopy in the column, plus ice on top of water at the ocean surface. + * Existing snow is not duplicated. Safe to call multiple times for the same column + */ + private void applySnowAndIceForColumn(final int dx, final int dz, final int oceanY) { + final int dy = this.world.getHeightValue(dx, dz); + final Biome localBiome = this.world.getBlockBiome(dx, dy, dz); + + final boolean wantsSnow = localBiome.hasTag(BiomeTags.HAS_SURFACE_SNOW) || this.world.getWorldType().hasTag(WorldTypeTags.ENDLESS_SNOW); + if (wantsSnow && dy > 0 && dy < this.world.getHeightBlocks()) { + if (this.world.isAirBlock(dx, dy, dz) && this.world.getBlockMaterial(dx, dy - 1, dz).blocksMotion()) { + this.world.setBlockWithNotify(dx, dy, dz, Blocks.LAYER_SNOW.id()); + } + final int minScanY = Math.max(1, dy - 32); + boolean passedTree = false; + for (int scanY = dy - 1; scanY > minScanY; scanY--) { + final int hereId = this.world.getBlockId(dx, scanY, dz); + final net.minecraft.core.block.Block here = hereId > 0 ? Blocks.blocksList[hereId] : null; + if (here != null && (here.getLogic() instanceof BlockLogicLeavesBase || here.getMaterial() == Materials.WOOD)) { + passedTree = true; + continue; + } + if (here == Blocks.LAYER_SNOW) { + continue; + } + if (hereId == 0) { + if (!passedTree) { continue; } + final int belowId = this.world.getBlockId(dx, scanY - 1, dz); + if (belowId == 0) { continue; } + final net.minecraft.core.block.Block below = Blocks.blocksList[belowId]; + if (below == null) { continue; } + if (below == Blocks.LAYER_SNOW) { continue; } + if (below.getLogic() instanceof BlockLogicLeavesBase) { + this.world.setBlockWithNotify(dx, scanY, dz, Blocks.LAYER_SNOW.id()); + continue; + } + if (below.getMaterial() == Materials.WOOD) { continue; } + if (below.getMaterial().blocksMotion()) { + this.world.setBlockWithNotify(dx, scanY, dz, Blocks.LAYER_SNOW.id()); + break; + } + continue; + } + break; + } + } + + final boolean wantsIce = localBiome.hasTag(BiomeTags.HAS_SURFACE_ICE) || this.world.getWorldType().hasTag(WorldTypeTags.ENDLESS_SNOW); + if (wantsIce) { + final int oceanFluidId = this.world.getBlockId(dx, oceanY - 1, dz); + if (oceanFluidId == Blocks.FLUID_WATER_STILL.id() || oceanFluidId == Blocks.FLUID_WATER_FLOWING.id()) { + this.world.setBlockWithNotify(dx, oceanY - 1, dz, Blocks.ICE.id()); + } + } } } diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkDecoratorOverworldB173.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkDecoratorOverworldB173.java index f71d51782..d518830a0 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkDecoratorOverworldB173.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkDecoratorOverworldB173.java @@ -1,7 +1,10 @@ package net.minecraft.core.world.generate.chunk.perlin.overworld.b173; +import com.mojang.logging.LogUtils; import net.minecraft.core.block.BlockLogicFallingBlock; +import net.minecraft.core.block.BlockLogicLeavesBase; import net.minecraft.core.block.Blocks; +import net.minecraft.core.block.material.Materials; import net.minecraft.core.world.World; import net.minecraft.core.world.biome.Biome; import net.minecraft.core.world.biome.BiomeTags; @@ -11,12 +14,16 @@ import net.minecraft.core.world.generate.chunk.ChunkDecorator; import net.minecraft.core.world.generate.feature.*; import net.minecraft.core.world.noise.FractalNoise2D; import net.minecraft.core.world.noise.ImprovedPerlinNoise; +import net.minecraft.core.world.pos.TilePos; import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; import java.util.Random; public class ChunkDecoratorOverworldB173 implements ChunkDecorator { + private static final @NotNull Logger LOGGER = LogUtils.getLogger(); + private final @NotNull World world; private final @NotNull FractalNoise2D forestNoise; @@ -34,6 +41,8 @@ public class ChunkDecoratorOverworldB173 final int x = chunk.pos.x; final int z = chunk.pos.z; + try { + final int minY = this.world.getWorldType().getMinY(world); final int maxY = this.world.getWorldType().getMaxY(world); final int rangeY = (maxY + 1) - minY; @@ -50,6 +59,7 @@ public class ChunkDecoratorOverworldB173 rand.setSeed(rx * x + rz * z ^ this.world.getRandomSeed()); + try { if (rand.nextInt(4) == 0) { final int fx = wx + rand.nextInt(16) + 8; final int fy = rand.nextInt(rangeY); @@ -65,7 +75,9 @@ public class ChunkDecoratorOverworldB173 new WorldFeatureLake(Blocks.FLUID_LAVA_STILL.id()).place(this.world, rand, fx, fy, fz); } } + } catch (final Throwable t) { LOGGER.error("Decoration step 'lakes' failed at chunk ({}, {}); continuing.", x, z, t); } + try { for (int i = 0; i < 8; i++) { final int fx = wx + rand.nextInt(16) + 8; final int fy = rand.nextInt(rangeY); @@ -84,58 +96,68 @@ public class ChunkDecoratorOverworldB173 final int fx = wx + rand.nextInt(16); final int fy = rand.nextInt(rangeY); final int fz = wz + rand.nextInt(16); - new WorldFeatureOre(Blocks.DIRT.id(), 32).place(this.world, rand, fx, fy, fz); + final TilePos queryPos = new TilePos(fx, fy, fz); + new WorldFeatureOre(Blocks.DIRT.id(), 32).place(this.world, rand, queryPos); } for (int i = 0; i < 10; i++) { final int fx = wx + rand.nextInt(16); final int fy = rand.nextInt(rangeY); final int fz = wz + rand.nextInt(16); - new WorldFeatureOre(Blocks.GRAVEL.id(), 32).place(this.world, rand, fx, fy, fz); + final TilePos queryPos = new TilePos(fx, fy, fz); + new WorldFeatureOre(Blocks.GRAVEL.id(), 32).place(this.world, rand, queryPos); } for (int i = 0; i < 20; i++) { final int fx = wx + rand.nextInt(16); final int fy = rand.nextInt(rangeY); final int fz = wz + rand.nextInt(16); - new WorldFeatureOre(Blocks.ORE_COAL_STONE.id(), 16).place(this.world, rand, fx, fy, fz); + final TilePos queryPos = new TilePos(fx, fy, fz); + new WorldFeatureOre(Blocks.ORE_COAL_STONE.id(), 16).place(this.world, rand, queryPos); } for (int i = 0; i < 20; i++) { final int fx = wx + rand.nextInt(16); final int fy = rand.nextInt(rangeY / 2); final int fz = wz + rand.nextInt(16); - new WorldFeatureOre(Blocks.ORE_IRON_STONE.id(), 8).place(this.world, rand, fx, fy, fz); + final TilePos queryPos = new TilePos(fx, fy, fz); + new WorldFeatureOre(Blocks.ORE_IRON_STONE.id(), 8).place(this.world, rand, queryPos); } for (int i = 0; i < 2; i++) { final int fx = wx + rand.nextInt(16); final int fy = rand.nextInt(rangeY / 4); final int fz = wz + rand.nextInt(16); - new WorldFeatureOre(Blocks.ORE_GOLD_STONE.id(), 8).place(this.world, rand, fx, fy, fz); + final TilePos queryPos = new TilePos(fx, fy, fz); + new WorldFeatureOre(Blocks.ORE_GOLD_STONE.id(), 8).place(this.world, rand, queryPos); } for (int i = 0; i < 8; i++) { final int fx = wx + rand.nextInt(16); final int fy = rand.nextInt(rangeY / 8); final int fz = wz + rand.nextInt(16); - new WorldFeatureOre(Blocks.ORE_REDSTONE_STONE.id(), 7).place(this.world, rand, fx, fy, fz); + final TilePos queryPos = new TilePos(fx, fy, fz); + new WorldFeatureOre(Blocks.ORE_REDSTONE_STONE.id(), 7).place(this.world, rand, queryPos); } for (int i = 0; i < 1; i++) { final int fx = wx + rand.nextInt(16); final int fy = rand.nextInt(rangeY / 16); final int fz = wz + rand.nextInt(16); - new WorldFeatureOre(Blocks.ORE_DIAMOND_STONE.id(), 7).place(this.world, rand, fx, fy, fz); + final TilePos queryPos = new TilePos(fx, fy, fz); + new WorldFeatureOre(Blocks.ORE_DIAMOND_STONE.id(), 7).place(this.world, rand, queryPos); } for (int i = 0; i < 1; i++) { final int fx = wx + rand.nextInt(16); final int fy = rand.nextInt(rangeY / 16) + rand.nextInt(rangeY / 16); final int fz = wz + rand.nextInt(16); - new WorldFeatureOre(Blocks.ORE_LAPIS_STONE.id(), 6).place(this.world, rand, fx, fy, fz); + final TilePos queryPos = new TilePos(fx, fy, fz); + new WorldFeatureOre(Blocks.ORE_LAPIS_STONE.id(), 6).place(this.world, rand, queryPos); } + } catch (final Throwable t) { LOGGER.error("Decoration step 'ores_dungeons_clay' failed at chunk ({}, {}); continuing.", x, z, t); } + try { final double forestNoiseScale = 0.5; final int forestNoiseValue = (int) ((this.forestNoise.getValue(wx * forestNoiseScale, wz * forestNoiseScale) / 8.0 + rand.nextDouble() * 4.0 + 4.0) / 3.0); int numTrees = 0; @@ -167,13 +189,19 @@ public class ChunkDecoratorOverworldB173 } for (int i = 0; i < numTrees; i++) { - final int fx = wx + rand.nextInt(16) + 8; - final int fz = wz + rand.nextInt(16) + 8; - final @NotNull WorldFeature feature = biome.getTreeFeature(rand); - feature.init(1.0, 1.0, 1.0); - biome.getTreeFeature(rand).place(this.world, rand, fx, this.world.getHeightValue(fx, fz), fz); + try { + final int fx = wx + rand.nextInt(16) + 8; + final int fz = wz + rand.nextInt(16) + 8; + final @NotNull WorldFeature feature = biome.getTreeFeature(rand); + feature.init(1.0, 1.0, 1.0); + biome.getTreeFeature(rand).place(this.world, rand, fx, this.world.getHeightValue(fx, fz), fz); + } catch (final Throwable treeT) { + LOGGER.error("Tree placement #{} failed at chunk ({}, {}); continuing.", i, x, z, treeT); + } } + } catch (final Throwable t) { LOGGER.error("Decoration step 'trees' failed at chunk ({}, {}); continuing.", x, z, t); } + try { int numYellowFlowers = 0; if (biome == Biomes.OVERWORLD_LEGACY_FOREST) { numYellowFlowers += 2; @@ -296,25 +324,67 @@ public class ChunkDecoratorOverworldB173 final int fz = wz + rand.nextInt(16) + 8; new WorldFeatureLiquid(Blocks.FLUID_LAVA_FLOWING.id()).place(this.world, rand, fx, fy, fz); } + } catch (final Throwable t) { LOGGER.error("Decoration step 'plants_liquids' failed at chunk ({}, {}); continuing.", x, z, t); } final int oceanY = this.world.getWorldType().getOceanY(); - for (int xx = x + 8; xx < x + 8 + 16; xx++) { - for (int zz = z + 8; zz < z + 8 + 16; zz++) { - int yy = this.world.getHeightValue(xx, zz); - final Biome localBiome = this.world.getBlockBiome(xx, yy, zz); - - if (localBiome.hasTag(BiomeTags.HAS_SURFACE_SNOW) && yy > 0 && yy < this.world.getHeightBlocks()) { - if (this.world.isAirBlock(xx, yy, zz) && this.world.getBlockMaterial(xx, yy - 1, zz).blocksMotion()) { - this.world.setBlockWithNotify(xx, yy, zz, Blocks.LAYER_SNOW.id()); + try { + for (int xx = wx + 8; xx < wx + 8 + 16; xx++) { + for (int zz = wz + 8; zz < wz + 8 + 16; zz++) { + try { + applySnowAndIceForColumn(xx, zz, oceanY); + } catch (final Throwable colT) { + LOGGER.error("Snow/ice column ({}, {}) failed at chunk ({}, {}); continuing.", xx, zz, x, z, colT); } } - if (localBiome.hasTag(BiomeTags.HAS_SURFACE_ICE) && (this.world.getBlockId(xx, oceanY - 1, zz) == Blocks.FLUID_WATER_STILL.id() || this.world.getBlockId(xx, oceanY - 1, zz) == Blocks.FLUID_WATER_FLOWING.id())) { - this.world.setBlockWithNotify(xx, oceanY - 1, zz, Blocks.ICE.id()); + } + } catch (final Throwable t) { LOGGER.error("Decoration step 'snow_ice' failed at chunk ({}, {}); continuing.", x, z, t); } + + //resnow pass + try { + for (int dx = wx; dx < wx + 32; dx++) { + for (int dz = wz; dz < wz + 32; dz++) { + final int ownerChunkX = (dx - 8) >> 4; + final int ownerChunkZ = (dz - 8) >> 4; + if (ownerChunkX == x && ownerChunkZ == z) { continue; } + if (!this.world.isChunkLoaded(ownerChunkX, ownerChunkZ)) { continue; } + final Chunk owner = this.world.getChunkFromChunkCoords(ownerChunkX, ownerChunkZ); + if (!owner.isTerrainPopulated) { continue; } + final int physicalChunkX = dx >> 4; + final int physicalChunkZ = dz >> 4; + if (!this.world.isChunkLoaded(physicalChunkX, physicalChunkZ)) { continue; } + try { + applySnowAndIceForColumn(dx, dz, oceanY); + } catch (final Throwable colT) { + LOGGER.error("Spillover snow/ice column ({}, {}) failed at chunk ({}, {}); continuing.", dx, dz, x, z, colT); + } } } + } catch (final Throwable t) { LOGGER.error("Decoration step 'snow_ice_spillover' failed at chunk ({}, {}); continuing.", x, z, t); } + + } finally { + BlockLogicFallingBlock.fallInstantly = false; + this.world.scheduledUpdatesAreImmediate = false; } + } + + /** + * Places snow on the topmost surface of the column, plus ice on top of water at the ocean surface. + */ + private void applySnowAndIceForColumn(final int xx, final int zz, final int oceanY) { + final int yy = this.world.getHeightValue(xx, zz); + final Biome localBiome = this.world.getBlockBiome(xx, yy, zz); - BlockLogicFallingBlock.fallInstantly = false; - this.world.scheduledUpdatesAreImmediate = false; + if (localBiome.hasTag(BiomeTags.HAS_SURFACE_SNOW) && yy > 0 && yy < this.world.getHeightBlocks()) { + if (this.world.isAirBlock(xx, yy, zz) && this.world.getBlockMaterial(xx, yy - 1, zz).blocksMotion()) { + this.world.setBlockWithNotify(xx, yy, zz, Blocks.LAYER_SNOW.id()); + } + } + + if (localBiome.hasTag(BiomeTags.HAS_SURFACE_ICE)) { + final int oceanFluidId = this.world.getBlockId(xx, oceanY - 1, zz); + if (oceanFluidId == Blocks.FLUID_WATER_STILL.id() || oceanFluidId == Blocks.FLUID_WATER_FLOWING.id()) { + this.world.setBlockWithNotify(xx, oceanY - 1, zz, Blocks.ICE.id()); + } + } } } diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java index e53cd9eee..5a6d86159 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java @@ -15,6 +15,7 @@ import net.minecraft.core.world.generate.feature.tree.WorldFeatureTree; import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeFancy; import net.minecraft.core.world.noise.FractalNoise2D; import net.minecraft.core.world.noise.ImprovedPerlinNoise; +import net.minecraft.core.world.pos.TilePos; import org.jetbrains.annotations.NotNull; public class ChunkDecoratorOverworldHell @@ -107,7 +108,8 @@ public class ChunkDecoratorOverworldHell final int xx = worldX + rand.nextInt(16); final int yy = minY + rand.nextInt(rangeY); final int zz = worldZ + rand.nextInt(16); - (new WorldFeatureOre(Blocks.DIRT.id(), 32)).place(world, rand, xx, yy, zz); + TilePos pos = new TilePos(xx, yy, zz); + (new WorldFeatureOre(Blocks.DIRT.id(), 32)).place(world, rand, pos); } }); @@ -116,7 +118,8 @@ public class ChunkDecoratorOverworldHell final int xx = worldX + rand.nextInt(16); final int yy = minY + rand.nextInt(rangeY); final int zz = worldZ + rand.nextInt(16); - (new WorldFeatureOre(Blocks.GRAVEL.id(), 32)).place(world, rand, xx, yy, zz); + TilePos pos = new TilePos(xx, yy, zz); + (new WorldFeatureOre(Blocks.GRAVEL.id(), 32)).place(world, rand, pos); } }); @@ -125,7 +128,8 @@ public class ChunkDecoratorOverworldHell final int xx = worldX + rand.nextInt(16); final int yy = minY + rand.nextInt(rangeY); final int zz = worldZ + rand.nextInt(16); - (new WorldFeatureOre(BlockLogicOreCoal.variantMap, 16)).place(world, rand, xx, yy, zz); + TilePos pos = new TilePos(xx, yy, zz); + (new WorldFeatureOre(BlockLogicOreCoal.variantMap, 16)).place(world, rand, pos); } }); @@ -134,7 +138,8 @@ public class ChunkDecoratorOverworldHell final int xx = worldX + rand.nextInt(16); final int yy = minY + rand.nextInt(rangeY / 2); final int zz = worldZ + rand.nextInt(16); - (new WorldFeatureOre(BlockLogicOreIron.variantMap, 8)).place(world, rand, xx, yy, zz); + TilePos pos = new TilePos(xx, yy, zz); + (new WorldFeatureOre(BlockLogicOreIron.variantMap, 8)).place(world, rand, pos); } }); @@ -143,7 +148,8 @@ public class ChunkDecoratorOverworldHell final int xx = worldX + rand.nextInt(16); final int yy = minY + rand.nextInt(rangeY / 4); final int zz = worldZ + rand.nextInt(16); - (new WorldFeatureOre(BlockLogicOreGold.variantMap, 8)).place(world, rand, xx, yy, zz); + TilePos pos = new TilePos(xx, yy, zz); + (new WorldFeatureOre(BlockLogicOreGold.variantMap, 8)).place(world, rand, pos); } }); @@ -152,7 +158,8 @@ public class ChunkDecoratorOverworldHell final int xx = worldX + rand.nextInt(16); final int yy = minY + rand.nextInt(rangeY / 8); final int zz = worldZ + rand.nextInt(16); - (new WorldFeatureOre(BlockLogicOreRedstone.variantMap, 7)).place(world, rand, xx, yy, zz); + TilePos pos = new TilePos(xx, yy, zz); + (new WorldFeatureOre(BlockLogicOreRedstone.variantMap, 7)).place(world, rand, pos); } }); @@ -161,7 +168,8 @@ public class ChunkDecoratorOverworldHell final int xx = worldX + rand.nextInt(16); final int yy = minY + rand.nextInt(rangeY / 8); final int zz = worldZ + rand.nextInt(16); - (new WorldFeatureOre(BlockLogicOreDiamond.variantMap, 7)).place(world, rand, xx, yy, zz); + TilePos pos = new TilePos(xx, yy, zz); + (new WorldFeatureOre(BlockLogicOreDiamond.variantMap, 7)).place(world, rand, pos); } }); @@ -170,7 +178,8 @@ public class ChunkDecoratorOverworldHell final int xx = worldX + rand.nextInt(16); final int yy = minY + rand.nextInt(rangeY / 8) + rand.nextInt(rangeY / 8); final int zz = worldZ + rand.nextInt(16); - (new WorldFeatureOre(BlockLogicOreLapis.variantMap, 6)).place(world, rand, xx, yy, zz); + TilePos pos = new TilePos(xx, yy, zz); + (new WorldFeatureOre(BlockLogicOreLapis.variantMap, 6)).place(world, rand, pos); } }); diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkDecoratorOverworldRetro.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkDecoratorOverworldRetro.java index adf3fd0ff..b70de55bf 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkDecoratorOverworldRetro.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkDecoratorOverworldRetro.java @@ -1,5 +1,7 @@ package net.minecraft.core.world.generate.chunk.perlin.overworld.retro; +import com.mojang.logging.LogUtils; +import net.minecraft.core.block.BlockLogicLeavesBase; import net.minecraft.core.block.BlockLogicOreCoal; import net.minecraft.core.block.BlockLogicOreDiamond; import net.minecraft.core.block.BlockLogicOreGold; @@ -16,12 +18,16 @@ import net.minecraft.core.world.generate.feature.tree.WorldFeatureTree; import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeFancy; import net.minecraft.core.world.noise.FractalNoise2D; import net.minecraft.core.world.noise.ImprovedPerlinNoise; +import net.minecraft.core.world.pos.TilePos; import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; import java.util.Random; public class ChunkDecoratorOverworldRetro implements ChunkDecorator { + private static final @NotNull Logger LOGGER = LogUtils.getLogger(); + private final @NotNull World world; private final @NotNull FractalNoise2D treeDensityNoise; @@ -38,20 +44,25 @@ public class ChunkDecoratorOverworldRetro @Override public void decorate(@NotNull Chunk chunk) { this.world.scheduledUpdatesAreImmediate = true; - int chunkX = chunk.pos.x; - int chunkZ = chunk.pos.z; + BlockLogicFallingBlock.fallInstantly = true; + + final int chunkX = chunk.pos.x; + final int chunkZ = chunk.pos.z; + + try { int minY = this.world.getWorldType().getMinY(world); int maxY = this.world.getWorldType().getMaxY(world); int rangeY = (maxY + 1) - minY; - BlockLogicFallingBlock.fallInstantly = true; int k = chunkX * 16; int l = chunkZ * 16; Random rand = new Random(this.world.getRandomSeed()); long l1 = (rand.nextLong() / 2L) * 2L + 1L; long l2 = (rand.nextLong() / 2L) * 2L + 1L; rand.setSeed((long) chunkX * l1 + (long) chunkZ * l2 ^ this.world.getRandomSeed()); + + try { for (int i1 = 0; i1 < 8; i1++) { int i4 = k + rand.nextInt(16) + 8; int j6 = minY + rand.nextInt(rangeY); @@ -70,51 +81,60 @@ public class ChunkDecoratorOverworldRetro int k4 = k + rand.nextInt(16); int l6 = minY + rand.nextInt(rangeY); int k11 = l + rand.nextInt(16); - (new WorldFeatureOre(Blocks.DIRT.id(), 32)).place(this.world, rand, k4, l6, k11); + TilePos queryPos = new TilePos(k4, l6, k11); + (new WorldFeatureOre(Blocks.DIRT.id(), 32)).place(this.world, rand, queryPos); } for (int i2 = 0; i2 < 10; i2++) { int l4 = k + rand.nextInt(16); int i7 = minY + rand.nextInt(rangeY); int l11 = l + rand.nextInt(16); - (new WorldFeatureOre(Blocks.GRAVEL.id(), 32)).place(this.world, rand, l4, i7, l11); + TilePos queryPos = new TilePos(l4, i7, l11); + (new WorldFeatureOre(Blocks.GRAVEL.id(), 32)).place(this.world, rand, queryPos); } for (int j2 = 0; j2 < 20; j2++) { int i5 = k + rand.nextInt(16); int j7 = minY + rand.nextInt(rangeY); int i12 = l + rand.nextInt(16); - (new WorldFeatureOre(BlockLogicOreCoal.variantMap, 16)).place(this.world, rand, i5, j7, i12); + TilePos queryPos = new TilePos(i5, j7, i12); + (new WorldFeatureOre(BlockLogicOreCoal.variantMap, 16)).place(this.world, rand, queryPos); } for (int k2 = 0; k2 < 20; k2++) { int j5 = k + rand.nextInt(16); int k7 = minY + rand.nextInt(rangeY / 2); int j12 = l + rand.nextInt(16); - (new WorldFeatureOre(BlockLogicOreIron.variantMap, 8)).place(this.world, rand, j5, k7, j12); + TilePos queryPos = new TilePos(j5, k7, j12); + (new WorldFeatureOre(BlockLogicOreIron.variantMap, 8)).place(this.world, rand, queryPos); } for (int i3 = 0; i3 < 2; i3++) { int k5 = k + rand.nextInt(16); int l7 = minY + rand.nextInt(rangeY / 4); int k12 = l + rand.nextInt(16); - (new WorldFeatureOre(BlockLogicOreGold.variantMap, 8)).place(this.world, rand, k5, l7, k12); + TilePos queryPos = new TilePos(k5, l7, k12); + (new WorldFeatureOre(BlockLogicOreGold.variantMap, 8)).place(this.world, rand, queryPos); } for (int j3 = 0; j3 < 8; j3++) { int l5 = k + rand.nextInt(16); int i8 = minY + rand.nextInt(rangeY / 8); int l12 = l + rand.nextInt(16); - (new WorldFeatureOre(BlockLogicOreRedstone.variantMap, 7)).place(this.world, rand, l5, i8, l12); + TilePos queryPos = new TilePos(l5, i8, l12); + (new WorldFeatureOre(BlockLogicOreRedstone.variantMap, 7)).place(this.world, rand, queryPos); } for (int k3 = 0; k3 < 1; k3++) { int i6 = k + rand.nextInt(16); int j8 = minY + rand.nextInt(rangeY / 8); int i13 = l + rand.nextInt(16); - (new WorldFeatureOre(BlockLogicOreDiamond.variantMap, 7)).place(this.world, rand, i6, j8, i13); + TilePos queryPos = new TilePos(i6, j8, i13); + (new WorldFeatureOre(BlockLogicOreDiamond.variantMap, 7)).place(this.world, rand, queryPos); } + } catch (final Throwable t) { LOGGER.error("Decoration step 'dungeons_clay_ores' failed at chunk ({}, {}); continuing.", chunkX, chunkZ, t); } + try { double d = 0.5D; int l3 = (int) ((this.treeDensityNoise.getValue((double) k * d, (double) l * d) / 8D + rand.nextDouble() * 4D + 4D) / 3D); if (l3 < 0) { @@ -128,12 +148,18 @@ public class ChunkDecoratorOverworldRetro tree = new WorldFeatureTreeFancy(Blocks.LEAVES_OAK_RETRO.id(), Blocks.LOG_OAK.id()); } for (int k8 = 0; k8 < l3; k8++) { - int j13 = k + rand.nextInt(16) + 8; - int l15 = l + rand.nextInt(16) + 8; - tree.init(1.0D, 1.0D, 1.0D); - tree.place(this.world, rand, j13, this.world.getHeightValue(j13, l15), l15); + try { + int j13 = k + rand.nextInt(16) + 8; + int l15 = l + rand.nextInt(16) + 8; + tree.init(1.0D, 1.0D, 1.0D); + tree.place(this.world, rand, j13, this.world.getHeightValue(j13, l15), l15); + } catch (final Throwable treeT) { + LOGGER.error("Tree placement #{} failed at chunk ({}, {}); continuing.", k8, chunkX, chunkZ, treeT); + } } + } catch (final Throwable t) { LOGGER.error("Decoration step 'trees' failed at chunk ({}, {}); continuing.", chunkX, chunkZ, t); } + try { for (int l8 = 0; l8 < 2; l8++) { int k13 = k + rand.nextInt(16) + 8; int i16 = minY + rand.nextInt(rangeY); @@ -172,7 +198,9 @@ public class ChunkDecoratorOverworldRetro int l18 = l + rand.nextInt(16) + 8; (new WorldFeatureCactus()).place(this.world, rand, l14, j17, l18); } + } catch (final Throwable t) { LOGGER.error("Decoration step 'flowers_cactus' failed at chunk ({}, {}); continuing.", chunkX, chunkZ, t); } + try { for (int j10 = 0; j10 < 50; j10++) { int i15 = k + rand.nextInt(16) + 8; int k17 = minY + rand.nextInt(rand.nextInt(rangeY - 8) + 8); @@ -186,21 +214,65 @@ public class ChunkDecoratorOverworldRetro int j19 = l + rand.nextInt(16) + 8; (new WorldFeatureLiquid(Blocks.FLUID_LAVA_FLOWING.id())).place(this.world, rand, j15, l17, j19); } + } catch (final Throwable t) { LOGGER.error("Decoration step 'liquids' failed at chunk ({}, {}); continuing.", chunkX, chunkZ, t); } - for (int l10 = k + 8; l10 < k + 8 + 16; l10++) { - for (int k15 = l + 8; k15 < l + 8 + 16; k15++) { - int i18 = this.world.findTopSolidBlock(l10, k15); - if (this.snowCovered && i18 > minY && i18 <= maxY && this.world.getBlockId(l10, i18, k15) == 0 && this.world.getBlockMaterial(l10, i18 - 1, k15).blocksMotion() && this.world.getBlockMaterial(l10, i18 - 1, k15) != Materials.ICE) { - this.world.setBlockWithNotify(l10, i18, k15, Blocks.LAYER_SNOW.id()); + // First snow/ice pass + try { + for (int l10 = k + 8; l10 < k + 8 + 16; l10++) { + for (int k15 = l + 8; k15 < l + 8 + 16; k15++) { + try { + applySnowAndIceForColumn(l10, k15, minY, maxY); + } catch (final Throwable colT) { + LOGGER.error("Snow/ice column ({}, {}) failed at chunk ({}, {}); continuing.", l10, k15, chunkX, chunkZ, colT); + } } - if (this.snowCovered && this.world.getBlockMaterial(l10, this.world.getWorldType().getOceanY() - 1, k15) == Materials.WATER) { - this.world.setBlockWithNotify(l10, this.world.getWorldType().getOceanY() - 1, k15, Blocks.ICE.id()); + } + } catch (final Throwable t) { LOGGER.error("Decoration step 'snow_ice' failed at chunk ({}, {}); continuing.", chunkX, chunkZ, t); } + + // Snow/ice repass + try { + for (int dx = k; dx < k + 32; dx++) { + for (int dz = l; dz < l + 32; dz++) { + final int ownerChunkX = (dx - 8) >> 4; + final int ownerChunkZ = (dz - 8) >> 4; + if (ownerChunkX == chunkX && ownerChunkZ == chunkZ) { continue; } + if (!this.world.isChunkLoaded(ownerChunkX, ownerChunkZ)) { continue; } + final Chunk owner = this.world.getChunkFromChunkCoords(ownerChunkX, ownerChunkZ); + if (!owner.isTerrainPopulated) { continue; } + final int physicalChunkX = dx >> 4; + final int physicalChunkZ = dz >> 4; + if (!this.world.isChunkLoaded(physicalChunkX, physicalChunkZ)) { continue; } + try { + applySnowAndIceForColumn(dx, dz, minY, maxY); + } catch (final Throwable colT) { + LOGGER.error("Spillover snow/ice column ({}, {}) failed at chunk ({}, {}); continuing.", dx, dz, chunkX, chunkZ, colT); + } } } + } catch (final Throwable t) { LOGGER.error("Decoration step 'snow_ice_spillover' failed at chunk ({}, {}); continuing.", chunkX, chunkZ, t); } + } finally { + BlockLogicFallingBlock.fallInstantly = false; + this.world.scheduledUpdatesAreImmediate = false; } + } + + /** + * Places snow on the topmost surface of the column, plus ice on top of water at the ocean surface. + */ + private void applySnowAndIceForColumn(final int dx, final int dz, final int minY, final int maxY) { + if (!this.snowCovered) { return; } + + final int topY = this.world.findTopSolidBlock(dx, dz); - BlockLogicFallingBlock.fallInstantly = false; - this.world.scheduledUpdatesAreImmediate = false; + if (topY > minY && topY <= maxY && this.world.getBlockId(dx, topY, dz) == 0 + && this.world.getBlockMaterial(dx, topY - 1, dz).blocksMotion() + && this.world.getBlockMaterial(dx, topY - 1, dz) != Materials.ICE) { + this.world.setBlockWithNotify(dx, topY, dz, Blocks.LAYER_SNOW.id()); + } + + if (this.world.getBlockMaterial(dx, this.world.getWorldType().getOceanY() - 1, dz) == Materials.WATER) { + this.world.setBlockWithNotify(dx, this.world.getWorldType().getOceanY() - 1, dz, Blocks.ICE.id()); + } } } diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureBoulder.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureBoulder.java new file mode 100644 index 000000000..48bb52c9a --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureBoulder.java @@ -0,0 +1,104 @@ +package net.minecraft.core.world.generate.feature; + +import net.minecraft.core.block.Block; +import net.minecraft.core.block.tag.BlockTags; +import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; +import org.joml.Vector2i; + +import java.util.Random; + +public class WorldFeatureBoulder implements WorldFeatureInterface { + final double[][] RADIUS_MAPS = new double[][]{{(double)1.5F, (double)1.5F, (double)1.0F}, {(double)1.0F, (double)1.5F, (double)1.0F}}; + private final Block boulderBlock; + private final Block extraBlock; + + public WorldFeatureBoulder(Block boulderBlock, Block extraBlock) { + this.boulderBlock = boulderBlock; + this.extraBlock = extraBlock; + } + + private Block getBlockAt(Vector2i centerXZ, int x, int z) { + return boulderBlock; + } + + private void plotBlocks(World world, @NotNull Vector2i centerXZ, TilePos queryPos, int x, int y, int z) { + for(int xx = centerXZ.x - x; xx <= centerXZ.x + x; ++xx) { + Block block = this.getBlockAt(centerXZ, xx, centerXZ.y + z); + world.setBlockType(queryPos.set(xx, y, centerXZ.y + z), block); + world.setBlockType(queryPos.set(xx, y, centerXZ.y - z), block); + } + + for(int xx = centerXZ.x - z; xx <= centerXZ.x + z; ++xx) { + Block block = this.getBlockAt(centerXZ, xx, centerXZ.y + x); + world.setBlockType(queryPos.set(xx, y, centerXZ.y + x), block); + world.setBlockType(queryPos.set(xx, y, centerXZ.y - x), block); + } + } + + private void generateRadius(World world, Vector2i centerXZ, TilePos queryPos, double r, int y) { + int x = 0; + int z = (int)r; + double d = (double)3.0F - (double)2.0F * r; + this.plotBlocks(world, centerXZ, queryPos, x, y, z); + + for(; z > x; this.plotBlocks(world, centerXZ, queryPos, x, y, z)) { + ++x; + if (d > (double)0.0F) { + --z; + d = d + (double)(4 * (x - z)) + (double)10.0F; + } else { + d = d + (double)(4 * x) + (double)6.0F; + } + } + } + + private boolean hasSpace(World world, int xc, int y, int zc) { + TilePos queryPos = new TilePos(); + + for(queryPos.y = y - 2; queryPos.y < y + 2; ++queryPos.y) { + for(queryPos.x = xc - 2; queryPos.x < xc + 2; ++queryPos.x) { + for(queryPos.z = zc - 2; queryPos.z < zc + 2; ++queryPos.z) { + if (!world.isAirBlock(queryPos) && !world.getBlockType(queryPos).hasTag(BlockTags.NETHER_SURFACE_BLOCK)) { + return false; + } + } + } + } + return true; + } + + @Override + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePos) { + TilePos currentPos = new TilePos(tilePos); + while(world.isAirBlock(currentPos) && currentPos.y > 1) { + currentPos.y--; + } + + double[] map = this.RADIUS_MAPS[random.nextInt(2)]; + if (this.hasSpace(world, currentPos.x, currentPos.y, currentPos.z)) { + Vector2i centerXZ = new Vector2i(currentPos.x, currentPos.z); + TilePos queryPos = new TilePos(); + + for(int i = 0; i < map.length; ++i) { + this.generateRadius(world, centerXZ, queryPos, map[i], currentPos.y + i); + } + + TilePos circlePos = new TilePos(); + + for(circlePos.x = currentPos.x - 2; circlePos.x < currentPos.x + 2; ++circlePos.x) { + for(circlePos.z = currentPos.z - 2; circlePos.z < currentPos.z + 2; ++circlePos.z) { + for(circlePos.y = currentPos.y - 4; circlePos.y < currentPos.y + 4; ++circlePos.y) { + if (world.getBlockType(circlePos) == boulderBlock && random.nextInt(8) == 0) { + world.setBlockType(circlePos, extraBlock); + } + } + } + } + } + + return true; + } +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureBoulderGlowstone.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureBoulderGlowstone.java new file mode 100644 index 000000000..ed8ea7192 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureBoulderGlowstone.java @@ -0,0 +1,110 @@ +package net.minecraft.core.world.generate.feature; + +import net.minecraft.core.block.Block; +import net.minecraft.core.block.BlockLogicFluid; +import net.minecraft.core.block.Blocks; +import net.minecraft.core.block.tag.BlockTags; +import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Random; + +import static net.minecraft.core.block.BlockLogicFluid.isAcid; + +public class WorldFeatureBoulderGlowstone implements WorldFeatureInterface { + + private final Block stoneBlock; + private final Block fireBlock; + private final int radius; + + /** + * Creates a customizable boulder. + * + * @param stoneBlock The primary block used to build the boulder. + * @param fireBlock The block to place on top (e.g., Fire). Set to null for no top blocks. + * @param radius The size. 1 is 3x3, 2 is a 5x5, etc. + */ + public WorldFeatureBoulderGlowstone(@NotNull Block stoneBlock, @Nullable Block fireBlock, int radius) { + this.stoneBlock = stoneBlock; + this.fireBlock = fireBlock; + this.radius = Math.max(1, radius); + } + + private static final int MAX_DOWN_SCAN = 64; + + @Override + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePosc) { + TilePos tilePos = new TilePos(tilePosc.x(), tilePosc.y(), tilePosc.z()); + + // Find the ground or the bottom of the acid pool. Cap the search distance. + int scanned = 0; + while ((world.isAirBlock(tilePos) || isAcid(world, tilePos)) && tilePos.y() - 1 > 0 && scanned < MAX_DOWN_SCAN) { + tilePos.down(); + scanned++; + } + + // Must be resting on a Nether surface block + if (!world.getBlockType(tilePos).hasTag(BlockTags.NETHER_SURFACE_BLOCK)) { + return false; + } + + // Must be generated inside/under an acid pool + TilePos queryPos = new TilePos(); + if (!isAcid(world, tilePos.up(queryPos))) { + return false; + } + + int maxExpectedHeight = (this.radius * 2) + 2; + + if (hasSpace(world, tilePos.x(), tilePos.y(), tilePos.z(), maxExpectedHeight)) { + TilePos centerPos = new TilePos(tilePos.x(), tilePos.y() + 1, tilePos.z()); + + for (int x1 = -this.radius; x1 <= this.radius; x1++) { + for (int z1 = -this.radius; z1 <= this.radius; z1++) { + + int dist = Math.abs(x1) + Math.abs(z1); + + int height = random.nextInt(2) + Math.max(1, (this.radius * 2 + 1) - dist); + if (height <= 0) continue; + + // Place the main boulder + for(int y1 = 0; y1 < height; y1++){ + centerPos.add(x1, y1, z1, queryPos); + world.setBlockType(queryPos, this.stoneBlock); + } + + // Place the top-layer + if (this.fireBlock != null) { + centerPos.add(x1, height, z1, queryPos); + if (world.isAirBlock(queryPos) || isAcid(world, queryPos)) { + if(random.nextInt(2) == 0){ + world.setBlockType(queryPos, this.fireBlock); + } + } + } + } + } + + return true; + } + + return false; + } + + private boolean hasSpace(World world, int xc, int y, int zc, int maxExpectedHeight) { + TilePos queryPos = new TilePos(); + + for (queryPos.y = y + 1; queryPos.y < y + maxExpectedHeight; queryPos.y++) { + queryPos.x = xc; + queryPos.z = zc; + + if (!world.isAirBlock(queryPos) && !isAcid(world, queryPos)) { + return false; + } + } + return true; + } +} diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureMagmaBoulder.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureBoulderMagma.java similarity index 57% rename from game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureMagmaBoulder.java rename to game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureBoulderMagma.java index 6146fcf30..8ce53846e 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureMagmaBoulder.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureBoulderMagma.java @@ -5,46 +5,51 @@ import net.minecraft.core.block.Blocks; import net.minecraft.core.block.tag.BlockTags; import net.minecraft.core.world.World; import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; import org.joml.Vector2i; import java.util.Random; -public class WorldFeatureMagmaBoulder extends WorldFeature{ +public class WorldFeatureBoulderMagma implements WorldFeatureInterface { final double[][] RADIUS_MAPS = { - {1.5D, 1.5D, 1D}, - {1D, 1.5D, 1D}, + {1.5D, 1.5D, 1.0D}, + {1.0D, 1.5D, 1.0D}, }; @Override - public boolean place(World world, Random random, int x, int y, int z) { - TilePos pos = new TilePos(x, y, z); - while(world.isAirBlock(pos) && pos.y - 1 > 0) {pos.down(); } + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePos) { + TilePos pos = new TilePos(tilePos); + + while(world.isAirBlock(pos) && pos.y() - 1 > 0) { + pos.down(); + } double[] map = RADIUS_MAPS[random.nextInt(2)]; - if (hasSpace(world, pos.x, pos.y, pos.z)) { - Vector2i centerXZ = new Vector2i(pos.x, pos.z); - TilePos queryPos = new TilePos(pos.x, pos.y, pos.z); + if (hasSpace(world, pos.x(), pos.y(), pos.z())) { + Vector2i centerXZ = new Vector2i(pos.x(), pos.z()); + TilePos queryPos = new TilePos(pos); for (int i = 0; i < map.length; i++) { - generateRadius(world, centerXZ, queryPos, map[i], pos.y + i); + generateRadius(world, centerXZ, queryPos, map[i], pos.y() + i); } TilePos circlePos = new TilePos(); - for (circlePos.x = pos.x() - 2; circlePos.x < pos.x() + 2; circlePos.x++) { - for (circlePos.z = pos.z() - 2; circlePos.z < pos.z() + 2; circlePos.z++) { - for (circlePos.y = pos.y() - 4; circlePos.y < pos.y + 4; circlePos.y++) { - + for (int x = pos.x() - 2; x < pos.x() + 2; x++) { + for (int z = pos.z() - 2; z < pos.z() + 2; z++) { + for (int y = pos.y() - 4; y < pos.y() + 4; y++) { + circlePos.set(x, y, z); if (!world.isAirBlock(circlePos)) { - if (random.nextInt(8) == 0) + if (random.nextInt(8) == 0) { world.setBlockType(circlePos, Blocks.COBBLE_BASALT); + } } } } } } - return true; } @@ -53,13 +58,11 @@ public class WorldFeatureMagmaBoulder extends WorldFeature{ } private void plotBlocks(World world, Vector2i center, TilePos queryPos, int x, int y, int z){ + plotBlock(world, center, queryPos, z, y, x); + plotBlock(world, center, queryPos, x, y, z); + } - for(int xx = center.x - x; xx <= center.x + x; xx++) { - Block block = getBlockAt(center, xx, center.y + z); - world.setBlockType(queryPos.set(xx, queryPos.y, center.y + z), block); - world.setBlockType(queryPos.set(xx, queryPos.y, center.y - z), block); - } - + private void plotBlock(World world, Vector2i center, TilePos queryPos, int x, int y, int z) { for(int xx = center.x - z; xx <= center.x + z; xx++) { Block block = getBlockAt(center, xx, center.y + x); world.setBlockType(queryPos.set(xx, y, center.y + x), block); @@ -77,20 +80,22 @@ public class WorldFeatureMagmaBoulder extends WorldFeature{ if (d > 0) { z--; d = d + 4 * (x - z) + 10; - } else + } else { d = d + 4 * x + 6; - + } plotBlocks(world, center, queryPos, x, y, z); } } private boolean hasSpace(World world, int xc, int y, int zc){ - TilePos queryPos = new TilePos(); - for (queryPos.y = y - 2; queryPos.y < y + 2; queryPos.y++) { - for (queryPos.x = xc - 2; queryPos.x < xc + 2; queryPos.x++) { - for (queryPos.z = zc - 2; queryPos.z < zc + 2; queryPos.z++) { - if (!world.isAirBlock(queryPos) && !world.getBlockType(queryPos).hasTag(BlockTags.NETHER_SURFACE_BLOCK)) + TilePos queryPos = new TilePos(); + for (int py = y - 2; py < y + 2; py++) { + for (int px = xc - 2; px < xc + 2; px++) { + for (int pz = zc - 2; pz < zc + 2; pz++) { + queryPos.set(px, py, pz); + if (!world.isAirBlock(queryPos) && !world.getBlockType(queryPos).hasTag(BlockTags.NETHER_SURFACE_BLOCK)) { return false; + } } } } diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureFire.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureFire.java index 8560a7512..476a470e2 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureFire.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureFire.java @@ -1,32 +1,65 @@ package net.minecraft.core.world.generate.feature; +import net.minecraft.core.block.Block; import net.minecraft.core.block.Blocks; +import net.minecraft.core.block.tag.BlockTags; import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; import java.util.Random; -public class WorldFeatureFire extends WorldFeature -{ +public class WorldFeatureFire implements WorldFeatureInterface { - public WorldFeatureFire() - { + private final Block overrideFireBlock; + private final Block overrideGroundBlock; + + public WorldFeatureFire() { + this.overrideFireBlock = null; + this.overrideGroundBlock = null; + } + + public WorldFeatureFire(Block overrideFireBlock, Block overrideGroundBlock) { + this.overrideFireBlock = overrideFireBlock; + this.overrideGroundBlock = overrideGroundBlock; } @Override - public boolean place(World world, Random random, int x, int y, int z) - { - for(int i = 0; i < 32; i++) - { - int x1 = (x + random.nextInt(8)) - random.nextInt(8); - int y1 = (y + random.nextInt(4)) - random.nextInt(4); - int z1 = (z + random.nextInt(8)) - random.nextInt(8); - if(world.isAirBlock(x1, y1, z1) && (world.getBlockId(x1, y1 - 1, z1) == Blocks.COBBLE_NETHERRACK.id() || world.getBlockId(x1, y1 - 1, z1) == Blocks.BRIMSAND.id())) - { - world.setBlockWithNotify(x1, y1, z1, Blocks.FIRE.id()); - world.setBlock(x1, y1 - 1, z1, Blocks.COBBLE_NETHERRACK.id()); + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePos) { + TilePos queryPos = new TilePos(); + TilePos downPos = new TilePos(); + + for (int i = 0; i < 32; ++i) { + queryPos.set( + tilePos.x() + random.nextInt(8) - random.nextInt(8), + tilePos.y() + random.nextInt(4) - random.nextInt(4), + tilePos.z() + random.nextInt(8) - random.nextInt(8) + ); + + downPos.set(queryPos).down(); + + if (world.isAirBlock(queryPos)) { + Block surfaceBlock = world.getBlockType(downPos); + + if (this.overrideFireBlock != null && this.overrideGroundBlock != null) { + if (surfaceBlock.hasTag(BlockTags.NETHER_SURFACE_BLOCK)) { + world.setBlockTypeNotify(queryPos, this.overrideFireBlock); + world.setBlockTypeNotify(downPos, this.overrideGroundBlock); + } + } + + else { + if (surfaceBlock.hasTag(BlockTags.INFINITE_BURN_SULFURIC)) { + world.setBlockTypeNotify(queryPos, Blocks.FIRE_SULFURIC); + } + else if (surfaceBlock.hasTag(BlockTags.INFINITE_BURN)) { + world.setBlockTypeNotify(queryPos, Blocks.FIRE); + } + } } } return true; } -} +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureFloorVent.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureFloorVent.java index e9efe2239..5f12bdf2d 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureFloorVent.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureFloorVent.java @@ -9,70 +9,73 @@ import org.jetbrains.annotations.NotNull; import java.util.Random; -public class WorldFeatureFloorVent implements WorldFeatureInterface -{ +public class WorldFeatureFloorVent implements WorldFeatureInterface { private final int minRadius; private final int radiusMod; - - public WorldFeatureFloorVent(int minRadius, int radiusMod) - { + public WorldFeatureFloorVent(int minRadius, int radiusMod) { this.minRadius = minRadius; this.radiusMod = radiusMod; } - public WorldFeatureFloorVent() - { + public WorldFeatureFloorVent() { this.minRadius = 1; this.radiusMod = 2; } - private boolean isAirOrLiquid(World world, TilePos tilePos){ - return world.isAirBlock(tilePos) || - world.getBlockType(tilePos).hasTag(BlockTags.IS_LAVA) || - world.getBlockType(tilePos).hasTag(BlockTags.IS_WATER); - } - @Override public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePos) { - TilePos pos = (TilePos) tilePos; - while(isAirOrLiquid(world, pos) && pos.y - 1 > 0) {pos.down(); } + TilePos pos = new TilePos(tilePos.x(), tilePos.y(), tilePos.z()); - int radius = minRadius + random.nextInt(radiusMod); + pos.x += random.nextInt(8); + pos.z += random.nextInt(8); - TilePos centerPos = new TilePos(pos.x() + random.nextInt(8), pos.y(), pos.z() + random.nextInt(8)); - TilePos cursor = new TilePos(); + while (world.isAirBlock(pos) && pos.y > 0) { + pos.down(); + } - if(!canPlace(centerPos, world) && !isAirOrLiquid(world, centerPos.up(new TilePos()))){ + if (pos.y <= 0 || !canPlace(pos, world)) { return false; } - for(cursor.x = centerPos.x() - radius; cursor.x <= centerPos.x() + radius; cursor.x++) { - for (cursor.z = centerPos.z() - radius; cursor.z <= centerPos.z() + radius; cursor.z++) { - int xd = cursor.x() - centerPos.x(); - int zd = cursor.z() - centerPos.z(); + if (!world.isAirBlock(new TilePos(pos.x, pos.y + 1, pos.z)) || + !world.isAirBlock(new TilePos(pos.x + 1, pos.y + 1, pos.z)) || + !world.isAirBlock(new TilePos(pos.x - 1, pos.y + 1, pos.z)) || + !world.isAirBlock(new TilePos(pos.x, pos.y + 1, pos.z + 1)) || + !world.isAirBlock(new TilePos(pos.x, pos.y + 1, pos.z - 1))) { + return false; + } - float dist = xd * xd + zd * zd; + int radius = minRadius + random.nextInt(radiusMod); + TilePos cursor = new TilePos(); - for(cursor.y = centerPos.y(); cursor.y > pos.y - 4; cursor.y--) { + for (cursor.x = pos.x - radius; cursor.x <= pos.x + radius; cursor.x++) { + for (cursor.z = pos.z - radius; cursor.z <= pos.z + radius; cursor.z++) { + int xd = cursor.x - pos.x; + int zd = cursor.z - pos.z; + float distSq = xd * xd + zd * zd; - if(cursor.y <= 0) - continue; + if (distSq > radius * radius) { + continue; + } - // Skip placement if cursor hasn't hit ground yet + for (cursor.y = pos.y; cursor.y > pos.y - 4; cursor.y--) { + if (cursor.y <= 0) continue; - if(dist <= (radius * radius) && canPlace(cursor, world)) { - if(cursor.equals(centerPos)){ + if (canPlace(cursor, world)) { + if (cursor.x == pos.x && cursor.y == pos.y && cursor.z == pos.z) { world.setBlockTypeNotify(cursor, Blocks.THERMAL_VENT); } else { - if(random.nextInt(4) != 0) { + if (random.nextInt(4) != 0) { world.setBlockTypeNotify(cursor, Blocks.BASALT); - } else if(random.nextInt(20) == 0) { + } else if (random.nextInt(20) == 0) { + if (cursor.y == pos.y && world.isAirBlock(new TilePos(cursor.x, cursor.y + 1, cursor.z))) { world.setBlockTypeNotify(cursor, Blocks.THERMAL_VENT); + } else { + world.setBlockTypeNotify(cursor, Blocks.BASALT); + } } - } - } } } @@ -80,12 +83,13 @@ public class WorldFeatureFloorVent implements WorldFeatureInterface return true; } - private boolean canPlace(TilePos cursor, World world) { - - if (isAirOrLiquid(world, cursor)) { + private boolean canPlace(TilePos cursor, @NotNull World world) { + if (world.isAirBlock(cursor) || + world.getBlockType(cursor).hasTag(BlockTags.IS_LAVA) || + world.getBlockType(cursor).hasTag(BlockTags.IS_WATER)) { return false; } return world.getBlockType(cursor).hasTag(BlockTags.NETHER_SURFACE_BLOCK); } -} +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherPatch.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherPatch.java index 77eee77a1..96be52cc4 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherPatch.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherPatch.java @@ -1,34 +1,56 @@ package net.minecraft.core.world.generate.feature; -import net.minecraft.core.block.Blocks; +import net.minecraft.core.block.Block; import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; import java.util.Random; -public class WorldFeatureNetherPatch extends WorldFeature -{ - private final int blockId; - @MethodParametersAnnotation(names = {"blockId"}) - public WorldFeatureNetherPatch(int blockId) - { - this.blockId = blockId; +public class WorldFeatureNetherPatch implements WorldFeatureInterface { + protected final Block defaultBlock; + protected final int attempts; + + public WorldFeatureNetherPatch(Block defaultBlock, int attempts) { + this.defaultBlock = defaultBlock; + this.attempts = attempts; + } + + public WorldFeatureNetherPatch(Block defaultBlock) { + this(defaultBlock, 64); } @Override - public boolean place(World world, Random random, int x, int y, int z) - { - while(world.getBlockId(x, y, z) == 0 && y > 0) { y--; } - for(int i = 0; i < 8; i++) - { - int x1 = (x + random.nextInt(4)) - random.nextInt(4); - int y1 = (y + random.nextInt(4)) - random.nextInt(4); - int z1 = (z + random.nextInt(4)) - random.nextInt(4); - if(world.isAirBlock(x1, y1, z1) && Blocks.blocksList[blockId].canBlockStay(world, x1, y1, z1)) - { - world.setBlock(x1, y1, z1, blockId); + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePos) { + TilePos pos = new TilePos(tilePos); + + while (world.isAirBlock(pos) && pos.y() > 0) { + pos.down(); + } + + TilePos queryPos = new TilePos(); + + for (int i = 0; i < this.attempts; i++) { + queryPos.set( + pos.x() + random.nextInt(4) - random.nextInt(4), + pos.y() + random.nextInt(4) - random.nextInt(4), + pos.z() + random.nextInt(4) - random.nextInt(4) + ); + + if (world.isAirBlock(queryPos)) { + Block blockToPlace = this.getBlockToPlace(world, queryPos); + + if (blockToPlace != null && blockToPlace.canStay(world, queryPos)) { + world.setBlockType(queryPos, blockToPlace); + } } } return true; } -} + + protected Block getBlockToPlace(World world, TilePos queryPos) { + return this.defaultBlock; + } +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherPatchBelow.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherPatchBelow.java new file mode 100644 index 000000000..1181b6583 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherPatchBelow.java @@ -0,0 +1,59 @@ +package net.minecraft.core.world.generate.feature; + +import net.minecraft.core.block.Block; +import net.minecraft.core.block.Blocks; +import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; + +import java.util.Random; + +public class WorldFeatureNetherPatchBelow implements WorldFeatureInterface { + private final int blockId; + + @MethodParametersAnnotation(names = {"blockId"}) + public WorldFeatureNetherPatchBelow(int blockId) { + this.blockId = blockId; + } + + @Override + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePos) { + TilePos pos = new TilePos(tilePos); + + while (world.isAirBlock(pos) && pos.y() > 0) { + pos.down(); + } + + TilePos queryPos = new TilePos(); + TilePos targetPos = new TilePos(); + TilePos tempPos = new TilePos(); + Block block = Blocks.blocksList[this.blockId]; + + for (int i = 0; i < 8; ++i) { + queryPos.set( + pos.x() + random.nextInt(4) - random.nextInt(4), + pos.y() + random.nextInt(4) - random.nextInt(4), + pos.z() + random.nextInt(4) - random.nextInt(4) + ); + + targetPos.set(queryPos.x(), queryPos.y() - 1, queryPos.z()); + + if (world.isAirBlock(queryPos) && world.getBlockType(targetPos) == Blocks.BLOCK_ASH) { + + boolean surroundedByAsh = + world.getBlockType(tempPos.set(targetPos).east()) == Blocks.BLOCK_ASH && + world.getBlockType(tempPos.set(targetPos).west()) == Blocks.BLOCK_ASH && + world.getBlockType(tempPos.set(targetPos).south()) == Blocks.BLOCK_ASH && + world.getBlockType(tempPos.set(targetPos).north()) == Blocks.BLOCK_ASH; + + if (surroundedByAsh && block.canStay(world, queryPos)) { + world.setBlockType(targetPos, block); + world.setBlockType(queryPos, Blocks.AIR); + } + } + } + + return true; + } +} diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherScatter.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherScatter.java new file mode 100644 index 000000000..fe0c402e1 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherScatter.java @@ -0,0 +1,148 @@ +package net.minecraft.core.world.generate.feature; + +import net.minecraft.core.block.Block; +import net.minecraft.core.block.Blocks; +import net.minecraft.core.world.World; +import net.minecraft.core.world.biome.Biome; +import net.minecraft.core.world.biome.Biomes; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Random; + +public class WorldFeatureNetherScatter implements WorldFeatureInterface { + private static final int MAX_DOWN_SCAN = 96; + private static final int BONE_PILE_ON_ASH_RARE_ONE_IN = 8; + private static final int EMBER_FIRST_ROLL_SIDES = 4; + private static final int EMBER_FIRST_ROLL_THRESHOLD = 1; + + private final TilePos scratchGround = new TilePos(); + private final TilePos scratchPlace = new TilePos(); + private final TilePos scratchProbe = new TilePos(); + private final TilePos scratchNeighbor = new TilePos(); + + @Override + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePos) { + if (random.nextInt(EMBER_FIRST_ROLL_SIDES) >= EMBER_FIRST_ROLL_THRESHOLD) { + final Biome seedBiome = world.getBlockBiome(tilePos); + if (isOldWorldBiome(seedBiome)) { + if (this.tryPlaceEmberReplacingAsh(world, tilePos)) { + return true; + } + } + } + + final TilePos ground = this.scratchGround.set(tilePos.x(), tilePos.y(), tilePos.z()); + int scanned = 0; + while (world.isAirBlock(ground) && ground.y() > 0 && scanned < MAX_DOWN_SCAN) { + ground.down(); + scanned++; + } + if (ground.y() <= 0) { return false; } + + final Block surface = world.getBlockType(ground); + + if (isRubyglassScatterForbiddenSurface(surface)) { + return false; + } + + final TilePos placePos = this.scratchPlace.set(ground.x(), ground.y() + 1, ground.z()); + if (!world.isAirBlock(placePos)) { return false; } + + final Block chosen = pickDecoration(world, random, placePos, surface); + + if (chosen == Blocks.BOULDER_MAGMATIC && surface != Blocks.COBBLE_NETHERRACK && surface != Blocks.NETHERRACK) { + return false; + } + if (chosen == Blocks.BOULDER_SULFURIC && surface != Blocks.BRIMSAND && surface != Blocks.BRIMSTONE && surface != Blocks.BRIMTHAW) { + return false; + } + if (chosen == Blocks.BONE_PILE && isAshSurface(surface)) { + if (random.nextInt(BONE_PILE_ON_ASH_RARE_ONE_IN) != 0) { + return false; + } + } + if (!chosen.canStay(world, placePos)) { return false; } + + world.setBlockType(placePos, chosen); + return true; + } + + private static boolean isOldWorldBiome(final @Nullable Biome biome) { + return biome == Biomes.NETHER_OLD_WORLD || biome == Biomes.NETHER_OLD_WORLD_DESERT; + } + + private static boolean isAshSurface(final @NotNull Block surface) { + return surface == Blocks.BLOCK_ASH || surface == Blocks.LAYER_ASH; + } + + private static boolean isRubyglassScatterForbiddenSurface(final @NotNull Block surface) { + return surface == Blocks.RUBYGLASS_NODE + || surface == Blocks.RUBYGLASS_COLUMN + || surface == Blocks.RUBYGLASS_GROWTH; + } + + private boolean tryPlaceEmberReplacingAsh(final @NotNull World world, final @NotNull TilePosc start) { + final int x = start.x(); + final int z = start.z(); + final TilePos probe = this.scratchProbe; + + int scanned = 0; + for (int y = start.y(); y > 0 && scanned < MAX_DOWN_SCAN; y--, scanned++) { + probe.set(x, y, z); + + if (world.getBlockType(probe) != Blocks.BLOCK_ASH) { + continue; + } + + final TilePos above = this.scratchPlace.set(x, y + 1, z); + if (!world.isAirBlock(above)) { + continue; + } + + if (!isOldWorldBiome(world.getBlockBiome(probe))) { + continue; + } + + if (!this.isAshSurroundedByAsh(world, x, y, z)) { + continue; + } + + world.setBlockType(probe, Blocks.EMBER); + if (Blocks.LAYER_ASH.canPlaceAt(world, above)) { + world.setBlockType(above, Blocks.LAYER_ASH); + } + return true; + } + return false; + } + + private boolean isAshSurroundedByAsh(final @NotNull World world, final int ax, final int ay, final int az) { + final TilePos n = this.scratchNeighbor; + return world.getBlockType(n.set(ax + 1, ay, az)) == Blocks.BLOCK_ASH + && world.getBlockType(n.set(ax - 1, ay, az)) == Blocks.BLOCK_ASH + && world.getBlockType(n.set(ax, ay, az + 1)) == Blocks.BLOCK_ASH + && world.getBlockType(n.set(ax, ay, az - 1)) == Blocks.BLOCK_ASH; + } + + private @NotNull Block pickDecoration(final @NotNull World world, final @NotNull Random random, + final @NotNull TilePos placePos, final @NotNull Block surface) { + if (surface == Blocks.OBSIDIAN) { + return Blocks.BONE_PILE; + } + + final Biome biome = world.getBlockBiome(placePos); + if (biome == Biomes.NETHER_SULFUR_POOLS) { + return random.nextBoolean() ? Blocks.BONE_PILE : Blocks.BOULDER_SULFURIC; + } + if (biome == Biomes.NETHER_VOLCANIC_ISLANDS || biome == Biomes.NETHER_CRAG + || biome == Biomes.NETHER_CRYSTAL_PLAINS || biome == Biomes.NETHER_CRYSTAL_FOREST + || biome == Biomes.NETHER_SHELF) { + return random.nextBoolean() ? Blocks.BONE_PILE : Blocks.BOULDER_MAGMATIC; + } + + return Blocks.BONE_PILE; + } +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherSpring.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherSpring.java index b71f37b38..e5b7bf40d 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherSpring.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherSpring.java @@ -1,79 +1,65 @@ package net.minecraft.core.world.generate.feature; +import net.minecraft.core.block.Block; import net.minecraft.core.block.Blocks; +import net.minecraft.core.block.tag.BlockTags; import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; import java.util.Random; -public class WorldFeatureNetherSpring extends WorldFeature -{ - private final int blockId; - @MethodParametersAnnotation(names = {"blockId"}) - public WorldFeatureNetherSpring(int blockId) - { - this.blockId = blockId; - } +public class WorldFeatureNetherSpring implements WorldFeatureInterface { + private final int blockId; - @Override - public boolean place(World world, Random random, int x, int y, int z) - { - if(world.getBlockId(x, y + 1, z) != Blocks.COBBLE_NETHERRACK.id()) - { - return false; - } - if(world.getBlockId(x, y, z) != 0 && world.getBlockId(x, y, z) != Blocks.COBBLE_NETHERRACK.id()) - { - return false; - } - int l = 0; - if(world.getBlockId(x - 1, y, z) == Blocks.COBBLE_NETHERRACK.id()) - { - l++; - } - if(world.getBlockId(x + 1, y, z) == Blocks.COBBLE_NETHERRACK.id()) - { - l++; - } - if(world.getBlockId(x, y, z - 1) == Blocks.COBBLE_NETHERRACK.id()) - { - l++; - } - if(world.getBlockId(x, y, z + 1) == Blocks.COBBLE_NETHERRACK.id()) - { - l++; - } - if(world.getBlockId(x, y - 1, z) == Blocks.COBBLE_NETHERRACK.id()) - { - l++; - } - int i1 = 0; - if(world.isAirBlock(x - 1, y, z)) - { - i1++; - } - if(world.isAirBlock(x + 1, y, z)) - { - i1++; - } - if(world.isAirBlock(x, y, z - 1)) - { - i1++; - } - if(world.isAirBlock(x, y, z + 1)) - { - i1++; - } - if(world.isAirBlock(x, y - 1, z)) - { - i1++; - } - if(l == 4 && i1 == 1) - { - world.setBlockWithNotify(x, y, z, blockId); - world.scheduledUpdatesAreImmediate = true; - Blocks.blocksList[blockId].updateTick(world, x, y, z, random, false); - world.scheduledUpdatesAreImmediate = false; - } - return true; - } -} + @MethodParametersAnnotation(names = {"blockId"}) + public WorldFeatureNetherSpring(int blockId) { + this.blockId = blockId; + } + + @Override + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePos) { + TilePos upPos = new TilePos(tilePos).up(); + + if (world.getBlockType(upPos).hasTag(BlockTags.NETHER_SURFACE_BLOCK)) { + return false; + } else if (!world.isAirBlock(tilePos) && world.getBlockType(tilePos).hasTag(BlockTags.NETHER_SURFACE_BLOCK)) { + return false; + } else { + int solidCount = 0; + int airCount = 0; + + TilePos queryPos = new TilePos(); + int[][] offsets = {{-1, 0, 0}, {1, 0, 0}, {0, 0, -1}, {0, 0, 1}, {0, -1, 0}}; + + for (int[] offset : offsets) { + queryPos.set(tilePos.x() + offset[0], tilePos.y() + offset[1], tilePos.z() + offset[2]); + if (world.getBlockType(queryPos).hasTag(BlockTags.NETHER_SURFACE_BLOCK)) { + solidCount++; + } + if (world.isAirBlock(queryPos)) { + airCount++; + } + } + + if (solidCount == 4 && airCount == 1) { + if (this.blockId == Blocks.FLUID_ACID_STILL.id() || this.blockId == Blocks.FLUID_ACID_FLOWING.id()) { + if (random.nextInt(50) == 0 && world.isAirBlock(upPos)) { + world.setBlockTypeNotify(tilePos, Blocks.GLOWSTONE); + world.setBlockTypeNotify(upPos, Blocks.FIRE_SULFURIC); + } + } else { + Block block = Blocks.blocksList[this.blockId]; + world.setBlockTypeNotify(tilePos, block); + + world.scheduledUpdatesAreImmediate = true; + block.updateTick(world, tilePos, random, false); + world.scheduledUpdatesAreImmediate = false; + } + } + + return true; + } + } +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureOre.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureOre.java index 138b96771..908bebe16 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureOre.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureOre.java @@ -1,44 +1,51 @@ package net.minecraft.core.world.generate.feature; import it.unimi.dsi.fastutil.ints.Int2IntArrayMap; +import net.minecraft.core.block.Block; import net.minecraft.core.block.Blocks; import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; import java.util.Random; -public class WorldFeatureOre extends WorldFeature -{ - private int minableBlockId; - private int numberOfBlocks; +public class WorldFeatureOre implements WorldFeatureInterface { + private final int minableBlockId; + private final int numberOfBlocks; private final Int2IntArrayMap variantMap; @MethodParametersAnnotation(names = {"blockId", "numberOfBlocks"}) - public WorldFeatureOre(int blockId, int numberOfBlocks) - { - minableBlockId = blockId; + public WorldFeatureOre(int blockId, int numberOfBlocks) { + this.minableBlockId = blockId; this.numberOfBlocks = numberOfBlocks; this.variantMap = null; } @MethodParametersAnnotation(names = {"blockId", "numberOfBlocks", "variantMap"}) - public WorldFeatureOre(@NotNull Int2IntArrayMap variantMap, int numberOfBlocks) - { + public WorldFeatureOre(@NotNull Int2IntArrayMap variantMap, int numberOfBlocks) { + this.minableBlockId = 0; this.numberOfBlocks = numberOfBlocks; this.variantMap = variantMap; } @Override - public boolean place(World world, Random random, int xStart, int yStart, int zStart) - { + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePos) { float f = random.nextFloat() * MathHelper.PI; + + int xStart = tilePos.x(); + int yStart = tilePos.y(); + int zStart = tilePos.z(); + double xMax = (float)(xStart + 8) + MathHelper.sin(f) * (float)numberOfBlocks / 8F; double xMin = (float)(xStart + 8) - MathHelper.sin(f) * (float)numberOfBlocks / 8F; double zMax = (float)(zStart + 8) + MathHelper.cos(f) * (float)numberOfBlocks / 8F; double zMin = (float)(zStart + 8) - MathHelper.cos(f) * (float)numberOfBlocks / 8F; double yMax = yStart + random.nextInt(3) + 2; double yMin = yStart - random.nextInt(3) + 2; - for(int l = 0; l <= numberOfBlocks; l++) - { + + TilePos queryPos = new TilePos(); + + for(int l = 0; l <= numberOfBlocks; l++) { double d6 = xMax + (xMin - xMax) * (double)l / (double)numberOfBlocks; double d7 = yMax + (yMin - yMax) * (double)l / (double)numberOfBlocks; double d8 = zMax + (zMin - zMax) * (double)l / (double)numberOfBlocks; @@ -51,52 +58,45 @@ public class WorldFeatureOre extends WorldFeature int xVeinEnd = MathHelper.floor(d6 + d10 / 2D); int yVeinEnd = MathHelper.floor(d7 + d11 / 2D); int zVeinEnd = MathHelper.floor(d8 + d10 / 2D); - for(int x = xVeinStart; x <= xVeinEnd; x++) - { + + for(int x = xVeinStart; x <= xVeinEnd; x++) { double d12 = (((double)x + 0.5D) - d6) / (d10 / 2D); - if(d12 * d12 >= 1.0D) - { + if(d12 * d12 >= 1.0D) { continue; } - for(int y = yVeinStart; y <= yVeinEnd; y++) - { + for(int y = yVeinStart; y <= yVeinEnd; y++) { double d13 = (((double)y + 0.5D) - d7) / (d11 / 2D); - if(d12 * d12 + d13 * d13 >= 1.0D) - { + if(d12 * d12 + d13 * d13 >= 1.0D) { continue; } - for(int z = zVeinStart; z <= zVeinEnd; z++) - { + for(int z = zVeinStart; z <= zVeinEnd; z++) { double d14 = (((double)z + 0.5D) - d8) / (d10 / 2D); - if(d12 * d12 + d13 * d13 + d14 * d14 < 1.0D) - { - if (variantMap != null) - { - int blockId = world.getBlockId(x, y, z); - if (blockId <= 0) continue; - if (variantMap.containsKey(blockId)){ - world.setBlock(x, y, z, variantMap.get(blockId)); + if(d12 * d12 + d13 * d13 + d14 * d14 < 1.0D) { + + queryPos.set(x, y, z); + Block currentBlock = world.getBlockType(queryPos); + + if (currentBlock == Blocks.AIR) continue; + + int id = currentBlock.id(); + + if (variantMap != null) { + if (variantMap.containsKey(id)){ + world.setBlockType(queryPos, Blocks.blocksList[variantMap.get(id)]); + } + } else { + if (id == Blocks.STONE.id() || id == Blocks.COBBLE_NETHERRACK.id() || + id == Blocks.BASALT.id() || id == Blocks.LIMESTONE.id() || + id == Blocks.GRANITE.id()) { + + world.setBlockType(queryPos, Blocks.blocksList[minableBlockId]); } - } - else - { - int id = world.getBlockId(x, y, z); - if (id == Blocks.STONE.id() || id == Blocks.COBBLE_NETHERRACK.id() || - id == Blocks.BASALT.id() || id == Blocks.LIMESTONE.id() || - id == Blocks.GRANITE.id()) - { - world.setBlock(x, y, z, minableBlockId); - } - } + } } } - } - } - } - return true; } } diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeaturePerlinVein.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeaturePerlinVein.java new file mode 100644 index 000000000..a160d7226 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeaturePerlinVein.java @@ -0,0 +1,72 @@ +package net.minecraft.core.world.generate.feature; + +import net.minecraft.core.block.Block; +import net.minecraft.core.world.World; +import net.minecraft.core.world.noise.ImprovedPerlinNoise; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; + +import java.util.Random; + +public class WorldFeaturePerlinVein implements WorldFeatureInterface { + private final Block placeBlock; + private final Block targetBlock; + private ImprovedPerlinNoise noiseGen; + private final double scale; + private final double thickness; + + public WorldFeaturePerlinVein(Block placeBlock, Block targetBlock, double scale, double thickness) { + this.placeBlock = placeBlock; + this.targetBlock = targetBlock; + this.scale = scale; + this.thickness = thickness; + } + + @Override + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePos) { + if (this.noiseGen == null) { + this.noiseGen = new ImprovedPerlinNoise(new Random(world.getRandomSeed() + this.placeBlock.id())); + } + + int startX = tilePos.x(); + int startZ = tilePos.z(); + int maxY = world.getWorldType().getMaxY(world); + int minY = world.getWorldType().getMinY(world); + int ySize = maxY - minY; + if (ySize <= 0) { + return false; + } + + // Single bulk noise sample for the full chunk column instead of per-block. + double[] noiseRegion = this.noiseGen.getRegion(null, startX, minY, startZ, 16, ySize, 16, this.scale, this.scale, this.scale); + + boolean placedAny = false; + TilePos queryPos = new TilePos(); + + for (int xi = 0; xi < 16; xi++) { + int worldX = startX + xi; + int xBase = xi * 16 * ySize; + for (int zi = 0; zi < 16; zi++) { + int worldZ = startZ + zi; + int zBase = xBase + zi * ySize; + for (int yi = 0; yi < ySize; yi++) { + double noiseVal = noiseRegion[zBase + yi]; + if (Math.abs(noiseVal) > this.thickness) { + continue; + } + + queryPos.set(worldX, minY + yi, worldZ); + if (world.getBlockType(queryPos) != this.targetBlock) { + continue; + } + + world.setBlockType(queryPos, this.placeBlock); + placedAny = true; + } + } + } + + return placedAny; + } +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureRoofSpire.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureRoofSpire.java new file mode 100644 index 000000000..d60ce0ab1 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureRoofSpire.java @@ -0,0 +1,74 @@ +package net.minecraft.core.world.generate.feature; + +import net.minecraft.core.block.Block; +import net.minecraft.core.block.Blocks; +import net.minecraft.core.block.tag.BlockTags; +import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; +import org.joml.Vector3i; + +import java.util.Random; + +public class WorldFeatureRoofSpire extends WorldFeature { + private final Block boulderBlock; + + public WorldFeatureRoofSpire(Block boulderBlock) { + this.boulderBlock = boulderBlock; + } + + public boolean place(World world, Random random, int x, int y, int z) { + TilePos pos = new TilePos(x, y, z); + + while (world.isAirBlock(pos) && pos.y < 245) { + pos.up(); + } + + if (this.hasSpace(world, pos.x, pos.y, pos.z)) { + Vector3i highestOffset = new Vector3i(0, 0, 0); + TilePos centerPos = new TilePos(pos.x, pos.y, pos.z); + TilePos queryPos = new TilePos(); + + for (int x1 = 0; x1 < 2; ++x1) { + for (int z1 = 0; z1 < 2; ++z1) { + int height = random.nextInt(6) + 4; + if (height > highestOffset.y) { + highestOffset.set(x1, height, z1); + } + + for (int y1 = 0; y1 < height; ++y1) { + centerPos.add(x1, -y1, z1, queryPos); + + Block currentBlock = world.getBlockType(queryPos); + + if (currentBlock != Blocks.BEDROCK) { + world.setBlockType(queryPos, boulderBlock); + } + } + } + } + + for (int y1 = 0; y1 < 2; ++y1) { + centerPos.add(highestOffset.x, -(highestOffset.y + y1), highestOffset.z, queryPos); + world.setBlockType(queryPos, boulderBlock); + } + } + + return true; + } + + private boolean hasSpace(World world, int xc, int y, int zc) { + TilePos queryPos = new TilePos(); + + for (queryPos.y = y - 3; queryPos.y > y - 9; --queryPos.y) { + for (queryPos.x = xc - 3; queryPos.x < xc + 3; ++queryPos.x) { + for (queryPos.z = zc - 3; queryPos.z < zc + 3; ++queryPos.z) { + if (!world.isAirBlock(queryPos) && !world.getBlockType(queryPos).hasTag(BlockTags.NETHER_SURFACE_BLOCK)) { + return false; + } + } + } + } + + return true; + } +} diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureRubyglassCrystalline.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureRubyglassCrystalline.java new file mode 100644 index 000000000..c47fd7f3b --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureRubyglassCrystalline.java @@ -0,0 +1,164 @@ +package net.minecraft.core.world.generate.feature; + +import net.minecraft.core.block.Block; +import net.minecraft.core.block.Blocks; +import net.minecraft.core.util.helper.MathHelper; +import net.minecraft.core.world.World; +import net.minecraft.core.world.generate.voxelizer.ConvexShapeVoxelizer; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; +import org.joml.Matrix4f; +import org.joml.Vector3f; + +import java.util.Objects; +import java.util.Random; + +public class WorldFeatureRubyglassCrystalline implements WorldFeatureInterface { + private static final float BASE_PCTG = 0.5F; + private final boolean isCeiling; + private final int minHeight; + private final int heightMod; + + public WorldFeatureRubyglassCrystalline(boolean isCeiling, int minHeight, int heightMod) { + this.isCeiling = isCeiling; + this.minHeight = minHeight; + this.heightMod = heightMod; + } + + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePos) { + TilePos ti = new TilePos(tilePos.x() + random.nextInt(2) - random.nextInt(2), tilePos.y(), tilePos.z() + random.nextInt(2) - random.nextInt(2)); + int floorY = -1; + int checksForGround = 0; + boolean foundGround = false; + boolean canGenerate = false; + int groundDepth = 0; + + while (true) { + if (this.isCeiling) { + ++ti.y; + } else { + --ti.y; + } + + if (checksForGround > 64 || ti.y < 0 || ti.y >= world.getHeightBlocks()) { + break; + } + + Block block = world.getBlockType(ti); + if (!foundGround) { + if (block == Blocks.COBBLE_NETHERRACK) { + floorY = ti.y; + foundGround = true; + } + } else { + ++groundDepth; + if (block != Blocks.COBBLE_NETHERRACK) { + break; + } + + if (groundDepth >= 6) { + canGenerate = true; + break; + } + } + + ++checksForGround; + } + + Block block = world.getBlockType(ti); + if (canGenerate && (block == Blocks.COBBLE_NETHERRACK || block == Blocks.RUBYGLASS_CRYSTAL || block == Blocks.SOULSAND)) { + if (this.isCeiling) { + ++floorY; + } else { + --floorY; + } + + this.placeCrystal(world, random, new TilePos(ti.x, floorY, ti.z)); + return true; + } else { + return false; + } + } + + private float randomOffset(int length, @NotNull Random random) { + int base = length / 16; + return random.nextFloat() * (float) base; + } + + private void placeCrystal(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePos) { + float r = random.nextFloat(); + int length = this.minHeight + MathHelper.floor(Math.pow(r, 4.0F) * (double) this.heightMod); + int base = length / 4; + float rx = 0.0F; + float ry = 0.0F; + Block column = Blocks.RUBYGLASS_COLUMN; + Block bed = Blocks.COBBLE_NETHERRACK_CRYSTALLINE; + Block node = Blocks.RUBYGLASS_NODE; + TilePos ti = new TilePos(tilePos); + ti.y = this.isCeiling ? ti.y + base / 2 : ti.y - base / 2; + if (this.hasSpace(world, ti, base)) { + float minBase = -((float) base / 2.0F); + float maxBase = (float) base / 2.0F; + float randX = this.randomOffset(length, random); + float randZ = this.randomOffset(length, random); + Vector3f[] pts = new Vector3f[]{new Vector3f(minBase - randX, 0.0F, minBase - randZ), new Vector3f(maxBase + randX, 0.0F, minBase - randZ), new Vector3f(minBase - randX, 0.0F, maxBase + randZ), new Vector3f(maxBase + randX, 0.0F, maxBase + randZ), new Vector3f(minBase - randX, (float) length, minBase - randZ), new Vector3f(maxBase + randX, (float) length, minBase - randZ), new Vector3f(minBase - randX, (float) length, maxBase + randZ), new Vector3f(maxBase + randX, (float) length, maxBase + randZ), new Vector3f(0.0F, (float) length + maxBase * 4.0F * (random.nextFloat() * 0.5F + 0.5F), 0.0F)}; + if (this.isCeiling) { + rx = (float) Math.PI; + } + + rx += (float) ((random.nextDouble() - (double) 0.5F) * (Math.PI / 2D)) * 0.8F; + ry += (float) (random.nextDouble() * (double) 2.0F * Math.PI); + Matrix4f matrix = Objects.requireNonNull((new Matrix4f()).rotateY(ry).rotateX(rx)); + int[][] faces = new int[][]{{0, 1, 3}, {0, 1, 5}, {1, 3, 7}, {3, 2, 6}, {2, 0, 4}, {4, 5, 8}, {5, 7, 8}, {7, 6, 8}, {6, 4, 8}}; + ConvexShapeVoxelizer voxelizer = new ConvexShapeVoxelizer(pts, faces, matrix, (worldPos, replacing, faceDistances) -> { + if (replacing == Blocks.BEDROCK) { + return null; + } else { + boolean ore = random.nextInt(100) == 0; + boolean generateBed = false; + float distancePctg = faceDistances[0] / (float) length; + if (distancePctg < 0.5F) { + float innerDistancePctg = distancePctg / 0.5F; + if ((double) innerDistancePctg < (double) random.nextFloat() * (double) 0.75F) { + generateBed = true; + } + } + + float minDistToSide = 10.0F; + + for (int i = 1; i <= 4; ++i) { + minDistToSide = Math.min(faceDistances[i], minDistToSide); + } + + float distFromCenter = maxBase - minDistToSide; + float distanceToCenterPctg = minDistToSide / maxBase; + if ((double) distFromCenter > (double) 0.5F) { + return generateBed ? bed : (ore ? node : column); + } else { + float centerNoise = (float) Math.sin((double) distanceToCenterPctg * Math.PI * (double) 3.0F) * 0.5F; + float finalNoise = random.nextFloat() + centerNoise; + return (double) finalNoise > (double) 0.5F ? node : column; + } + } + }); + voxelizer.voxelize(world, ti); + } + } + + private boolean hasSpace(@NotNull World world, @NotNull TilePosc tilePos, int base) { + TilePos ti = new TilePos(); + + for (ti.y = tilePos.y(); ti.y < tilePos.y() + base; ++ti.y) { + for (ti.x = tilePos.x() - base; ti.x < tilePos.x() + base; ++ti.x) { + for (ti.z = tilePos.z() - base; ti.z < tilePos.z() + base; ++ti.z) { + if (world.getBlockType(ti) == Blocks.RUBYGLASS_COLUMN) { + return false; + } + } + } + } + + return true; + } +} diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureRubyglassGrowthPatch.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureRubyglassGrowthPatch.java new file mode 100644 index 000000000..b76a184f9 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureRubyglassGrowthPatch.java @@ -0,0 +1,122 @@ +package net.minecraft.core.world.generate.feature; + +import net.minecraft.core.block.Block; +import net.minecraft.core.block.BlockLogicGrowthRubyglass; +import net.minecraft.core.block.BlockLogicRotatable; +import net.minecraft.core.block.Blocks; +import net.minecraft.core.util.helper.Direction; +import net.minecraft.core.util.helper.Side; +import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; + +import java.util.Random; + +public class WorldFeatureRubyglassGrowthPatch implements WorldFeatureInterface { + + private final float tallGrowthChance; + + private final TilePos scratchPos = new TilePos(); + private final TilePos scratchSupportPos = new TilePos(); + private final TilePos scratchOutwardPos = new TilePos(); + private final TilePos scratchCubeQueryPos = new TilePos(); + + /** + * Generates a mixed patch with a 60% chance for buds to grow into 2-tall crystals. + */ + public WorldFeatureRubyglassGrowthPatch() { + this(0.6F); + } + + /** + * Generates a configurable Rubyglass patch. + * @param tallGrowthChance The chance (0.0F to 1.0F) that a crystal will attempt to grow 2 blocks tall. + * Set to 0 to generate only buds. + */ + public WorldFeatureRubyglassGrowthPatch(float tallGrowthChance) { + this.tallGrowthChance = tallGrowthChance; + } + + @Override + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePos) { + // Cache the static side array; Side.values() allocates a fresh array on every call. + final Side[] sides = Side.sides; + + for(int i1 = 0; i1 < 20; i1++) { + int x1 = (tilePos.x() + random.nextInt(4)) - random.nextInt(4); + int y1 = (tilePos.y() + random.nextInt(4)) - random.nextInt(4); + int z1 = (tilePos.z() + random.nextInt(4)) - random.nextInt(4); + + final TilePos pos = this.scratchPos.set(x1, y1, z1); + + if (!world.isAirBlock(pos)) { + continue; + } + + for (int s = 0, n = sides.length; s < n; s++) { + final Side side = sides[s]; + final Direction growthDir = side.direction(); + pos.add(growthDir.opposite(), this.scratchSupportPos); + + if (!this.isValidSupport(world, this.scratchSupportPos)) { + continue; + } + + int rot = BlockLogicRotatable.setDirection(0, growthDir); + pos.add(growthDir, this.scratchOutwardPos); + + if (this.tallGrowthChance > 0.0F && world.isAirBlock(this.scratchOutwardPos) && random.nextFloat() < this.tallGrowthChance) { + world.setBlockTypeData(pos, Blocks.RUBYGLASS_GROWTH, BlockLogicGrowthRubyglass.STATE_BOTTOM | rot); + world.setBlockTypeData(this.scratchOutwardPos, Blocks.RUBYGLASS_GROWTH, BlockLogicGrowthRubyglass.STATE_TOP | rot); + } else { + world.setBlockTypeData(pos, Blocks.RUBYGLASS_GROWTH, BlockLogicGrowthRubyglass.STATE_BUD | rot); + } + + break; + } + } + return true; + } + + /** + * Determines if the growth is allowed to attach to the given block. + */ + private boolean isValidSupport(@NotNull World world, TilePos pos) { + if (!world.isBlockNormalCube(pos)) { + return false; + } + + Block block = world.getBlockType(pos); + + if (block == Blocks.RUBYGLASS_GROWTH) { + return false; + } + + if (block == Blocks.RUBYGLASS_COLUMN || + block == Blocks.RUBYGLASS_NODE || + block == Blocks.COBBLE_NETHERRACK_CRYSTALLINE) { + return true; + } + + if (block == Blocks.COBBLE_NETHERRACK) { + final TilePos checkPos = this.scratchCubeQueryPos; + final int px = pos.x(); + final int py = pos.y(); + final int pz = pos.z(); + + for (int x = -1; x <= 1; x++) { + for (int y = -1; y <= 1; y++) { + for (int z = -1; z <= 1; z++) { + checkPos.set(px + x, py + y, pz + z); + if (world.getBlockType(checkPos) == Blocks.COBBLE_NETHERRACK_CRYSTALLINE) { + return true; + } + } + } + } + } + + return false; + } +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureRubyglassSproutPatch.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureRubyglassSproutPatch.java deleted file mode 100644 index 9eca06b81..000000000 --- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureRubyglassSproutPatch.java +++ /dev/null @@ -1,36 +0,0 @@ -package net.minecraft.core.world.generate.feature; - -import net.minecraft.core.block.BlockLogicRubyglassSprout; -import net.minecraft.core.block.Blocks; -import net.minecraft.core.world.World; -import net.minecraft.core.world.pos.TilePos; - -import java.util.Random; - -public class WorldFeatureRubyglassSproutPatch extends WorldFeature -{ - private final int blockId; - - public WorldFeatureRubyglassSproutPatch() - { - this.blockId = Blocks.RUBYGLASS_SPROUT.id(); - } - - @Override - public boolean place(World world, Random random, int x, int y, int z) - { - for(int i1 = 0; i1 < 20; i1++) - { - int x1 = (x + random.nextInt(4)) - random.nextInt(4); - int y1 = (y + random.nextInt(4)) - random.nextInt(4); - int z1 = (z + random.nextInt(4)) - random.nextInt(4); - if(world.isAirBlock(x1, y1, z1) && Blocks.blocksList[blockId].canBlockStay(world, x1, y1, z1)) - { - world.setBlock(x1, y1, z1, blockId); - BlockLogicRubyglassSprout.setDefaultDirection(world, new TilePos(x1, y1, z1)); - } - } - - return true; - } -} diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureSoulCatcherPatch.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureSoulCatcherPatch.java new file mode 100644 index 000000000..4d9ab4857 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureSoulCatcherPatch.java @@ -0,0 +1,53 @@ +package net.minecraft.core.world.generate.feature; + +import net.minecraft.core.block.Blocks; +import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; + +import java.util.Random; + +public class WorldFeatureSoulCatcherPatch implements WorldFeatureInterface { + private static final int SOULSAND_ATTEMPTS = 28; + private static final int OTHER_ATTEMPTS = 6; + private static final int SPORADIC_CHANCE_DENOM = 5; + private static final int OFFSET_RAND_BOUND = 3; + + private final TilePos scratchGround = new TilePos(); + private final TilePos scratchQuery = new TilePos(); + private final TilePos scratchBelow = new TilePos(); + + @Override + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePos) { + final TilePos ground = this.scratchGround.set(tilePos.x(), tilePos.y(), tilePos.z()); + while (world.isAirBlock(ground) && ground.y() > 0) { + ground.down(); + } + if (ground.y() <= 0) { return false; } + + final boolean seedOnSoulSand = world.getBlockType(ground) == Blocks.SOULSAND; + final int attempts = seedOnSoulSand ? SOULSAND_ATTEMPTS : OTHER_ATTEMPTS; + + for (int i = 0; i < attempts; i++) { + final int qx = ground.x() + random.nextInt(OFFSET_RAND_BOUND) - random.nextInt(OFFSET_RAND_BOUND); + final int qy = ground.y() + 1 + random.nextInt(2) - random.nextInt(2); + final int qz = ground.z() + random.nextInt(OFFSET_RAND_BOUND) - random.nextInt(OFFSET_RAND_BOUND); + this.scratchQuery.set(qx, qy, qz); + + if (!world.isAirBlock(this.scratchQuery)) { continue; } + + this.scratchBelow.set(qx, qy - 1, qz); + final boolean overSoulSand = world.getBlockType(this.scratchBelow) == Blocks.SOULSAND; + + if (!overSoulSand && random.nextInt(SPORADIC_CHANCE_DENOM) != 0) { + continue; + } + + if (Blocks.SOUL_CATCHER.canStay(world, this.scratchQuery)) { + world.setBlockType(this.scratchQuery, Blocks.SOUL_CATCHER); + } + } + return true; + } +} diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureSpeleothems.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureSpeleothems.java deleted file mode 100644 index b39c1d7b7..000000000 --- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureSpeleothems.java +++ /dev/null @@ -1,177 +0,0 @@ -package net.minecraft.core.world.generate.feature; - -import net.minecraft.core.block.Block; -import net.minecraft.core.block.Blocks; -import net.minecraft.core.util.helper.MathHelper; -import net.minecraft.core.world.World; -import net.minecraft.core.world.pos.TilePos; -import net.minecraft.core.world.pos.TilePosc; -import org.jetbrains.annotations.NotNull; - -import java.util.Random; - -public class WorldFeatureSpeleothems extends WorldFeature { - protected final int maxRadius; - protected final boolean generateBottom; - protected final int maxHeight; - protected final boolean checkDepth; - - public WorldFeatureSpeleothems(final int maxRadius, final boolean generateBottom, final int maxHeight, final boolean checkDepth) { - this.maxRadius = maxRadius; - this.generateBottom = generateBottom; - this.maxHeight = maxHeight; - this.checkDepth = checkDepth; - } - - @Override - public boolean place(final @NotNull World world, final @NotNull Random random, int x, int y, int z) { - final @NotNull TilePosc tilePos = new TilePos(x, y, z); - final @NotNull TilePos queryPos = new TilePos(); - - final @NotNull Block baseBlock = Blocks.COBBLE_NETHERRACK; - - if (world.getBlockType(tilePos) == Blocks.AIR) { - tilePos.up(queryPos); - if (world.getBlockType(queryPos) != Blocks.AIR) { - y = y + 1; - } else - return false; - - } - - final int radius = random.nextInt(this.maxRadius) + this.maxRadius; // Radius 5-10 - final int depth = radius * 2; - - // Check we have enough space underneath proportionally to our radius - if (this.checkDepth) { - for (int i = y - 1; i > y - depth; i--) { - queryPos.set(x, i, z); - if (world.getBlockType(queryPos) != Blocks.AIR) { - return false; - } - } - } - - // Determine the number of base blocks we need to generate - final int numBaseBlocks = (radius * 2) * (radius * 2); - - for (int i = 0; i < numBaseBlocks; i++) { - // Determine our base block's location - final int dx = radius - random.nextInt(radius * 2); - int dy = 0; - final int dz = radius - random.nextInt(radius * 2); - - if (world.getBlockType(queryPos.set(x + dx, y, z + dz)) == baseBlock) { - continue; - } - - int distance = dx * dz; - - // Make sure our distance is never 0 - if (distance == 0) { - if (dx == 0 && dz == 0) { - distance = 1; - } else if (dx == 0) { - distance = dz; - } else if (dz == 0) { - distance = dx; - } - } - - // Bias so we're more likely to generate base blocks closer to the middle - if (random.nextInt(Math.abs(distance)) != 0) { - i--; - continue; - } - - // Move up one block if needed - if (world.getBlockType(queryPos.set(x + dx, y, z + dz)) == Blocks.AIR) { - dy = 1; - if (world.getBlockType(queryPos.set(x + dx, y + 1, z + dz)) == Blocks.AIR) { - continue; - } - } - - // Move down one block if needed - if (world.getBlockType(queryPos.set(x + dx, y - 1, z + dz)) != Blocks.AIR) { - dy = -1; - if (world.getBlockType(queryPos.set(x + dx, y - 2, z + dz)) != Blocks.AIR) { - continue; - } - } - - // Set base block - world.setBlockTypeNotify(queryPos.set(x + dx, y + dy, z + dz), baseBlock); - - // Generate stalactite - if (random.nextInt(5) == 0) { - int height = random.nextInt(depth - radius - 1) + 1; // 2-12 - - if (this.maxHeight > -1 && height > this.maxHeight) { - height = this.maxHeight; - } - this.placeSpeleothem(world, queryPos.set(x + dx, y + dy, z + dz), height); - - // Possibly generate stalagmite - if (this.generateBottom) { - if (random.nextInt(3) == 0) { - int bottom = -1; - - for (int j = height + 1; j < depth * 2; j++) { - if (world.getBlockType(queryPos.set(x + dx, y + dy - j, z + dz)) != Blocks.AIR) { - bottom = y + dy - j; - break; - } - } - - if (bottom != -1 && world.getBlockType(queryPos.set(x + dx, bottom - 1, z + dz)).solid()) { - this.placeSpeleothem(world, queryPos.set(x + dx, bottom, z + dz), -height / 2); - } - } - } - } - } - - return true; - } - - private boolean placeSpeleothem(final @NotNull World world, final @NotNull TilePosc pos, final int height) { - if (height == 0) { - return false; - } - - final @NotNull Block block = Blocks.FLOWSTONE; - - final @NotNull TilePos queryPos = new TilePos(pos); - final int absHeight = Math.abs(height); - final int dy = height < 0 ? 1 : -1; - - // Check space is clear - for (int i = 0; i < absHeight; i++) { - queryPos.y += dy; - if (world.getBlockType(queryPos) != Blocks.AIR) { - return false; - } - } - - // Handle edge cases first so we get nice-looking short speleothems - queryPos.set(pos); - if (absHeight <= 4) { - int data = 4 - absHeight; - for (int i = 0; i < absHeight; i++) { - queryPos.y += dy; - world.setBlockTypeData(queryPos, block, data); - data++; - } - } else { - for (int i = 0; i < absHeight; i++) { - final float progress = (float) i / (float) absHeight; - final int data = (int) (progress * 4); - queryPos.y += dy; - world.setBlockTypeData(queryPos, block, data); - } - } - - return true; - } -} diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureSpireVent.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureSpireVent.java new file mode 100644 index 000000000..fd316d6fb --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureSpireVent.java @@ -0,0 +1,92 @@ +package net.minecraft.core.world.generate.feature; + +import net.minecraft.core.block.Blocks; +import net.minecraft.core.block.tag.BlockTags; +import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; +import org.joml.Vector3i; + +import java.util.Random; + +public class WorldFeatureSpireVent implements WorldFeatureInterface{ + + /** + * Maximum vertical drop allowed when scanning down for a placement surface. + * Caps the cost of feature placement when called inside large open caves. + */ + private static final int MAX_DOWN_SCAN = 64; + + @Override + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePosc) { + if (!world.isAirBlock(tilePosc)) { + return false; + } + + TilePos tilePos = new TilePos(tilePosc.x(), tilePosc.y(), tilePosc.z()); + + int scanned = 0; + while(world.isAirBlock(tilePos) && tilePos.y() - 1 > 0 && scanned < MAX_DOWN_SCAN) { + tilePos.down(); + scanned++; + } + + if (!world.getBlockType(tilePos).hasTag(BlockTags.NETHER_SURFACE_BLOCK)) { + return false; + } + + if (hasSpace(world, tilePos.x(), tilePos.y(), tilePos.z())) { + + Vector3i highestOffset = new Vector3i(0, 0, 0); + TilePos centerPos = new TilePos(tilePos.x(), tilePos.y(), tilePos.z()); + TilePos queryPos = new TilePos(); + + for (int x1 = 0; x1 < 2; x1++) { + for (int z1 = 0; z1 < 2; z1++) { + int height = random.nextInt(6) + 4; + if(height > highestOffset.y) { + highestOffset.set(x1, height, z1); + } + + // Bottom third of each column gets scattered nethercoal ore. + int oreRange = Math.max(1, height / 3); + + for(int y1 = 0; y1 < height; y1++){ + centerPos.add(x1, y1, z1, queryPos); + if (y1 < oreRange && random.nextInt(2) == 0) { + world.setBlockType(queryPos, Blocks.ORE_NETHERCOAL_BASALT); + } else { + world.setBlockType(queryPos, Blocks.BASALT); + } + } + } + } + + for(int y1 = 0; y1 < 2; y1++){ + centerPos.add(highestOffset.x, highestOffset.y + y1, highestOffset.z, queryPos); + world.setBlockType(queryPos, Blocks.THERMAL_VENT); + } + + return true; + } + + return false; + } + + private boolean hasSpace(World world, int xc, int y, int zc){ + TilePos queryPos = new TilePos(); + + for (queryPos.y = y + 1; queryPos.y < y + 5; queryPos.y++) { + for (queryPos.x = xc; queryPos.x < xc + 2; queryPos.x++) { + for (queryPos.z = zc; queryPos.z < zc + 2; queryPos.z++) { + if (!world.isAirBlock(queryPos)) { + return false; + } + } + } + } + return true; + } + +} diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureThermalSpire.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureThermalSpire.java deleted file mode 100644 index d3d03df70..000000000 --- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureThermalSpire.java +++ /dev/null @@ -1,63 +0,0 @@ -package net.minecraft.core.world.generate.feature; - -import net.minecraft.core.block.Block; -import net.minecraft.core.block.Blocks; -import net.minecraft.core.block.tag.BlockTags; -import net.minecraft.core.world.World; -import net.minecraft.core.world.pos.TilePos; -import org.joml.Vector2i; -import org.joml.Vector3i; -import org.joml.Vector3ic; - -import java.util.Random; - -public class WorldFeatureThermalSpire extends WorldFeature{ - @Override - public boolean place(World world, Random random, int x, int y, int z) { - TilePos pos = new TilePos(x, y, z); - while(world.isAirBlock(pos) && pos.y - 1 > 0) {pos.down(); } - if (hasSpace(world, pos.x, pos.y, pos.z)) { - - Vector3i highestOffset = new Vector3i(0, 0, 0); - TilePos centerPos = new TilePos(pos.x, pos.y, pos.z); - TilePos queryPos = new TilePos(); - - for (int x1 = 0; x1 < 2; x1++) { - for (int z1 = 0; z1 < 2; z1++) { - int height = random.nextInt(6) + 4; - if(height > highestOffset.y) { - highestOffset.set(x1, height, z1); - } - - for(int y1 = 0; y1 < height; y1++){ - centerPos.add(x1, y1, z1, queryPos); - world.setBlockType(queryPos, Blocks.BASALT); - } - } - } - - for(int y1 = 0; y1 < 2; y1++){ - centerPos.add(highestOffset.x, highestOffset.y + y1, highestOffset.z, queryPos); - world.setBlockType(queryPos, Blocks.BASALT); - } - } - - - return true; - } - - private boolean hasSpace(World world, int xc, int y, int zc){ - TilePos queryPos = new TilePos(); - for (queryPos.y = y - 3; queryPos.y < y + 3; queryPos.y++) { - for (queryPos.x = xc - 3; queryPos.x < xc + 3; queryPos.x++) { - for (queryPos.z = zc - 3; queryPos.z < zc + 3; queryPos.z++) { - if (!world.isAirBlock(queryPos) && !world.getBlockType(queryPos).hasTag(BlockTags.NETHER_SURFACE_BLOCK)) - return false; - } - } - } - return true; - } - - -} diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureChimney.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureThermalVent.java similarity index 98% rename from game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureChimney.java rename to game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureThermalVent.java index c895b7b97..be95987e0 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureChimney.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureThermalVent.java @@ -9,7 +9,7 @@ import org.joml.Vector2i; import java.util.Random; -public class WorldFeatureChimney extends WorldFeature{ +public class WorldFeatureThermalVent extends WorldFeature{ final double[][] RADIUS_MAPS = { {1.5D, 1.5D, 1D, 1D, 0D, 0D}, diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureWallClump.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureWallClump.java new file mode 100644 index 000000000..a4303ab4e --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureWallClump.java @@ -0,0 +1,78 @@ +package net.minecraft.core.world.generate.feature; + +import net.minecraft.core.block.Block; +import net.minecraft.core.util.helper.Direction; +import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; + +import java.util.Random; + +public class WorldFeatureWallClump implements WorldFeatureInterface { + private final Block placeBlock; + private final Block targetBlock; + private final int maxClumpSize; + + public WorldFeatureWallClump(Block placeBlock, Block targetBlock, int maxClumpSize) { + this.placeBlock = placeBlock; + this.targetBlock = targetBlock; + this.maxClumpSize = maxClumpSize; + } + + @Override + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePos) { + + if (world.getBlockType(tilePos) != this.targetBlock) { + return false; + } + + TilePos checkPos = new TilePos(); + if (!hasAirNeighbor(world, tilePos, checkPos)) { + return false; + } + + TilePos currentPos = new TilePos(); + currentPos.set(tilePos); + + world.setBlockType(currentPos, this.placeBlock); + int blocksPlaced = 1; + + TilePos nextPos = new TilePos(); + final Direction[] directions = Direction.ID_MAP; + + for (int i = 0; i < this.maxClumpSize * 2 && blocksPlaced < this.maxClumpSize; i++) { + Direction dir = directions[random.nextInt(directions.length)]; + nextPos.set(currentPos).add(dir); + + if (isValid(world, nextPos, checkPos)) { + world.setBlockType(nextPos, this.placeBlock); + currentPos.set(nextPos); + blocksPlaced++; + } + } + + return true; + } + + /** + * Checks if the position is the target block AND is exposed to air on at least one side. + * Reuses checkPos to prevent memory allocation in loops. + */ + private boolean isValid(@NotNull World world, TilePosc pos, TilePos checkPos) { + if (world.getBlockType(pos) != this.targetBlock) { + return false; + } + return hasAirNeighbor(world, pos, checkPos); + } + + private boolean hasAirNeighbor(@NotNull World world, TilePosc pos, TilePos checkPos) { + final Direction[] directions = Direction.ID_MAP; + for (int d = 0, n = directions.length; d < n; d++) { + if (world.isAirBlock(checkPos.set(pos).add(directions[d]))) { + return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/hanging/WorldFeatureHangingDungeon.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/hanging/WorldFeatureHangingDungeon.java new file mode 100644 index 000000000..ff627fae1 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/hanging/WorldFeatureHangingDungeon.java @@ -0,0 +1,198 @@ +package net.minecraft.core.world.generate.feature.hanging; + +import net.minecraft.core.block.Blocks; +import net.minecraft.core.WeightedRandomBag; +import net.minecraft.core.WeightedRandomLootObject; +import net.minecraft.core.block.Block; +import net.minecraft.core.item.Item; +import net.minecraft.core.item.ItemStack; +import net.minecraft.core.item.Items; +import net.minecraft.core.world.World; +import net.minecraft.core.world.generate.feature.WorldFeatureInterface; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; + + +import java.util.Random; + +public class WorldFeatureHangingDungeon { + + public static final WeightedRandomBag lootNormal = new WeightedRandomBag<>(); + + static { + lootNormal.addEntry(new WeightedRandomLootObject(Items.INGOT_STEEL_CRUDE.getDefaultStack(), 1, 6), 50.0F); + lootNormal.addEntry(new WeightedRandomLootObject(Items.FOOD_APPLE_GOLD.getDefaultStack()), 3.0F); + lootNormal.addEntry(new WeightedRandomLootObject(Items.DUST_REDSTONE.getDefaultStack(), 6, 24), 100.0F); + lootNormal.addEntry(new WeightedRandomLootObject(Items.DUST_GLOWSTONE.getDefaultStack(), 6, 24), 100.0F); + lootNormal.addEntry(new WeightedRandomLootObject(Items.NETHERCOAL.getDefaultStack(), 3, 9), 100.0F); + lootNormal.addEntry(new WeightedRandomLootObject(Blocks.TNT.getDefaultStack(), 4, 12), 50.0F); + lootNormal.addEntry(new WeightedRandomLootObject(Blocks.RAIL.getDefaultStack(), 12, 32), 50.0F); + lootNormal.addEntry(new WeightedRandomLootObject(Blocks.RAIL_POWERED.getDefaultStack(), 9, 16), 50.0F); + lootNormal.addEntry(new WeightedRandomLootObject(Items.INGOT_GOLD.getDefaultStack(), 5, 8), 100.0F); + lootNormal.addEntry(new WeightedRandomLootObject(Items.INGOT_IRON.getDefaultStack(), 5, 10), 100.0F); + + for (int i = 0; i < 9; ++i) { + lootNormal.addEntry(new WeightedRandomLootObject(new ItemStack(Item.itemsList[Items.RECORD_13.id + i]), 1), 1.0F); + } + + lootNormal.addEntry(new WeightedRandomLootObject(Blocks.PUMICE_DRY.getDefaultStack(), 2, 7), 100.0F); + lootNormal.addEntry(new WeightedRandomLootObject(Items.BONE.getDefaultStack(), 2, 7), 100.0F); + lootNormal.addEntry(new WeightedRandomLootObject(null), 180.0F); + } + + + public static class RandomType implements WorldFeatureInterface { + private final WorldFeatureInterface[] features; + + public RandomType() { + this.features = new WorldFeatureInterface[] { + new Basalt(), + new Slate(), + new Gloomstone(), + new Netherrack() + }; + } + + @Override + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePosc) { + int index = random.nextInt(features.length); + return features[index].place(world, random, tilePosc); + } + } + + public static class Basalt implements WorldFeatureInterface { + private static final WeightedRandomBag> hangingDungeonBase = new WeightedRandomBag<>(); + + static { + hangingDungeonBase.addEntry(Blocks.BRICK_BASALT, 1); + hangingDungeonBase.addEntry(Blocks.BASALT_CARVED, .75); + hangingDungeonBase.addEntry(Blocks.BASALT_POLISHED, .10); + } + + private static final WeightedRandomBag> hangingDungeonRope = new WeightedRandomBag<>(); + + static { + hangingDungeonRope.addEntry(Blocks.ROPE, 1); + } + + private static final WorldFeatureInterface dungeon = new WorldFeatureHangingDungeonBase( + 7, + 32, + 10, + 6, + hangingDungeonBase, hangingDungeonRope, + lootNormal + ); + + public Basalt() { + } + + @Override + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePosc) { + return dungeon.place(world, random, tilePosc); + } + + } + + public static class Slate implements WorldFeatureInterface { + private static final WeightedRandomBag> hangingDungeonBase = new WeightedRandomBag<>(); + + static { + hangingDungeonBase.addEntry(Blocks.BRICK_SLATE, 1); + hangingDungeonBase.addEntry(Blocks.SLATE_POLISHED, .75); + hangingDungeonBase.addEntry(Blocks.SLATE_CARVED, .10); + } + + private static final WeightedRandomBag> hangingDungeonRope = new WeightedRandomBag<>(); + + static { + hangingDungeonRope.addEntry(Blocks.ROPE, 1); + } + + private static final WorldFeatureInterface dungeon = new WorldFeatureHangingDungeonBase( + 7, + 32, + 10, + 6, + hangingDungeonBase, hangingDungeonRope, + lootNormal + ); + + public Slate() { + } + + @Override + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePosc) { + return dungeon.place(world, random, tilePosc); + } + + } + + public static class Gloomstone implements WorldFeatureInterface { + private static final WeightedRandomBag> hangingDungeonBase = new WeightedRandomBag<>(); + + static { + hangingDungeonBase.addEntry(Blocks.BRICK_GLOOMSTONE, 1); + hangingDungeonBase.addEntry(Blocks.GLOOMSTONE_CARVED, .75); + hangingDungeonBase.addEntry(Blocks.GLOOMSTONE_POLISHED, .10); + } + + private static final WeightedRandomBag> hangingDungeonRope = new WeightedRandomBag<>(); + + static { + hangingDungeonRope.addEntry(Blocks.ROPE, 1); + } + + private static final WorldFeatureInterface dungeon = new WorldFeatureHangingDungeonBase( + 7, + 32, + 10, + 6, + hangingDungeonBase, hangingDungeonRope, + lootNormal + ); + + public Gloomstone() { + } + + @Override + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePosc) { + return dungeon.place(world, random, tilePosc); + } + + } + + public static class Netherrack implements WorldFeatureInterface { + private static final WeightedRandomBag> hangingDungeonBase = new WeightedRandomBag<>(); + + static { + hangingDungeonBase.addEntry(Blocks.BRICK_NETHERRACK, 1); + hangingDungeonBase.addEntry(Blocks.NETHERRACK_CARVED, .75); + hangingDungeonBase.addEntry(Blocks.NETHERRACK_POLISHED, .10); + } + + private static final WeightedRandomBag> hangingDungeonRope = new WeightedRandomBag<>(); + + static { + hangingDungeonRope.addEntry(Blocks.ROPE, 1); + } + + private static final WorldFeatureInterface dungeon = new WorldFeatureHangingDungeonBase( + 7, + 32, + 10, + 6, + hangingDungeonBase, hangingDungeonRope, + lootNormal + ); + + public Netherrack() { + } + + @Override + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePosc) { + return dungeon.place(world, random, tilePosc); + } + + } +} diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/hanging/WorldFeatureHangingDungeonBase.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/hanging/WorldFeatureHangingDungeonBase.java new file mode 100644 index 000000000..0e97f2f0a --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/hanging/WorldFeatureHangingDungeonBase.java @@ -0,0 +1,162 @@ +package net.minecraft.core.world.generate.feature.hanging; + +import net.minecraft.core.block.Blocks; +import net.minecraft.core.WeightedRandomBag; +import net.minecraft.core.WeightedRandomLootObject; +import net.minecraft.core.block.Block; +import net.minecraft.core.block.entity.TileEntityChest; +import net.minecraft.core.block.entity.TileEntityMobSpawner; +import net.minecraft.core.util.helper.DyeColor; +import net.minecraft.core.util.helper.MathHelper; +import net.minecraft.core.world.World; +import net.minecraft.core.world.generate.feature.WorldFeatureInterface; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; +import org.joml.Vector2d; + + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Random; + +public record WorldFeatureHangingDungeonBase( + int size, int maxDrop, int minDrop, int clumping, + WeightedRandomBag> base, WeightedRandomBag> ropes, + WeightedRandomBag lootTable) implements WorldFeatureInterface { + + public WorldFeatureHangingDungeonBase { + assert size >= 7; + // You don't want less than 7 because it will look ass. + + assert size % 2 != 0; + // You don't want an even number because the spawner will be crooked. + + } + + @Override + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePosc) { + // 1. find the highest block from current Y. + // 2. check of an empty column on the 4 corners + // 3. place all ropes to a random height + // 4. fill platform + + final TilePos[] corners = { + new TilePos(tilePosc.x(), tilePosc.y(), tilePosc.z()), + new TilePos(tilePosc.x() + this.size - 1, tilePosc.y(), tilePosc.z()), + new TilePos(tilePosc.x(), tilePosc.y(), tilePosc.z() + this.size - 1), + new TilePos(tilePosc.x() + this.size - 1, tilePosc.y(), tilePosc.z() + this.size - 1), + }; + + for (TilePos tilePos : corners) { + for (int currY = tilePos.y(); currY < world.getWorldType().getMaxY(world); currY++) { + if (currY > world.getWorldType().getMaxY(world)) { + return false; + } + + var block = new TilePos(tilePos); + block.y = currY; + + if (world.getBlockType(block).solid()) { + tilePos.y = currY; + break; + } + } + } + + int minMaxHeight = Arrays.stream(corners).map(TilePos::y).min(Integer::compareTo).get(); + int maxMaxHeight = Arrays.stream(corners).map(TilePos::y).max(Integer::compareTo).get(); + + if (minMaxHeight - tilePosc.y() < this.minDrop) { + return false; + } + + var minHeight = minMaxHeight - MathHelper.clamp(random.nextInt(minMaxHeight - tilePosc.y()), this.minDrop, this.maxDrop); + + if (maxMaxHeight - minHeight > this.maxDrop * 2) { + return false; + } + + for (TilePos corner : corners) { + for (int y = minHeight; y < corner.y(); y++) { + var block = new TilePos(corner); + block.y = y; + + var variant = ropes.getRandom(random); + world.setBlockTypeDataNotify(block, variant, 0); + } + } + + for (int x = corners[0].x(); x <= corners[3].x(); x++) { + for (int z = corners[0].z(); z <= corners[3].z(); z++) { + var block = new TilePos(x, minHeight, z); + var variant = base.getRandom(random); + + world.setBlockTypeData(block, variant, 0); + } + } + + for (int step = 1; step < this.size -1; step++) { + var block = new TilePos(corners[0].x() + step, minHeight + 4, corners[0].z()); + var block2 = new TilePos(corners[2].x() + step, minHeight + 4, corners[2].z()); + var block3 = new TilePos(corners[0].x(), minHeight + 4, corners[0].z() + step); + var block4 = new TilePos(corners[1].x(), minHeight + 4, corners[1].z() + step); + + var variant = ropes.getRandom(random); + var variant2 = ropes.getRandom(random); + var variant3 = ropes.getRandom(random); + var variant4 = ropes.getRandom(random); + + world.setBlockTypeNotify(block, variant); + world.setBlockTypeNotify(block2, variant2); + world.setBlockTypeNotify(block3, variant3); + world.setBlockTypeNotify(block4, variant4); + } + + final int half = this.size / 2; + var center = new TilePos(tilePosc.x() + half, minHeight + 1, tilePosc.z() + half); + + world.setBlockTypeDataNotify(center, Blocks.MOBSPAWNER, 0); + var spawner = (TileEntityMobSpawner) world.getTileEntity(center); + if (spawner != null) { + spawner.setMobId("minecraft:zombie_pigman"); + } + + final var positions = new ArrayList(); + positions.add(new TilePos(half, 0, 0)); + positions.add(new TilePos(-half, 0, 0)); + positions.add(new TilePos(0, 0, half)); + positions.add(new TilePos(0, 0, -half)); + + for (int ii = 0; ii < 2; ii++) { + var chestPos = positions.remove(random.nextInt(positions.size() - 1)); + chestPos.add(center.x(), center.y(), center.z()); + + world.setBlockTypeData(chestPos, Blocks.CHEST_PLANKS_OAK_PAINTED, DyeColor.RED.blockMeta * 16 + random.nextInt(3)); + + var chest = (TileEntityChest) world.getTileEntity(chestPos); + + if (chest != null) { + for (int i = 0; i < 3 + random.nextInt(8); i++) { + chest.setItem((int) Math.floor(chest.getContainerSize() * random.nextFloat()), this.lootTable.getRandom(random).getItemStack(random)); + } + } + } + + if (random.nextInt(clumping) == 0) { + var vec2 = new Vector2d(1, 0) + .mul(MathHelper.rotateVec2(Math.PI * 2 * random.nextFloat())) + .mul(this.size * 2 + (this.size * random.nextFloat())); + + var block = new TilePos( + tilePosc.x() + Math.floor(vec2.x()), + tilePosc.y() - 2 + random.nextInt(5), + tilePosc.z() + Math.floor(vec2.y()) + ); + + this.place(world, random, block); + } + + return true; + } +} diff --git a/game/core/src/main/java/net/minecraft/core/world/lighting/LightingEngineLegacy.java b/game/core/src/main/java/net/minecraft/core/world/lighting/LightingEngineLegacy.java index f6847acde..98c8d6e15 100644 --- a/game/core/src/main/java/net/minecraft/core/world/lighting/LightingEngineLegacy.java +++ b/game/core/src/main/java/net/minecraft/core/world/lighting/LightingEngineLegacy.java @@ -26,26 +26,33 @@ public class LightingEngineLegacy implements LightingEngine { @Override public boolean updatingLighting() { - if(this.lightingUpdatesCounter >= 50) - { + if(this.lightingUpdatesCounter >= 50) { return false; } this.lightingUpdatesCounter++; - try - { - for (int i = 499; !this.lightingToUpdate.isEmpty() && i >= 0; i--) - { + try { + // Why was this changed? During the development of 8.0, after adding many light sources to the nether, + // the lighting propagation/updates were getting caught up, and needed to be adjusted/upgraded + + // Lighting updates are allowed to take up 7% of the tick budget max + final long timeBudgetNanos = 3_000_000L; + final long startTime = System.nanoTime(); + int processed = 0; + + while (!this.lightingToUpdate.isEmpty()) { this.lightingToUpdate.remove(this.lightingToUpdate.size() - 1).performLightUpdate(this, this.world); - if (i == 0) - { - return true; + processed++; + + // Check the clock every 64 updates + if (processed % 64 == 0) { + if (System.nanoTime() - startTime > timeBudgetNanos) { + return true; // cut it short + } } } - return false; - } - finally - { + return false; // emptied the queue + } finally { this.lightingUpdatesCounter--; } } @@ -80,9 +87,9 @@ public class LightingEngineLegacy implements LightingEngine { } int numLightingUpdates = this.lightingToUpdate.size(); - if(numLightingUpdates > 5) - { - numLightingUpdates = 5; + + if(numLightingUpdates > 12) { + numLightingUpdates = 12; } for(int i = 0; i < numLightingUpdates; i++) diff --git a/game/core/src/main/java/net/minecraft/core/world/particle/ParticleEmitterRange.java b/game/core/src/main/java/net/minecraft/core/world/particle/ParticleEmitterRange.java new file mode 100644 index 000000000..5ce6e423d --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/world/particle/ParticleEmitterRange.java @@ -0,0 +1,34 @@ +package net.minecraft.core.world.particle; + +public enum ParticleEmitterRange { + // BASIC fixed 16-block radius + BASIC(0.0f), + + // SHORT scales to 25% of the players' particle render distance + SHORT(0.25f), + + // MEDIUM scales to 50% + MEDIUM(0.5f), + + // FAR scales to 75% + FAR(0.75f), + + // EXTREME uses 100% + EXTREME(1.0f); + + public final float multiplier; + + ParticleEmitterRange(float multiplier) { + this.multiplier = multiplier; + } + + public double getMaxDistanceSq(int renderDistanceChunks) { + if (this == BASIC) { + return 16.0 * 16.0; + } + + double maxBlocks = (renderDistanceChunks * 16.0) * this.multiplier; + maxBlocks = Math.max(maxBlocks, 16.0); + return maxBlocks * maxBlocks; + } +} diff --git a/game/core/src/main/java/net/minecraft/core/world/particle/ParticleEmitterRegistry.java b/game/core/src/main/java/net/minecraft/core/world/particle/ParticleEmitterRegistry.java new file mode 100644 index 000000000..7e7d6b532 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/world/particle/ParticleEmitterRegistry.java @@ -0,0 +1,103 @@ +package net.minecraft.core.world.particle; + +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import net.minecraft.core.block.Block; +import net.minecraft.core.entity.player.Player; +import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.ConcurrentLinkedQueue; + +public class ParticleEmitterRegistry { + + private record EmitterNode(TilePos pos, ParticleEmitterRange type) { } + + private final Long2ObjectOpenHashMap emitters = new Long2ObjectOpenHashMap<>(); + + private final ConcurrentLinkedQueue pendingAdds = new ConcurrentLinkedQueue<>(); + private final ConcurrentLinkedQueue pendingRemoves = new ConcurrentLinkedQueue<>(); + + private long getPosHash(int x, int y, int z) { + long hash = x & 0x3FFFFFF; + hash |= ((long)(z & 0x3FFFFFF)) << 26; + hash |= ((long)(y & 0xFFF)) << 52; + return hash; + } + + public void add(TilePos pos) { + this.add(pos, ParticleEmitterRange.BASIC); + } + + public void add(@NotNull TilePos pos, ParticleEmitterRange type) { + this.pendingAdds.add(new EmitterNode(new TilePos(pos), type)); + } + + public void add(TilePosc pos) { + this.add(pos, ParticleEmitterRange.BASIC); + } + + public void add(@NotNull TilePosc pos, ParticleEmitterRange type) { + this.pendingAdds.add(new EmitterNode(new TilePos(pos), type)); + } + + public void remove(@NotNull TilePos pos) { + this.pendingRemoves.add(getPosHash(pos.x(), pos.y(), pos.z())); + } + + public void remove(@NotNull TilePosc pos) { + this.pendingRemoves.add(getPosHash(pos.x(), pos.y(), pos.z())); + } + + public void tick(World world, Player player, int renderDistanceChunks) { + while (!this.pendingRemoves.isEmpty()) { + this.emitters.remove(this.pendingRemoves.poll().longValue()); + } + while (!this.pendingAdds.isEmpty()) { + EmitterNode node = this.pendingAdds.poll(); + this.emitters.put(getPosHash(node.pos.x(), node.pos.y(), node.pos.z()), node); + } + + if (this.emitters.isEmpty()) return; + + var iterator = this.emitters.long2ObjectEntrySet().fastIterator(); + + while (iterator.hasNext()) { + Long2ObjectMap.Entry entry = iterator.next(); + EmitterNode node = entry.getValue(); + TilePos pos = node.pos; + ParticleEmitterRange type = node.type; + + if (!world.isBlockLoaded(pos)) { + iterator.remove(); + continue; + } + + double dx = pos.x() - player.x; + double dy = pos.y() - player.y; + double dz = pos.z() - player.z; + double distSq = dx * dx + dy * dy + dz * dz; + + if (distSq > type.getMaxDistanceSq(renderDistanceChunks)) continue; + + int throttle = 4; + if (distSq > 4096) { + throttle = 64; + } else if (distSq > 1024) { + throttle = 16; + } + + if (world.rand.nextInt(throttle) == 0) { + Block block = world.getBlockType(pos); + + if (block.getLogic().getParticleEmitterRange() != null) { + block.animationTick(world, pos, world.rand); + } else { + iterator.remove(); + } + } + } + } +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/world/pos/TilePos.java b/game/core/src/main/java/net/minecraft/core/world/pos/TilePos.java index 58453ec8f..303fe2ce7 100644 --- a/game/core/src/main/java/net/minecraft/core/world/pos/TilePos.java +++ b/game/core/src/main/java/net/minecraft/core/world/pos/TilePos.java @@ -115,6 +115,20 @@ public final class TilePos implements Externalizable, Cloneable, TilePosc { return this; } + public @NotNull TilePos set(final double x, final double y, final double z) { + this.x = (int) Math.floor(x); + this.y = (int) Math.floor(y); + this.z = (int) Math.floor(z); + return this; + } + + public @NotNull TilePos set(final float x, final float y, final float z) { + this.x = (int) Math.floor(x); + this.y = (int) Math.floor(y); + this.z = (int) Math.floor(z); + return this; + } + public @NotNull TilePos set(final @NotNull TilePosc pos) { this.x = pos.x(); this.y = pos.y(); diff --git a/game/core/src/main/resources/assets/minecraft/lang/en_US/gamerules.lang b/game/core/src/main/resources/assets/minecraft/lang/en_US/gamerules.lang index e760fb69a..48e921839 100644 --- a/game/core/src/main/resources/assets/minecraft/lang/en_US/gamerules.lang +++ b/game/core/src/main/resources/assets/minecraft/lang/en_US/gamerules.lang @@ -22,6 +22,8 @@ gamerule.do_fire_spread.name=Fire Spread gamerule.do_fire_spread.desc=If disabled, fire will not spread. gamerule.instant_healing.name=Instant Healing from Food gamerule.instant_healing.desc=If enabled, food will heal the player instantly as it did in older versions of BTA!. +gamerule.acid_melt_rate.name=Acid Melt Rate +gamerule.acid_melt_rate.desc=Ticks between each acid bank tick, durability melt, and post-exit drain pulse. Default matches fire damage (every 20 ticks). Lower values run faster. gamerule.random_tick_speed.name=Random Tick Rate gamerule.random_tick_speed.desc=Determines how many blocks are randomly ticked per game tick. gamerule.dropped_item_despawn_delay.name=Dropped Item Despawn Delay diff --git a/game/core/src/main/resources/assets/minecraft/lang/en_US/item.lang b/game/core/src/main/resources/assets/minecraft/lang/en_US/item.lang index 939eabe0b..fe9875735 100644 --- a/game/core/src/main/resources/assets/minecraft/lang/en_US/item.lang +++ b/game/core/src/main/resources/assets/minecraft/lang/en_US/item.lang @@ -490,28 +490,23 @@ item.jar.butterfly.silver.name=Silver Butterfly Jar item.jar.butterfly.silver.desc=A glass jar containing a silver butterfly. item.statue.stone.name=Stone Statue -item.statue.stone.desc=A decorative stone statue for you to hang your armor. +item.statue.stone.desc=A decorative statue carved out of stone. item.statue.basalt.name=Basalt Statue -item.statue.basalt.desc=A decorative basalt statue for you to hang your armor. +item.statue.basalt.desc=A decorative statue carved out of basalt. item.statue.limestone.name=Limestone Statue -item.statue.limestone.desc=A decorative limestone statue for you to hang your armor. +item.statue.limestone.desc=A decorative statue carved out of limestone. item.statue.granite.name=Granite Statue -item.statue.granite.desc=A decorative granite statue for you to hang your armor. +item.statue.granite.desc=A decorative statue carved out of granite. item.statue.marble.name=Marble Statue -item.statue.marble.desc=A decorative marble statue for you to hang your armor. +item.statue.marble.desc=A decorative statue carved out of marble. item.statue.pigman.name=Pigman Statue item.statue.pigman.desc=An ancient marble statue found in a long-forgotten place. item.dough.name=Dough item.dough.desc=Uncooked dough. Can be baked into bread. -item.rubyglass.crystal.cracked.name=Rubyglass Shards -item.rubyglass.crystal.cracked.desc=Cracked and full of impurities. But still aesthetically pleasing. -item.rubyglass.crystal.pure.name=Rubyglass -item.rubyglass.crystal.pure.desc=A shard of charged Rubyglass crystal, brimming with energy. - -item.sulfur.name=Sulfur -item.sulfur.desc=Highly flammable and yellow. Packs a punch. +item.rubyglass.name=Rubyglass +item.rubyglass.desc=A shard of charged rubyglass, brimming with energy. item.armor.wolf.leather.name=Leather Wolf Armor item.armor.wolf.leather.desc=Keep your best friend safe with this soft leather shell. @@ -525,3 +520,62 @@ item.armor.wolf.gold.name=Gold Wolf Armor item.armor.wolf.gold.desc=Keep your best friend fabulous with this shiny gold shell. item.armor.wolf.steel.name=Steel Wolf Armor item.armor.wolf.steel.desc=Keep your best friend safe with this sturdy steel shell. + + +item.paintbrush.black.name=Black Paintbrush +item.paintbrush.black.desc=Loaded with black dye and ready for use! +item.paintbrush.red.name=Red Paintbrush +item.paintbrush.red.desc=Loaded with red dye and ready for use! +item.paintbrush.green.name=Green Paintbrush +item.paintbrush.green.desc=Loaded with green dye and ready for use! +item.paintbrush.brown.name=Brown Paintbrush +item.paintbrush.brown.desc=Loaded with brown dye and ready for use! +item.paintbrush.blue.name=Blue Paintbrush +item.paintbrush.blue.desc=Loaded with blue dye and ready for use! +item.paintbrush.purple.name=Purple Paintbrush +item.paintbrush.purple.desc=Loaded with purple dye and ready for use! +item.paintbrush.cyan.name=Cyan Paintbrush +item.paintbrush.cyan.desc=Loaded with cyan dye and ready for use! +item.paintbrush.silver.name=Light Gray Paintbrush +item.paintbrush.silver.desc=Loaded with light gray dye and ready for use! +item.paintbrush.gray.name=Gray Paintbrush +item.paintbrush.gray.desc=Loaded with gray dye and ready for use! +item.paintbrush.pink.name=Pink Paintbrush +item.paintbrush.pink.desc=Loaded with pink dye and ready for use! +item.paintbrush.yellow.name=Yellow Paintbrush +item.paintbrush.yellow.desc=Loaded with yellow dye and ready for use! +item.paintbrush.lime.name=Lime Paintbrush +item.paintbrush.lime.desc=Loaded with lime dye and ready for use! +item.paintbrush.lightblue.name=Light Blue Paintbrush +item.paintbrush.lightblue.desc=Loaded with light blue dye and ready for use! +item.paintbrush.magenta.name=Magenta Paintbrush +item.paintbrush.magenta.desc=Loaded with magenta dye and ready for use! +item.paintbrush.orange.name=Orange Paintbrush +item.paintbrush.orange.desc=Loaded with orange dye and ready for use! +item.paintbrush.white.name=White Paintbrush +item.paintbrush.white.desc=Loaded with white dye and ready for use! + +item.statue.slate.name=Slate Statue +item.statue.slate.desc=A decorative statue carved from slate. + +item.statue.permafrost.name=Permafrost Statue +item.statue.permafrost.desc=A decorative statue carved from freezing permafrost. + +item.statue.netherrack.name=Netherrack Statue +item.statue.netherrack.desc=A decorative statue carved from netherrack. + +item.statue.gloomstone.name=Gloomstone Statue +item.statue.gloomstone.desc=A decorative statue carved from gloomy stone. + +item.ammo.arrow.flaming.name=Flaming Arrow +item.ammo.arrow.flaming.desc=An arrow tipped with highly combustible sulfur. + +item.sulfur.name=Sulfur +item.sulfur.desc=A pungent, flammable powder sourced from acidic pools. + +item.bucket.iron.acid.name=Iron Acid Bucket +item.bucket.iron.acid.desc=A sturdy bucket carefully filled with corrosive acid. + +item.bucket.steel.acid.name=Steel Acid Bucket +item.bucket.steel.acid.desc=A large sturdy bucket carefully filled with corrosive acid. + diff --git a/game/core/src/main/resources/assets/minecraft/lang/en_US/options.lang b/game/core/src/main/resources/assets/minecraft/lang/en_US/options.lang index 1e57d8946..5ec26009f 100644 --- a/game/core/src/main/resources/assets/minecraft/lang/en_US/options.lang +++ b/game/core/src/main/resources/assets/minecraft/lang/en_US/options.lang @@ -268,6 +268,7 @@ options.hideDynamicTooltip=Hide options.hideHealthBar=Hide options.hideOxygenBar=Hide options.hideFireBar=Hide +options.hideAcidBar=Hide options.hideVehicleBar=Hide options.hideHelmetBar=Hide @@ -296,6 +297,7 @@ options.verticalHealthBar=Vertical options.verticalOxygenBar=Vertical options.verticalVehicleBar=Vertical options.verticalFireBar=Vertical +options.verticalAcidBar=Vertical options.flipHeldItemCount=Flip options.flipHelmetBar=Flip @@ -306,6 +308,7 @@ options.flipHealthBar=Flip options.flipOxygenBar=Flip options.flipVehicleBar=Flip options.flipFireBar=Flip +options.flipAcidBar=Flip options.horizontalInfoTextAlignment=Horizontal Alignment options.horizontalInfoTextAlignment.left=Left diff --git a/game/core/src/main/resources/assets/minecraft/lang/en_US/tile.lang b/game/core/src/main/resources/assets/minecraft/lang/en_US/tile.lang index 1f2511f1a..0d97b30e8 100644 --- a/game/core/src/main/resources/assets/minecraft/lang/en_US/tile.lang +++ b/game/core/src/main/resources/assets/minecraft/lang/en_US/tile.lang @@ -54,6 +54,8 @@ tile.netherrack.carved.name=Carved Netherrack tile.netherrack.carved.desc=Polished Netherrack with lines hewn through the middle. tile.gloomstone.carved.name=Carved Gloomstone tile.gloomstone.carved.desc=Polished Gloomstone with lines hewn through the middle. +tile.slate.carved.name=Carved Slate +tile.slate.carved.desc=Two slabs of polished slate. tile.planks.oak.name=Wooden Planks tile.planks.oak.desc=Processed tree insides. @@ -235,6 +237,8 @@ tile.brick.stone.desc=Stacked bricks of stone. tile.brick.permafrost.name=Permafrost Bricks tile.brick.permafrost.desc=Stacked bricks of permafrost. +tile.brick.rubyglass.name=Rubyglass Bricks +tile.brick.rubyglass.desc=Stacked bricks of rubyglass. tile.brick.diamond.name=Diamond Bricks tile.brick.diamond.desc=Stacked bricks of diamond. tile.brick.iron.name=Iron Bricks @@ -260,6 +264,8 @@ tile.slab.brick.stone.polished.name=Polished Stone Brick Slab tile.slab.brick.stone.polished.desc=A slab of polished stone bricks. tile.slab.stone.carved.name=Polished Stone Slab tile.slab.stone.carved.desc=A slab of polished stone. +tile.slab.slate.polished.name=Polished Slate Slab +tile.slab.slate.polished.desc=A slab of polished slate. tile.slab.brick.marble.name=Marble Brick Slab tile.slab.brick.marble.desc=A slab of marble bricks. tile.slab.brick.clay.name=Clay Brick Slab @@ -332,6 +338,8 @@ tile.slab.brick.sandstone.desc=A slab of sandstone bricks. tile.slab.brick.permafrost.name=Permafrost Brick Slab tile.slab.brick.permafrost.desc=A slab of permafrost bricks. +tile.slab.brick.rubyglass.name=Rubyglass Brick Slab +tile.slab.brick.rubyglass.desc=A slab of rubyglass bricks. tile.slab.brick.diamond.name=Diamond Brick Slab tile.slab.brick.diamond.desc=A slab of diamond bricks. tile.slab.brick.iron.name=Iron Brick Slab @@ -382,6 +390,8 @@ tile.stairs.brick.sandstone.desc=Sandstone brick block used for rapid vertical m tile.stairs.brick.permafrost.name=Permafrost Brick Stairs tile.stairs.brick.permafrost.desc=Permafrost brick block used for rapid vertical movement. +tile.stairs.brick.rubyglass.name=Rubyglass Brick Stairs +tile.stairs.brick.rubyglass.desc=Rubyglass brick block used for rapid vertical movement. tile.stairs.brick.diamond.name=Diamond Brick Stairs tile.stairs.brick.diamond.desc=Diamond brick block used for rapid vertical movement. tile.stairs.brick.iron.name=Iron Brick Stairs @@ -519,8 +529,6 @@ tile.log.thorn.name=Thorn Log tile.log.thorn.desc=A log from a thorn tree. tile.log.palm.name=Palm Log tile.log.palm.desc=A log from a palm tree. -tile.log.petrified.name=Petrified Pillar -tile.log.petrified.desc=A pillar of carbon, encased in hardened ash. tile.leaves.oak.name=Oak Leaves tile.leaves.oak.desc=Leaves from an oak tree. @@ -1069,19 +1077,19 @@ tile.cobble.netherrack.desc=Dark red rock that burns forever. tile.magma.name=Magma tile.magma.desc=Lava that's been partially cooled. Melts in extreme heat. tile.cobble.netherrack.crystalline.name=Crystalline Netherrack -tile.cobble.netherrack.crystalline.desc=Netherrack, covered in a web of Rubyglass. +tile.cobble.netherrack.crystalline.desc=Netherrack, covered in a web of rubyglass. tile.netherrack.name=Netherrack tile.netherrack.desc=Dark red rock, smoothed by heat and time. tile.brick.netherrack.name=Netherrack Bricks -tile.brick.netherrack.desc=Stacked bricks of Netherrack. +tile.brick.netherrack.desc=Stacked bricks of netherrack. tile.slab.netherrack.carved.name=Polished Netherrack Slab -tile.slab.netherrack.carved.desc=A slab of polished Netherrack. +tile.slab.netherrack.carved.desc=A slab of polished netherrack. tile.slab.cobble.netherrack.name=Cobbled Netherrack Slab -tile.slab.cobble.netherrack.desc=A slab of cobbled Netherrack. +tile.slab.cobble.netherrack.desc=A slab of cobbled netherrack. tile.slab.brick.netherrack.name=Netherrack Brick Slab -tile.slab.brick.netherrack.desc=A slab of Netherrack bricks. +tile.slab.brick.netherrack.desc=A slab of netherrack bricks. tile.stairs.cobble.netherrack.name=Cobbled Netherrack Stairs -tile.stairs.cobble.netherrack.desc=Cobbled Netherrack block used for rapid vertical movement. +tile.stairs.cobble.netherrack.desc=Cobbled netherrack block used for rapid vertical movement. tile.stairs.brick.netherrack.name=Netherrack Brick Stairs tile.stairs.brick.netherrack.desc=Netherrack brick block used for rapid vertical movement. @@ -1433,25 +1441,23 @@ tile.rope.name=Rope tile.rope.desc=Rope, rope, rope your boat. tile.rubyglass.column.name=Rubyglass Column -tile.rubyglass.column.desc=A column of tightly packed Rubyglass. - +tile.rubyglass.column.desc=A column of tightly packed rubyglass. tile.rubyglass.node.name=Rubyglass Node -tile.rubyglass.node.desc=A dense outcrop of Rubyglass. Crystals harvested from this node are purer and more powerful than usual. - +tile.rubyglass.node.desc=A dense outcrop yeilding pure rubyglass. tile.block.rubyglass.name=Block of Rubyglass -tile.block.rubyglass.desc=A translucent glass-like crystal brimming with energy. - -tile.rubyglass.sprout.name=Rubyglass Bud -tile.rubyglass.sprout.desc=A small bud of rubyglass, branching out in many directions. - +tile.block.rubyglass.desc=A bright pink crystal brimming with energy. tile.rubyglass.conduit.name=Conduit -tile.rubyglass.conduit.desc=Netherrack etched with lines of rubyglass. It resonates with latent power. +tile.rubyglass.conduit.desc=Netherrack powered by lines of etched rubyglass using redstone as a catalyst. +tile.rubyglass.growth.name=Rubyglass Growth +tile.rubyglass.growth.desc=A squared, crystalline formation of rubyglass. +tile.rubyglass.crystal.name=Rubyglass Crystal +tile.rubyglass.crystal.desc=Thin glass crystal with the crimson hue of rubyglass. -tile.vent.name=Chimney -tile.vent.desc=A rocky column that emits a stream of smoke. +tile.vent.name=Thermal Vent +tile.vent.desc=An explosive, geothermal column amplified by its length. tile.bone_pile.name=Bone Pile -tile.bone_pile.desc=A pile of solid calcium. +tile.bone_pile.desc=A pile of bones. tile.soul_catcher.name=Soul Catcher tile.soul_catcher.desc=Tendrils of soul sand that seemingly move on their own. Hard to walk through. @@ -1465,34 +1471,78 @@ tile.jar.butterfly.silver.name=Silver Butterfly Jar tile.jar.butterfly.silver.desc=A glass jar containing a silver butterfly. tile.statue.stone.lower.name=Stone Statue (Lower) -tile.statue.stone.lower.desc= +tile.statue.stone.lower.desc=How? tile.statue.stone.upper.name=Stone Statue (Upper) -tile.statue.stone.upper.desc= +tile.statue.stone.upper.desc=How? tile.statue.basalt.lower.name=Basalt Statue (Lower) -tile.statue.basalt.lower.desc= +tile.statue.basalt.lower.desc=How? tile.statue.basalt.upper.name=Basalt Statue (Upper) -tile.statue.basalt.upper.desc= +tile.statue.basalt.upper.desc=How? tile.statue.limestone.lower.name=Limestone Statue (Lower) -tile.statue.limestone.lower.desc= +tile.statue.limestone.lower.desc=How? tile.statue.limestone.upper.name=Limestone Statue (Upper) -tile.statue.limestone.upper.desc= +tile.statue.limestone.upper.desc=How? tile.statue.granite.lower.name=Granite Statue (Lower) -tile.statue.granite.lower.desc= +tile.statue.granite.lower.desc=How? tile.statue.granite.upper.name=Granite Statue (Upper) -tile.statue.granite.upper.desc= +tile.statue.granite.upper.desc=How? tile.statue.marble.lower.name=Marble Statue (Lower) -tile.statue.marble.lower.desc= +tile.statue.marble.lower.desc=How? tile.statue.marble.upper.name=Marble Statue (Upper) -tile.statue.marble.upper.desc= +tile.statue.marble.upper.desc=How? tile.statue.pigman.lower.name=Pigman Statue (Lower) -tile.statue.pigman.lower.desc= +tile.statue.pigman.lower.desc=How? tile.statue.pigman.upper.name=Pigman Statue (Upper) -tile.statue.pigman.upper.desc= +tile.statue.pigman.upper.desc=How? tile.matcher.name=Matcher tile.matcher.desc=Matches the block in front to the block behind. tile.matcher.active.name=Matcher tile.matcher.desc=Matches the block in front to the block behind. -tile.flowstone.name=Flowstone -tile.flowstone.desc=A rocky growth formed over millennia. \ No newline at end of file +tile.log.scorched.name=Scorched Log +tile.log.scorched.desc=A severely burnt log, charred black by intense heat. + +tile.brimstone.name=Brimstone +tile.brimstone.desc=Compacted brimsand. + +tile.slab.brimstone.name=Brimstone Slab +tile.slab.brimstone.desc=A slab of brimstone. + +tile.stairs.brimstone.name=Brimstone Stairs +tile.stairs.brimstone.desc=Brimstone block used for rapid vertical movement. + +tile.brick.brimstone.name=Brimstone Bricks +tile.brick.brimstone.desc=Stacked bricks of Brimstone. + +tile.slab.brick.brimstone.name=Brimstone Brick Slab +tile.slab.brick.brimstone.desc=A slab of brimstone bricks. + +tile.stairs.brick.brimstone.name=Brimstone Brick Stairs +tile.stairs.brick.brimstone.desc=Brimstone brick block used for rapid vertical movement. + +tile.sulfur.name=Block of Sulfur +tile.sulfur.desc=A foul-smelling block of concentrated sulfur. + +tile.sulfur_hardened.name=Hardened Block of Sulfur +tile.sulfur_hardened.desc=A rough, foul-smelling block of concentrated sulfur. + +tile.chain.iron.large.name=Iron Chain +tile.chain.iron.large.desc=A heavy iron chain. +tile.chain.steel.name=Steel Chain +tile.chain.steel.desc=A durable steel chain. + +tile.boulder.magmatic.name=Magmatic Boulder +tile.boulder.magmatic.desc=A large magmatic rock. + +tile.boulder.sulfuric.name=Sulfuric Boulder +tile.boulder.sulfuric.desc=A large sulfuric rock. + +tile.brimthaw.name=Brimthaw +tile.brimthaw.desc=Brimstone laced with glowing rock. + +tile.ember.name=Ember +tile.ember.desc=Smoldering, explosive remnants of a forgotten world. + +tile.acid.name=Acid +tile.acid.desc=A highly corrosive, sulfuric fluid. \ No newline at end of file diff --git a/game/core/src/main/resources/assets/minecraft/lang/en_US/tips.txt b/game/core/src/main/resources/assets/minecraft/lang/en_US/tips.txt index e19432969..cec08b9fd 100644 --- a/game/core/src/main/resources/assets/minecraft/lang/en_US/tips.txt +++ b/game/core/src/main/resources/assets/minecraft/lang/en_US/tips.txt @@ -14,7 +14,7 @@ Beds need blankets! Use cloth to craft them. Quivers provide a convenient way to store a lot of arrows. Olivine is a decent substitute for Nether coal. Outback soil is rich with minerals. -There are 4 main types of rock! See which one you like best. +There are 5 main types of rock in the overworld! See which one you like best. Fancy a splash of color? Try painting wooden planks! Press %key.hotbar.switch to change your active hotbar. Use a compass to see your coordinates. diff --git a/game/core/src/main/resources/assets/minecraft/sounds/sounds.json b/game/core/src/main/resources/assets/minecraft/sounds/sounds.json index 0aad36ab1..5181f4807 100644 --- a/game/core/src/main/resources/assets/minecraft/sounds/sounds.json +++ b/game/core/src/main/resources/assets/minecraft/sounds/sounds.json @@ -892,6 +892,57 @@ } ] }, + "tile.acidbubble": { + "subtitle": "subtitles.tile.acidbubble", + "sounds": [ + "tile/bubble_1.ogg", + "tile/bubble_2.ogg", + "tile/bubble_3.ogg", + "tile/bubble_4.ogg" + ] + }, + "step.crystal": { + "subtitle": "subtitles.step.crystal", + "sounds": [ + "step/crystal_1.ogg", + "step/crystal_2.ogg", + "step/crystal_3.ogg", + "step/crystal_4.ogg", + "step/crystal_5.ogg", + "step/crystal_6.ogg" + ] + }, + "tile.deepboom": { + "subtitle": "subtitles.tile.deepboom", + "sounds": [ + "tile/deepboom.ogg" + ] + }, + "tile.deepquietboom": { + "subtitle": "subtitles.tile.deepquietboom", + "sounds": [ + "tile/deepquietboom.ogg" + ] + }, + "tile.crumble": { + "subtitle": "subtitles.tile.crumble", + "sounds": [ + "tile/crumble_1.ogg", + "tile/crumble_2.ogg" + ] + }, + "tile.deepcrumble": { + "subtitle": "subtitles.tile.deepcrumble", + "sounds": [ + "tile/deepcrumble.ogg" + ] + }, + "random.scrape": { + "subtitle": "subtitles.random.scrape", + "sounds": [ + "random/scrape.ogg" + ] + }, "record.mall": { "sounds": [ { diff --git a/game/core/src/test/java/TestFlammables.java b/game/core/src/test/java/TestFlammables.java index c662cff05..73c5baf96 100644 --- a/game/core/src/test/java/TestFlammables.java +++ b/game/core/src/test/java/TestFlammables.java @@ -24,10 +24,16 @@ public class TestFlammables { Block.hasLogicClass(block, BlockLogicLog.class) || Block.hasLogicClass(block, BlockLogicLeavesBase.class) || Block.hasLogicClass(block, BlockLogicMoss.class); + boolean shouldSmelt = Block.hasLogicClass(block, BlockLogicLog.class) || Block.hasLogicClass(block, BlockLogicSaplingBase.class); + if (block == Blocks.LOG_SCORCHED){ + shouldCombust = false; + shouldSmelt = false; + } + if (shouldCombust) { Assertions.assertTrue(BlockLogicFire.canBurn(block.id()), () -> "Block '" + block.namespaceId() + "' of class '" + block.getLogic().getClass() + "' should probably be flammable!"); } diff --git a/util/datagen/src/main/java/net/minecraft/datagen/SmeltingGenerator.java b/util/datagen/src/main/java/net/minecraft/datagen/SmeltingGenerator.java index 5c4ecdee4..96b7562d4 100644 --- a/util/datagen/src/main/java/net/minecraft/datagen/SmeltingGenerator.java +++ b/util/datagen/src/main/java/net/minecraft/datagen/SmeltingGenerator.java @@ -28,7 +28,7 @@ public class SmeltingGenerator { sharedRecipe("raw_iron_to_iron_ingot", Items.ORE_RAW_IRON.getDefaultStack(), Items.INGOT_IRON.getDefaultStack()); sharedRecipe("raw_gold_to_gold_ingot", Items.ORE_RAW_GOLD.getDefaultStack(), Items.INGOT_GOLD.getDefaultStack()); - + furnaceRecipe("dough_to_bread", Items.DOUGH.getDefaultStack(), Items.FOOD_BREAD.getDefaultStack()); furnaceRecipe("fish_raw_to_fish_cooked", Items.FOOD_FISH_RAW.getDefaultStack(), Items.FOOD_FISH_COOKED.getDefaultStack()); furnaceRecipe("porkchop_raw_to_porkchop_cooked", Items.FOOD_PORKCHOP_RAW.getDefaultStack(), Items.FOOD_PORKCHOP_COOKED.getDefaultStack()); @@ -42,16 +42,30 @@ public class SmeltingGenerator { furnaceRecipe("cobble_permafrost_to_permafrost", Blocks.COBBLE_PERMAFROST.getDefaultStack(), Blocks.PERMAFROST.getDefaultStack()); furnaceRecipe("cobble_gloomstone_to_gloomstone", Blocks.COBBLE_GLOOMSTONE.getDefaultStack(), Blocks.GLOOMSTONE.getDefaultStack()); + blastRecipe("cobble_stone_to_slate", Blocks.COBBLE_STONE.getDefaultStack(), Blocks.SLATE.getDefaultStack()); + blastRecipe("cobble_stone_to_stone", Blocks.COBBLE_STONE.getDefaultStack(), Blocks.COBBLE_STONE.getDefaultStack(), Blocks.STONE.getDefaultStack()); + blastRecipe("cobble_basalt_to_olivine", Blocks.COBBLE_BASALT.getDefaultStack(), Items.OLIVINE.getDefaultStack()); + blastRecipe("cobble_basalt_to_basalt", Blocks.COBBLE_BASALT.getDefaultStack(), Blocks.COBBLE_BASALT.getDefaultStack(), Blocks.BASALT.getDefaultStack()); + blastRecipe("cobble_granite_to_quartz", Blocks.COBBLE_GRANITE.getDefaultStack(), Items.QUARTZ.getDefaultStack()); + blastRecipe("cobble_granite_to_granite", Blocks.COBBLE_GRANITE.getDefaultStack(), Blocks.COBBLE_GRANITE.getDefaultStack(), Blocks.GRANITE.getDefaultStack()); + blastRecipe("cobble_limestone_to_marble", Blocks.COBBLE_LIMESTONE.getDefaultStack(), Blocks.MARBLE.getDefaultStack()); + blastRecipe("cobble_limestone_to_limestone", Blocks.COBBLE_LIMESTONE.getDefaultStack(), Blocks.COBBLE_LIMESTONE.getDefaultStack(), Blocks.LIMESTONE.getDefaultStack()); + + blastRecipe("cobble_netherrack_to_magma", Blocks.COBBLE_NETHERRACK.getDefaultStack(), Blocks.MAGMA.getDefaultStack()); + blastRecipe("cobble_netherrack_to_netherrack", Blocks.COBBLE_NETHERRACK.getDefaultStack(), Blocks.COBBLE_NETHERRACK.getDefaultStack(), Blocks.NETHERRACK.getDefaultStack()); + + blastRecipe("brimstone_to_brimthaw", Blocks.BRIMSTONE.getDefaultStack(), Blocks.BRIMTHAW.getDefaultStack()); + blastRecipe("cobble_permafrost_to_permafrost", Blocks.COBBLE_PERMAFROST.getDefaultStack(), Blocks.PERMAFROST.getDefaultStack()); - blastRecipe("cobble_stone_to_slate", Blocks.COBBLE_STONE.getDefaultStack(), Blocks.SLATE.getDefaultStack()); + blastRecipe("cobble_gloomstone_to_gloomstone", Blocks.COBBLE_GLOOMSTONE.getDefaultStack(), Blocks.GLOOMSTONE.getDefaultStack()); + blastRecipe("iron_ingot_and_coal_to_crude_steel", Items.INGOT_IRON.getDefaultStack(), Items.COAL.getDefaultStack(), Items.INGOT_STEEL_CRUDE.getDefaultStack()); blastRecipe("iron_ingot_and_charcoal_to_crude_steel", Items.INGOT_IRON.getDefaultStack(), new ItemStack(Items.COAL, 1, 1), Items.INGOT_STEEL_CRUDE.getDefaultStack()); - blastRecipe("cobble_netherrack_to_magma", Blocks.COBBLE_NETHERRACK.getDefaultStack(), Blocks.MAGMA.getDefaultStack()); - blastRecipe("logs_to_petrified_pillar", "minecraft:logs", Blocks.BLOCK_ASH.getDefaultStack(), Blocks.LOG_PETRIFIED.getDefaultStack()); + blastRecipe("log_to_scorched_log", "minecraft:logs", Blocks.BLOCK_ASH.getDefaultStack(), Blocks.LOG_SCORCHED.getDefaultStack()); } private static void furnaceRecipe(String id, ItemStack input, ItemStack output) { diff --git a/util/datagen/src/main/java/net/minecraft/datagen/TrommelGenerator.java b/util/datagen/src/main/java/net/minecraft/datagen/TrommelGenerator.java index 1190892b3..095655ba5 100644 --- a/util/datagen/src/main/java/net/minecraft/datagen/TrommelGenerator.java +++ b/util/datagen/src/main/java/net/minecraft/datagen/TrommelGenerator.java @@ -78,19 +78,30 @@ public class TrommelGenerator { .addEntry(new WeightedRandomLootObject(new ItemStack(Items.ORE_RAW_GOLD), 1), 2) .addEntry(new WeightedRandomLootObject(new ItemStack(Items.ORE_RAW_IRON), 1), 1) .addEntry(new WeightedRandomLootObject(new ItemStack(Items.DUST_GLOWSTONE), 1, 6), 5) -// .addEntry(new WeightedRandomLootObject(new ItemStack(Items.RUBYGLASS_DUST), 1, 3), 5) .addEntry(new WeightedRandomLootObject(new ItemStack(Items.NETHERCOAL), 1), 2) + .addEntry(new WeightedRandomLootObject(new ItemStack(Items.AMMO_PEBBLE), 1, 2), 15) .create("soul_sand"); RecipeBuilder.Trommel(RecipesGenerator.CORE_NAMESPACE) - .setInput(Blocks.BRIMSAND) - .addEntry(new WeightedRandomLootObject(new ItemStack(Items.GUNPOWDER), 1, 2), 25) - .addEntry(new WeightedRandomLootObject(new ItemStack(Items.BONE), 1, 2), 10) - .addEntry(new WeightedRandomLootObject(new ItemStack(Items.DUST_GLOWSTONE), 1, 4), 5) - .addEntry(new WeightedRandomLootObject(new ItemStack(Items.FLINT), 1, 2), 5) - .addEntry(new WeightedRandomLootObject(new ItemStack(Items.OLIVINE), 1), 5) - .addEntry(new WeightedRandomLootObject(new ItemStack(Items.ORE_RAW_GOLD), 1), 0.5) - .create("brimsand"); + .setInput(Blocks.BRIMSAND) + .addEntry(new WeightedRandomLootObject(new ItemStack(Items.AMMO_PEBBLE), 2, 3), 35) + .addEntry(new WeightedRandomLootObject(new ItemStack(Items.GUNPOWDER), 1, 2), 25) + .addEntry(new WeightedRandomLootObject(new ItemStack(Items.BONE), 1, 2), 10) + .addEntry(new WeightedRandomLootObject(new ItemStack(Items.DUST_GLOWSTONE), 1, 2), 10) + .addEntry(new WeightedRandomLootObject(new ItemStack(Items.FLINT), 1, 2), 5) + .addEntry(new WeightedRandomLootObject(new ItemStack(Items.SULFUR), 1, 2), 5) + .addEntry(new WeightedRandomLootObject(new ItemStack(Items.NETHERCOAL), 1), 5) + .addEntry(new WeightedRandomLootObject(new ItemStack(Items.ORE_RAW_GOLD), 1), 0.5) + .create("brimsand"); + + RecipeBuilder.Trommel(RecipesGenerator.CORE_NAMESPACE) + .setInput(Blocks.SULFUR) + .addEntry(new WeightedRandomLootObject(new ItemStack(Items.SULFUR), 2, 5), 30) + .addEntry(new WeightedRandomLootObject(new ItemStack(Items.DUST_GLOWSTONE), 1, 3), 20) + .addEntry(new WeightedRandomLootObject(new ItemStack(Items.BONE), 1, 2), 10) + .addEntry(new WeightedRandomLootObject(new ItemStack(Items.FLINT), 1, 2), 5) + .addEntry(new WeightedRandomLootObject(new ItemStack(Items.ORE_RAW_IRON), 1, 2), 4) + .create("sulfur"); } } diff --git a/util/datagen/src/main/java/net/minecraft/datagen/WorkbenchGenerator.java b/util/datagen/src/main/java/net/minecraft/datagen/WorkbenchGenerator.java index 82a1a4cab..50656deab 100644 --- a/util/datagen/src/main/java/net/minecraft/datagen/WorkbenchGenerator.java +++ b/util/datagen/src/main/java/net/minecraft/datagen/WorkbenchGenerator.java @@ -62,6 +62,9 @@ class WorkbenchGenerator { generateDyeingRecipes(); generateStatueRecipes(); + generateAcidConversions(); + + generateMiscNewRecipes(); RecipeBuilder.Shaped(CORE_NAMESPACE) .setShape( @@ -151,11 +154,11 @@ class WorkbenchGenerator { "###", "CSR", "###") - .addInput('#', Blocks.COBBLE_NETHERRACK) + .addInput('#', Blocks.NETHERRACK) .addInput('S', Blocks.SOULSAND) .addInput('C', Blocks.CONDUIT) .addInput('R', Items.DUST_REDSTONE) - .create("activator", Blocks.ACTIVATOR_COBBLE_NETHERRACK.getDefaultStack()); + .create("activator", Blocks.ACTIVATOR.getDefaultStack()); RecipeBuilder.Shaped(CORE_NAMESPACE) .setShape( @@ -254,7 +257,7 @@ class WorkbenchGenerator { shape22.addInput('#', Items.CLAY).create("clay_block", Blocks.BLOCK_CLAY.getDefaultStack()); shape22.addInput('#', Items.AMMO_SNOWBALL).create("snow_block", Blocks.BLOCK_SNOW.getDefaultStack()); shape22.addInput('#', Items.STRING).create("string_to_wool", Blocks.WOOL.getDefaultStack()); - shape22.addInput('#', Items.AMMO_PEBBLE).create("pebbles_to_cobblestone", Blocks.COBBLE_STONE.getDefaultStack()); + shape22.addInput('#', Items.AMMO_PEBBLE).create("pebbles_to_cobblestone", new ItemStack(Blocks.COBBLE_STONE, 2)); shape22.addInput('#', Blocks.SAND).create("sandstone", new ItemStack(Blocks.SANDSTONE, 2)); shape22.addInput('#', "minecraft:planks").create("workbench", Blocks.WORKBENCH.getDefaultStack()); @@ -429,7 +432,59 @@ class WorkbenchGenerator { .addInput(new ItemStack(Items.DYE, 1, DyeColor.BLACK.itemMeta)) .addInput(Items.STRING) .create("blank_label", Items.LABEL.getDefaultStack()); + + RecipeBuilder.Shapeless(CORE_NAMESPACE) + .addInput(Items.BONE) + .addInput(Items.BONE) + .create("bone_pile", Blocks.BONE_PILE.getDefaultStack()); + + RecipeBuilder.Shaped(CORE_NAMESPACE) + .setShape( + "GSG", + "SCS", + "GSG") + .addInput('C', Items.NETHERCOAL) + .addInput('G', Items.GUNPOWDER) + .addInput('S', Items.SULFUR) + .create("ember", Blocks.EMBER.getDefaultStack()); + + RecipeBuilder.Shapeless(CORE_NAMESPACE) + .addInput(Items.SULFUR) + .addInput(Items.COAL) + .addInput(Items.PAPER) + .create("gunpowder_with_coal", new ItemStack(Items.GUNPOWDER, 2)); + + RecipeBuilder.Shapeless(CORE_NAMESPACE) + .addInput(Items.SULFUR) + .addInput(new ItemStack(Items.COAL, 1, 1)) + .addInput(Items.PAPER) + .create("gunpowder_with_charcoal", new ItemStack(Items.GUNPOWDER, 2)); + + RecipeBuilder.Shapeless(CORE_NAMESPACE) + .addInput(Items.SULFUR) + .addInput(Items.NETHERCOAL) + .addInput(Items.PAPER) + .create("gunpowder_with_nethercoal", new ItemStack(Items.GUNPOWDER, 4)); + + RecipeBuilder.Shapeless(CORE_NAMESPACE) + .addInput(Blocks.RUBYGLASS_COLUMN) + .create("ruby_column_to_growth", new ItemStack(Blocks.RUBYGLASS_GROWTH, 4)); + + RecipeBuilder.Shapeless(CORE_NAMESPACE) + .addInput(Blocks.RUBYGLASS_GROWTH) + .addInput(Blocks.RUBYGLASS_GROWTH) + .addInput(Blocks.RUBYGLASS_GROWTH) + .addInput(Blocks.RUBYGLASS_GROWTH) + .create("ruby_growth_to_column", new ItemStack(Blocks.RUBYGLASS_COLUMN, 1)); + + RecipeBuilder.Shapeless(CORE_NAMESPACE) + .addInput(Items.SULFUR) + .addInput(Items.CLAY) + .addInput(new ItemStack(Items.DYE, 1, DyeColor.WHITE.itemMeta)) + .create("dirt", new ItemStack(Blocks.DIRT, 2)); } + + private static void generatePickaxes() { RecipeBuilderShaped pickaxeTemplate = RecipeBuilder.Shaped(CORE_NAMESPACE) .setShape( @@ -732,7 +787,7 @@ class WorkbenchGenerator { block.addInput('X', Items.DIAMOND).create("block_of_diamond", Blocks.BLOCK_DIAMOND.getDefaultStack()); block.addInput('X', Items.QUARTZ).create("block_of_quartz", Blocks.BLOCK_QUARTZ.getDefaultStack()); block.addInput('X', Items.SUGARCANE).create("block_of_sugarcane", Blocks.BLOCK_SUGARCANE.getDefaultStack()); - block.addInput('X', Items.RUBYGLASS_CRYSTAL).create("block_of_rubyglass", Blocks.BLOCK_RUBYGLASS.getDefaultStack()); + block.addInput('X', Items.RUBYGLASS).create("block_of_rubyglass", Blocks.BLOCK_RUBYGLASS.getDefaultStack()); blockFuel.addInput('X', Items.COAL, 0).create("block_of_coal", Blocks.BLOCK_COAL.getDefaultStack()); blockFuel.addInput('X', Items.COAL, 1).create("block_of_charcoal", Blocks.BLOCK_CHARCOAL.getDefaultStack()); @@ -748,7 +803,7 @@ class WorkbenchGenerator { RecipeBuilder.Shapeless(CORE_NAMESPACE).addInput(Blocks.BLOCK_REDSTONE).create("block_of_redstone_to_redstone", new ItemStack(Items.DUST_REDSTONE, 9)); RecipeBuilder.Shapeless(CORE_NAMESPACE).addInput(Blocks.BLOCK_DIAMOND).create("block_of_diamond_to_diamond", new ItemStack(Items.DIAMOND, 9)); RecipeBuilder.Shapeless(CORE_NAMESPACE).addInput(Blocks.BLOCK_QUARTZ).create("block_of_quartz_to_quartz", new ItemStack(Items.QUARTZ, 9)); - RecipeBuilder.Shapeless(CORE_NAMESPACE).addInput(Blocks.BLOCK_RUBYGLASS).create("block_of_rubyglass_to_rubyglass", new ItemStack(Items.RUBYGLASS_CRYSTAL, 9)); + RecipeBuilder.Shapeless(CORE_NAMESPACE).addInput(Blocks.BLOCK_RUBYGLASS).create("block_of_rubyglass_to_rubyglass", new ItemStack(Items.RUBYGLASS, 9)); RecipeBuilder.Shapeless(CORE_NAMESPACE).addInput(Blocks.BLOCK_SUGARCANE).create("block_of_sugarcane_to_sugarcane", new ItemStack(Items.SUGARCANE, 9)); RecipeBuilder.Shapeless(CORE_NAMESPACE).addInput(Blocks.BLOCK_COAL).create("block_of_coal_to_coal", new ItemStack(Items.COAL, 8, 0)); @@ -765,6 +820,7 @@ class WorkbenchGenerator { ); final int stackSize = 4; + bricks.addInput('X', Items.RUBYGLASS).create("rubyglass_bricks", new ItemStack(Blocks.BRICK_RUBYGLASS, stackSize)); bricks.addInput('X', Items.DIAMOND).create("diamond_bricks", new ItemStack(Blocks.BRICK_DIAMOND, stackSize)); bricks.addInput('X', Items.BRICK_CLAY).create("clay_bricks", new ItemStack(Blocks.BRICK_CLAY, stackSize)); bricks.addInput('X', Items.INGOT_GOLD).create("golden_bricks", new ItemStack(Blocks.BRICK_GOLD, stackSize)); @@ -830,6 +886,7 @@ class WorkbenchGenerator { slabs.addInput('X', Blocks.BRICK_NETHERRACK).create("netherrack_brick_slab", new ItemStack(Blocks.SLAB_BRICK_NETHERRACK, stackSize)); slabs.addInput('X', Blocks.BRICK_GLOOMSTONE).create("gloomstone_brick_slab", new ItemStack(Blocks.SLAB_BRICK_GLOOMSTONE, stackSize)); + slabs.addInput('X', Blocks.BRICK_RUBYGLASS).create("rubyglass_brick_slab", new ItemStack(Blocks.SLAB_BRICK_RUBYGLASS, stackSize)); slabs.addInput('X', Blocks.BRICK_DIAMOND).create("diamond_brick_slab", new ItemStack(Blocks.SLAB_BRICK_DIAMOND, stackSize)); slabs.addInput('X', Blocks.BRICK_IRON).create("iron_brick_slab", new ItemStack(Blocks.SLAB_BRICK_IRON, stackSize)); slabs.addInput('X', Blocks.BRICK_GOLD).create("gold_brick_slab", new ItemStack(Blocks.SLAB_BRICK_GOLD, stackSize)); @@ -880,6 +937,7 @@ class WorkbenchGenerator { stairs.addInput('X', Blocks.BRICK_NETHERRACK).create("netherrack_brick_stairs", new ItemStack(Blocks.STAIRS_BRICK_NETHERRACK, stackSize)); stairs.addInput('X', Blocks.BRICK_GLOOMSTONE).create("gloomstone_brick_stairs", new ItemStack(Blocks.STAIRS_BRICK_GLOOMSTONE, stackSize)); + stairs.addInput('X', Blocks.BRICK_RUBYGLASS).create("rubyglass_brick_stairs", new ItemStack(Blocks.STAIRS_BRICK_RUBYGLASS, stackSize)); stairs.addInput('X', Blocks.BRICK_DIAMOND).create("diamond_brick_stairs", new ItemStack(Blocks.STAIRS_BRICK_DIAMOND, stackSize)); stairs.addInput('X', Blocks.BRICK_IRON).create("iron_brick_stairs", new ItemStack(Blocks.STAIRS_BRICK_IRON, stackSize)); stairs.addInput('X', Blocks.BRICK_GOLD).create("gold_brick_stairs", new ItemStack(Blocks.STAIRS_BRICK_GOLD, stackSize)); @@ -1384,7 +1442,7 @@ class WorkbenchGenerator { "#C#", "#Q#" ) - .addInput('#', Blocks.COBBLE_NETHERRACK) + .addInput('#', Blocks.NETHERRACK) .addInput('Q', Items.QUARTZ) .addInput('C', Blocks.CONDUIT) .create("matcher", new ItemStack(Blocks.MATCHER, 1)); @@ -1395,8 +1453,8 @@ class WorkbenchGenerator { "ORO", "XOX") .addInput('R', Items.DUST_REDSTONE) - .addInput('O', Items.RUBYGLASS_CRYSTAL) - .addInput('X', Blocks.COBBLE_NETHERRACK) + .addInput('O', Items.RUBYGLASS) + .addInput('X', Blocks.NETHERRACK) .create("conduit", new ItemStack(Blocks.CONDUIT, 1)); RecipeBuilder.Shaped(CORE_NAMESPACE) @@ -1431,18 +1489,14 @@ class WorkbenchGenerator { } private static void generateStatueRecipes() { - final String[] statueNames = new String[]{"stone", "basalt", "limestone", "granite", "marble"}; - final Item[] statueItems = new Item[]{Items.STATUE_STONE, Items.STATUE_BASALT, Items.STATUE_LIMESTONE, Items.STATUE_GRANITE, Items.STATUE_MARBLE}; - final Block[] statueBodyBlocks = new Block[]{Blocks.STONE, Blocks.BASALT, Blocks.LIMESTONE, Blocks.GRANITE, Blocks.MARBLE}; - final Block[] statueBaseBlocks = new Block[]{Blocks.SLAB_STONE_POLISHED, Blocks.SLAB_BASALT_POLISHED, Blocks.SLAB_LIMESTONE_POLISHED, Blocks.SLAB_GRANITE_POLISHED, Blocks.SLAB_CAPSTONE_MARBLE}; + final String[] statueNames = new String[]{"stone", "basalt", "limestone", "granite", "marble", "slate", "permafrost", "netherrack", "gloomstone"}; + final Item[] statueItems = new Item[]{Items.STATUE_STONE, Items.STATUE_BASALT, Items.STATUE_LIMESTONE, Items.STATUE_GRANITE, Items.STATUE_MARBLE, Items.STATUE_SLATE, Items.STATUE_PERMAFROST, Items.STATUE_NETHERRACK, Items.STATUE_GLOOMSTONE}; + final Block[] statueBodyBlocks = new Block[]{Blocks.STONE, Blocks.BASALT, Blocks.LIMESTONE, Blocks.GRANITE, Blocks.MARBLE, Blocks.SLATE, Blocks.PERMAFROST, Blocks.NETHERRACK, Blocks.GLOOMSTONE}; + final Block[] statueBaseBlocks = new Block[]{Blocks.SLAB_STONE_POLISHED, Blocks.SLAB_BASALT_POLISHED, Blocks.SLAB_LIMESTONE_POLISHED, Blocks.SLAB_GRANITE_POLISHED, Blocks.SLAB_CAPSTONE_MARBLE, Blocks.SLAB_SLATE_POLISHED, Blocks.SLAB_PERMAFROST_POLISHED, Blocks.SLAB_NETHERRACK_POLISHED, Blocks.SLAB_GLOOMSTONE_POLISHED}; for (int i = 0; i < statueItems.length; i++) { RecipeBuilder.Shaped(CORE_NAMESPACE) - .setShape( - "#", - "#", - "_" - ) + .setShape("#", "#", "_") .addInput('#', statueBodyBlocks[i]) .addInput('_', statueBaseBlocks[i]) .create("statue_" + statueNames[i], new ItemStack(statueItems[i], 1)); @@ -1484,4 +1538,64 @@ class WorkbenchGenerator { Registries.RECIPES.WORKBENCH.register(String.format(format, "buttons_planks"), new RecipeEntryDyeing(new RecipeSymbol("minecraft:button_planks"), new ItemStack(Blocks.BUTTON_PLANKS_PAINTED), true, false)); Registries.RECIPES.WORKBENCH.register(String.format(format, "pressureplates_planks"), new RecipeEntryDyeing(new RecipeSymbol("minecraft:pressureplates_planks"), new ItemStack(Blocks.PRESSURE_PLATE_PLANKS_OAK_PAINTED), true, false)); } + + private static void generateMiscNewRecipes() { + // Carved Stones + RecipeBuilderShaped templateCarvedStone = RecipeBuilder.Shaped(CORE_NAMESPACE).setShape("SS", "SS"); + templateCarvedStone.addInput('S', Blocks.STONE_POLISHED).create("carved_stone", new ItemStack(Blocks.STONE_CARVED, 2)); + templateCarvedStone.addInput('S', Blocks.BASALT_POLISHED).create("carved_basalt", new ItemStack(Blocks.BASALT_CARVED, 2)); + templateCarvedStone.addInput('S', Blocks.LIMESTONE_POLISHED).create("carved_limestone", new ItemStack(Blocks.LIMESTONE_CARVED, 2)); + templateCarvedStone.addInput('S', Blocks.GRANITE_POLISHED).create("carved_granite", new ItemStack(Blocks.GRANITE_CARVED, 2)); + templateCarvedStone.addInput('S', Blocks.PERMAFROST_POLISHED).create("carved_permafrost", new ItemStack(Blocks.PERMAFROST_CARVED, 2)); + templateCarvedStone.addInput('S', Blocks.MARBLE).create("marble_capstone", new ItemStack(Blocks.CAPSTONE_MARBLE, 2)); + templateCarvedStone.addInput('S', Blocks.SLATE_POLISHED).create("carved_slate", new ItemStack(Blocks.SLATE_CARVED, 2)); + templateCarvedStone.addInput('S', Blocks.NETHERRACK_POLISHED).create("carved_netherrack", new ItemStack(Blocks.NETHERRACK_CARVED, 2)); + templateCarvedStone.addInput('S', Blocks.GLOOMSTONE_POLISHED).create("carved_gloomstone", new ItemStack(Blocks.GLOOMSTONE_CARVED, 2)); + + // Brimstone Formatting + RecipeBuilder.Shaped(CORE_NAMESPACE).setShape("SS", "SS").addInput('S', Blocks.BRIMSAND).create("brimstone", new ItemStack(Blocks.BRIMSTONE, 2)); + RecipeBuilder.Shaped(CORE_NAMESPACE).setShape("SSS").addInput('S', Blocks.BRIMSTONE).create("brimstone_slab", new ItemStack(Blocks.SLAB_BRIMSTONE, 6)); + RecipeBuilder.Shaped(CORE_NAMESPACE).setShape("S ", "SS ", "SSS").addInput('S', Blocks.BRIMSTONE).create("brimstone_stairs", new ItemStack(Blocks.STAIRS_BRIMSTONE, 6)); + RecipeBuilder.Shaped(CORE_NAMESPACE).setShape("SS", "SS").addInput('S', Blocks.BRIMSTONE).create("brimstone_bricks", new ItemStack(Blocks.BRICK_BRIMSTONE, 4)); + RecipeBuilder.Shaped(CORE_NAMESPACE).setShape("SSS").addInput('S', Blocks.BRICK_BRIMSTONE).create("brick_brimstone_slab", new ItemStack(Blocks.SLAB_BRICK_BRIMSTONE, 6)); + RecipeBuilder.Shaped(CORE_NAMESPACE).setShape("S ", "SS ", "SSS").addInput('S', Blocks.BRICK_BRIMSTONE).create("brick_brimstone_stairs", new ItemStack(Blocks.STAIRS_BRICK_BRIMSTONE, 6)); + + // Misc additions + RecipeBuilder.Shaped(CORE_NAMESPACE).setShape("SSS").addInput('S', Blocks.SLATE_POLISHED).create("polished_slate_slab", new ItemStack(Blocks.SLAB_SLATE_POLISHED, 6)); + RecipeBuilder.Shaped(CORE_NAMESPACE).setShape("PO", "OP").addInput('P', Items.AMMO_PEBBLE).addInput('O', Blocks.OBSIDIAN).create("pebbles_to_gloomstone", new ItemStack(Blocks.COBBLE_GLOOMSTONE, 2)); + RecipeBuilder.Shaped(CORE_NAMESPACE).setShape(" S ", "SAS", " S ").addInput('S', Items.SULFUR).addInput('A', Items.AMMO_ARROW).create("flaming_arrow", new ItemStack(Items.AMMO_ARROW_FLAMING, 4)); + RecipeBuilder.Shaped(CORE_NAMESPACE).setShape("SS", "SS").addInput('S', Items.SULFUR).create("sulfur_block", new ItemStack(Blocks.SULFUR, 1)); + + RecipeBuilder.Shapeless(CORE_NAMESPACE).addInput(Blocks.LOG_SCORCHED).create("scorched_log_to_black_wooden_planks", new ItemStack(Blocks.PLANKS_OAK_PAINTED, 4, 15)); + } + + private static void generateAcidConversions() { + // Each pair: { input, output } + final Block[][] pairs = { + { Blocks.COBBLE_STONE, Blocks.STONE }, + { Blocks.COBBLE_BASALT, Blocks.BASALT }, + { Blocks.COBBLE_LIMESTONE, Blocks.LIMESTONE }, + { Blocks.COBBLE_GRANITE, Blocks.GRANITE }, + { Blocks.COBBLE_PERMAFROST, Blocks.PERMAFROST }, + { Blocks.COBBLE_NETHERRACK, Blocks.NETHERRACK }, + { Blocks.COBBLE_GLOOMSTONE, Blocks.GLOOMSTONE }, + { Blocks.SAND, Blocks.SANDSTONE }, + { Blocks.BRIMSAND, Blocks.BRIMSTONE } + }; + + for (Block[] pair : pairs) { + Block cobble = pair[0]; + Block smooth = pair[1]; + String cobbleName = cobble.getKey().replace(".", "_").replace(":", "_"); + + RecipeBuilder.Shaped(CORE_NAMESPACE) + .setShape( + "CCC", + "CAC", + "CCC") + .addInput('C', cobble) + .addInput('A', "minecraft:acid_buckets") + .create("acid_conversion_" + cobbleName, new ItemStack(smooth, 4)); + } + } } diff --git a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTABiome.java b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTABiome.java index cb9b399df..bd6bb7962 100644 --- a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTABiome.java +++ b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTABiome.java @@ -1,6 +1,5 @@ package org.useless.seedviewer.bta; -import net.minecraft.core.data.registry.Registries; import net.minecraft.core.lang.I18n; import net.minecraft.core.util.HardIllegalArgumentException; import net.minecraft.core.util.collection.NamespaceID; @@ -19,8 +18,12 @@ public class BTABiome implements ViewerBiome { @Override public NamespaceID getID() { + final String key = this.biome.getRegistryKey(); + if (key == null) { + throw new IllegalArgumentException("Unregistered biome: " + this.biome.translationKey); + } try { - return NamespaceID.fromPool(Registries.BIOMES.getKey(this.biome)).copyUnpooled(); + return NamespaceID.fromPool(key).copyUnpooled(); } catch (HardIllegalArgumentException e) { throw new IllegalArgumentException(e); }