diff --git a/CHANGELOG.md b/CHANGELOG.md index 85dcaa14a..ec1f47c06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,16 @@ ## [8.1] ### Features +- Added Diving Suit (Helmet, Chestplate, Leggings, Boots). Pieces spawn in labyrinths and provide various benefits when exploring or working underwater. +- Added Barrier and Intangible Barrier Blocks. ### Fixes +- Fixed saving images/files to clipboard with proper X11, Wayland and GTK support ## [8.0.2] ### Features - Added Frame Timer Precision option. Higher values improve timing precision, but increase CPU usage. -- Added Directional Audio option. This was previously always enabled, disabling this might provide a better experience when using speakers. +- Added Directional Audio option. This was previously always enabled; disabling it might provide a better experience when using speakers. - Entities can now turn either left or right during death animation ### Fixes @@ -40,6 +43,7 @@ - Dispensers - Fix unban command banning player instead - Fix fence bounding box not being offset +- Fixed items not being emissive when held by some entities - Fixed Summoning Wand opening mob picker screen when right-clicking entities - Fixed mobs flailing frantically while being hit repeatedly - Fixed block models that extended beyond a block having broken lighting @@ -68,8 +72,21 @@ - Fixed arrow despawn animation not matching items - Fixed bow not rendering arrows in inventories - Fixed held blocks being positioned incorrectly while sneaking -- Fixed texture bleeding on most block models - Fixed endless winter not being endless - Fixed subtitle option being reset when the hud editor has not yet been opened - Fixed button painting working incorrectly - Fixed fast clouds being cut off +- Fixed b1.7.3 and skyblock nether not being used on the server +- Fixed custom dynamic textures being broken when Animated Textures is not set to Custom +- Fixed leaf piles not respecting the Fast leaves setting +- Fixed fishing rod line rendering in first person +- Fixed console readability and issues regarding line rap/font +- Fixed statues rendering translucent items as opaque +- Fixed braziers not updating when ignited by flaming arrows +- Fixed water not flowing when ice is melted by flaming arrows +- Fixed newly created worlds starting on the 3rd day +- Fixed days being counted from 0 +- Fixed three packet related issues, including a crash upon receiving an empty payload +- Fixed texture bleeding on most block models +- Fixed UV insets not following the UV direction +- Fixed specific z-fighting issues on AMD based GPUs diff --git a/game/client/src/main/java/net/minecraft/client/gui/Screen.java b/game/client/src/main/java/net/minecraft/client/gui/Screen.java index 1f9f69bf6..552bd059c 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/Screen.java +++ b/game/client/src/main/java/net/minecraft/client/gui/Screen.java @@ -1,5 +1,6 @@ package net.minecraft.client.gui; +import java.io.File; import java.util.ArrayList; import java.util.List; @@ -158,6 +159,9 @@ public abstract class Screen extends Gui { public void tick() { } + public void filesDropped(final @NotNull List<@NotNull File> files) { + } + public void removed() { } diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenConsole.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenConsole.java index d7981d1dd..7b25f37a9 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/ScreenConsole.java +++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenConsole.java @@ -34,26 +34,31 @@ public class ScreenConsole extends Screen { private static boolean callbackInitialized = false; - private final @NotNull Map preludes = new HashMap<>(); + private static final @NotNull Map PRELUDES = new HashMap<>(); - private int width = 0; + static { + PRELUDES.put(LogMessage.Level.ERROR, TextFormatting.RED); + PRELUDES.put(LogMessage.Level.WARN, TextFormatting.YELLOW); + PRELUDES.put(LogMessage.Level.INFO, TextFormatting.WHITE); + PRELUDES.put(LogMessage.Level.DEBUG, TextFormatting.LIGHT_BLUE); + PRELUDES.put(LogMessage.Level.TRACE, TextFormatting.GRAY); + } + + private static int width = 0; private int scroll = 0; private final FontRenderer font; public LogRenderer(FontRenderer font) { this.font = font; - this.preludes.put(LogMessage.Level.ERROR, TextFormatting.RED); - this.preludes.put(LogMessage.Level.WARN, TextFormatting.YELLOW); - this.preludes.put(LogMessage.Level.INFO, TextFormatting.WHITE); - this.preludes.put(LogMessage.Level.DEBUG, TextFormatting.LIGHT_BLUE); - this.preludes.put(LogMessage.Level.TRACE, TextFormatting.GRAY); } public void init(final @NotNull Minecraft mc, final int width) { - this.width = width; + if (width != LogRenderer.width) { + LogRenderer.width = width; + initWorkedLines(); + } - initWorkedLines(); final @NotNull List<@NotNull String> workedLine = new ArrayList<>(); if (!callbackInitialized) { LogMessageReceiver.addCallback((message) -> { @@ -85,7 +90,7 @@ public class ScreenConsole extends Screen { } public int getWidth() { - return this.width; + return width; } public void scroll(final int numLines) { @@ -101,14 +106,14 @@ public class ScreenConsole extends Screen { private void renderScrollIndicator(final int x, final int y, final int numLines) { if (numLines * LINE_HEIGHT <= SCROLL_INDICATOR_HEIGHT) { - drawRect(x + this.width - SCROLL_INDICATOR_WIDTH, y, x + this.width, y + numLines * LINE_HEIGHT, 0xFF_FF_FF_FF); + drawRect(x + width - SCROLL_INDICATOR_WIDTH, y, x + width, y + numLines * LINE_HEIGHT, 0xFF_FF_FF_FF); return; } final float scrollPercentage = 1.0f - getScrollPercentage(); final int scrollRegionHeight = numLines * LINE_HEIGHT - SCROLL_INDICATOR_HEIGHT; final int scrollY = (int) (scrollRegionHeight * scrollPercentage); - drawRect(x + this.width - SCROLL_INDICATOR_WIDTH, y + scrollY, x + this.width, y + scrollY + SCROLL_INDICATOR_HEIGHT, 0xFF_FF_FF_FF); + drawRect(x + width - SCROLL_INDICATOR_WIDTH, y + scrollY, x + width, y + scrollY + SCROLL_INDICATOR_HEIGHT, 0xFF_FF_FF_FF); } private float getScrollPercentage() { @@ -142,7 +147,7 @@ public class ScreenConsole extends Screen { .replace("\t", " ") .split("\n"); - @NotNull TextFormatting currentFormat = this.preludes.getOrDefault(message.getLevel(), TextFormatting.WHITE); + @NotNull TextFormatting currentFormat = PRELUDES.getOrDefault(message.getLevel(), TextFormatting.WHITE); for (final @NotNull String line : workedString) { @NotNull String trimmedLine = line; @@ -160,7 +165,7 @@ public class ScreenConsole extends Screen { lineWidth -= Fonts.MONOSPACE.charWidth(c) + Fonts.MONOSPACE.charWidth(trimmedLine.charAt(i + 1)); } final int cWidth = Fonts.MONOSPACE.charWidth(c); - if (lineWidth + cWidth >= this.width) { + if (lineWidth + cWidth >= width) { out.add(currentFormat.toString() + sb); sb = new StringBuilder(); sb.append(nextFormat); diff --git a/game/client/src/main/java/net/minecraft/client/gui/TextFieldElement.java b/game/client/src/main/java/net/minecraft/client/gui/TextFieldElement.java index 770d8bc57..01790d6fb 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/TextFieldElement.java +++ b/game/client/src/main/java/net/minecraft/client/gui/TextFieldElement.java @@ -9,6 +9,7 @@ import net.minecraft.client.option.GameSettings; import net.minecraft.client.render.font.FontRenderer; import net.minecraft.client.render.window.CursorShape; import net.minecraft.core.util.helper.MathHelper; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.lwjgl.input.Keyboard; @@ -25,12 +26,16 @@ public class TextFieldElement extends Gui implements ITextField private String text = ""; private int maxStringLength; private int cursorCounter; + private int scroll = 0; public boolean isFocused; public boolean isEnabled; public @Nullable Screen parent; private ITextChangeListener textChangeListener; private String placeholder; public boolean drawBackground = true; + public boolean hideCursorWhenFull = false; + public int textColor = 0xE0E0E0; + public int rightPadding = 4; private final TextFieldEditor editor; public TextFieldElement(@Nullable Screen parent, FontRenderer fontRenderer, int xPosition, int yPosition, int width, int height, String defaultText, String placeholder) @@ -145,30 +150,24 @@ public class TextFieldElement extends Gui implements ITextField if(this.isEnabled) { - boolean drawCursor = this.isFocused && (this.cursorCounter / 6) % 2 == 0; - int cursor = this.editor.getCursor(); - int maxDisplayableChars = this.width / this.fontRenderer.getFont().charWidth('_'); - - if(this.text.length() <= maxDisplayableChars-1){ - drawStringShadow(this.fontRenderer, this.text, this.xPosition + 4, this.yPosition + (this.height - 8) / 2, 0xE0E0E0); - } else { - //only draw the part of the string that's maxDisplayableChars chars around the cursor - int begin = Math.max(0,cursor - maxDisplayableChars); - int end = Math.max(maxDisplayableChars,Math.min(this.text.length(),cursor)); - drawStringShadow(this.fontRenderer, this.text.substring(begin, end), this.xPosition + 4, this.yPosition + (this.height - 8) / 2, 0xE0E0E0); - } + boolean cursorHidden = this.hideCursorWhenFull && this.text.length() >= maxLength(); + boolean drawCursor = this.isFocused && (this.cursorCounter / 6) % 2 == 0 && !cursorHidden; + int cursor = Math.max(0, Math.min(this.editor.getCursor(), this.text.length())); + + int room = this.width - 4 - this.rightPadding; + int cursorRoom = cursorHidden ? room : Math.min(room, this.width - 4 - textWidth("_")); + if (cursor < this.scroll) this.scroll = cursor; + while (this.scroll < cursor && textWidth(this.text.substring(this.scroll, cursor)) > cursorRoom) this.scroll++; + while (this.scroll > 0 && textWidth(this.text.substring(this.scroll - 1)) <= room + && textWidth(this.text.substring(this.scroll - 1, cursor)) <= cursorRoom) this.scroll--; + int end = this.scroll; + while (end < this.text.length() && textWidth(this.text.substring(this.scroll, end + 1)) <= room) end++; + + drawStringShadow(this.fontRenderer, this.text.substring(this.scroll, end), this.xPosition + 4, this.yPosition + (this.height - 8) / 2, this.textColor); if (drawCursor) { - int width = MathHelper.ceil(this.fontRenderer.stringWidthDouble(this.text)); - if (cursor < this.text.length()) - { - width = MathHelper.ceil(this.fontRenderer.stringWidthDouble(this.text.substring(0, cursor))); - } - if(width >= this.width-4){ - // width of the text box - the width of the last character - width = (this.width-4) - MathHelper.ceil(this.fontRenderer.stringWidthDouble(this.text.substring(this.text.length()-2, this.text.length()-1))); - } - drawStringShadow(this.fontRenderer, "_", this.xPosition + 4 + width, this.yPosition + (this.height - 8) / 2 + 1, 0xE0E0E0); + int width = textWidth(this.text.substring(this.scroll, cursor)); + drawStringShadow(this.fontRenderer, "_", this.xPosition + 4 + width, this.yPosition + (this.height - 8) / 2 + 1, this.textColor); } } else @@ -177,6 +176,10 @@ public class TextFieldElement extends Gui implements ITextField } } + private int textWidth(@NotNull String s) { + return MathHelper.ceil(this.fontRenderer.stringWidthDouble(s)); + } + public void setMaxStringLength(int i) { this.maxStringLength = i; 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 d71a3d56d..ab4db49be 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 @@ -31,7 +31,6 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.hud.component.HudComponent; import net.minecraft.client.gui.hud.component.HudComponents; import net.minecraft.client.render.Lighting; -import net.minecraft.client.render.dynamictexture.DynamicTexture; import net.minecraft.client.render.terrain.RenderList; import net.minecraft.client.render.terrain.RenderRegion; import net.minecraft.client.render.terrain.TerrainRendererMultiDraw; @@ -108,7 +107,12 @@ public class HudIngame extends Gui { // Render pumpkin overlay final ItemStack headSlotItem = this.mc.thePlayer.inventory.armorItemInSlot(HumanArmorShape.HEAD); if (GameSettings.THIRD_PERSON_VIEW.value == 0 && headSlotItem != null && (headSlotItem.getItem() == Blocks.PUMPKIN_CARVED_IDLE.asItem() || headSlotItem.getItem() == Blocks.PUMPKIN_REDSTONE.asItem())) { - renderPumpkinBlur(width, height); + renderBlurredOverlay(width, height, "/assets/minecraft/textures/misc/pumpkinblur.png"); + } + + // Render diving overlay + if (GameSettings.THIRD_PERSON_VIEW.value == 0 && headSlotItem != null && headSlotItem.getItem() == Items.ARMOR_HELMET_DIVING) { + renderBlurredOverlay(width, height, "/assets/minecraft/textures/misc/divingblur.png"); } // Render portal overlay @@ -592,14 +596,14 @@ public class HudIngame extends Gui { return String.valueOf(i); } - protected void renderPumpkinBlur(int xSize, int ySize) { + protected void renderBlurredOverlay(int xSize, int ySize, @NotNull String path) { GLRenderer.pushFrame(); GLRenderer.disableState(State.DEPTH_TEST); GLRenderer.setAlphaTest(0); GLRenderer.setDepthMask(false); GLRenderer.setBlendFunc(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA); GLRenderer.setColor4f(1.0F, 1.0F, 1.0F, 1.0F); - this.mc.textureManager.loadTexture("/assets/minecraft/textures/misc/pumpkinblur.png").bind(); + this.mc.textureManager.loadTexture(path).bind(); TessellatorGeneral tessellator = GLRenderer.getTessellator(); tessellator.startDrawingQuads(); tessellator.addVertexWithUV(0.0D, ySize, -90D, 0.0D, 1.0D); 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 85beb83ee..cd262378f 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 @@ -12,6 +12,7 @@ import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.core.block.Blocks; import net.minecraft.core.enums.HumanArmorShape; import net.minecraft.core.item.ItemStack; +import net.minecraft.core.item.Items; import net.minecraft.core.net.command.TextFormatting; import net.minecraft.core.player.inventory.container.ContainerInventory; @@ -48,7 +49,12 @@ public class HudIngameDoom // Render pumpkin overlay ItemStack headSlotItem = this.mc.thePlayer.getItemInArmorSlot(HumanArmorShape.HEAD); if (GameSettings.THIRD_PERSON_VIEW.value == 0 && headSlotItem != null && (headSlotItem.getItem() == Blocks.PUMPKIN_CARVED_IDLE.asItem() || headSlotItem.itemID == Blocks.PUMPKIN_REDSTONE.id())) { - renderPumpkinBlur(width, height); + renderBlurredOverlay(width, height, "/assets/minecraft/textures/misc/pumpkinblur.png"); + } + + // Render diving overlay + if (GameSettings.THIRD_PERSON_VIEW.value == 0 && headSlotItem != null && headSlotItem.getItem() == Items.ARMOR_HELMET_DIVING) { + renderBlurredOverlay(width, height, "/assets/minecraft/textures/misc/divingblur.png"); } // Render portal overlay 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 0f3956013..cba362dbc 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 @@ -16,6 +16,7 @@ import net.minecraft.core.enums.ArmorHiddenState; import net.minecraft.core.enums.HumanArmorShape; import net.minecraft.core.item.IArmorItem; import net.minecraft.core.item.Item; +import net.minecraft.core.item.ItemQuiver; import net.minecraft.core.item.ItemStack; import net.minecraft.core.item.block.ItemBlock; import net.minecraft.core.util.collection.NamespaceID; @@ -138,8 +139,7 @@ public class HudComponentArmorBar extends HudComponentMovable { if (hiddenState == ArmorHiddenState.ALWAYS) return false; if (hiddenState == ArmorHiddenState.WHEN_NOT_WEARING) { - ItemStack armorStack; - return mc.thePlayer != null && (armorStack = mc.thePlayer.inventory.armorItemInSlot(this.targetShape)) != null && ArmorState.calculate(armorStack) != ArmorState.EMPTY; + return mc.thePlayer != null && mc.thePlayer.inventory.armorItemInSlot(this.targetShape) != null; } return true; @@ -174,17 +174,15 @@ public class HudComponentArmorBar extends HudComponentMovable { state = ArmorState.INFINITE; } - if (state != ArmorState.EMPTY) { - String itemIcon = resolveItemIcon(item, state, isFlipped); - if (itemIcon != null) { - query = itemIcon; - } else if (!isArmorItem) { - query = slotQuery(item instanceof ItemBlock ? SLOT_GENERIC_BLOCK : SLOT_GENERIC_ITEM); - } else { - query = slotQuery(SLOT_UNKNOWN); - } + String itemIcon = resolveItemIcon(item, state, isFlipped); + if (itemIcon != null) { + query = itemIcon; + } else if (!isArmorItem) { + query = slotQuery(item instanceof ItemBlock ? SLOT_GENERIC_BLOCK : SLOT_GENERIC_ITEM); + } else { + query = slotQuery(SLOT_EMPTY); } - } + } int x = this.getLayout().getComponentX(this, xSizeScreen); int y = this.getLayout().getComponentY(this, ySizeScreen); @@ -315,7 +313,10 @@ public class HudComponentArmorBar extends HudComponentMovable { if (maxDurability <= 0) return INFINITE; int currentDurability = maxDurability - armorStack.getItemDamageForDisplay(); - if (currentDurability <= 0) return EMPTY; + // FIXME fix durability weirdness at some point + if (armorStack.getItem() instanceof ItemQuiver) currentDurability--; + + if (currentDurability < 0) return EMPTY; float durabilityPercentage = (float) currentDurability / maxDurability; if (durabilityPercentage > 0.5f) return FULL; diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentInfoOverlay.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentInfoOverlay.java index 1dc35b596..cb63881c3 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentInfoOverlay.java +++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentInfoOverlay.java @@ -124,11 +124,11 @@ public class HudComponentInfoOverlay extends HudComponentMovable { if (GameSettings.TIME_IN_OVERLAY.value) { int color = (GameSettings.OVERLAY_MODE.value == 2) ? 0xFFFFFF80 : 0xFFFFFFFF; if (GameSettings.OVERLAY_MODE.value == 0) { - addLine(color).append(HudIngame.getTimeString(mc)).append(" ").append(I18n.getInstance().translateKey("unit.day")).append(" ").append(mc.currentWorld.getWorldTime() / Global.DAY_LENGTH_TICKS); + addLine(color).append(HudIngame.getTimeString(mc)).append(" ").append(I18n.getInstance().translateKey("unit.day")).append(" ").append(mc.currentWorld.getDayNatural()); } if (GameSettings.OVERLAY_MODE.value > 0) { addLine(color).append(HudIngame.getTimeString(mc)); - addLine(color).append(I18n.getInstance().translateKey("unit.day")).append(" ").append(mc.currentWorld.getWorldTime() / Global.DAY_LENGTH_TICKS); + addLine(color).append(I18n.getInstance().translateKey("unit.day")).append(" ").append(mc.currentWorld.getDayNatural()); } } } diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentOxygenBar.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentOxygenBar.java index 652119648..d5f058d3a 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentOxygenBar.java +++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentOxygenBar.java @@ -8,7 +8,6 @@ import net.minecraft.client.render.renderer.GLRenderer; import net.minecraft.client.render.renderer.State; import net.minecraft.client.render.texture.stitcher.IconCoordinate; import net.minecraft.client.render.texture.stitcher.TextureRegistry; -import net.minecraft.core.block.material.Materials; public class HudComponentOxygenBar extends HudComponentMovable { private final IconCoordinate air; @@ -76,8 +75,8 @@ public class HudComponentOxygenBar extends HudComponentMovable { boolean isVertical = this.isVertical(); boolean isFlipped = this.isFlipped(); - int numBubbles = (int) Math.ceil(((double) (mc.thePlayer.airSupply - 2) * 10D) / 300D); - int numPops = (int) Math.ceil(((double) mc.thePlayer.airSupply * 10D) / 300D) - numBubbles; + int numBubbles = (int) Math.ceil(((double) (mc.thePlayer.airSupply - 2) * 10D) / mc.thePlayer.getMaxAirSupply()); + int numPops = (int) Math.ceil(((double) mc.thePlayer.airSupply * 10D) / mc.thePlayer.getMaxAirSupply()) - numBubbles; for (int i = 0; i < numBubbles + numPops; i++) { int xIcon; diff --git a/game/client/src/main/java/net/minecraft/client/render/BarrierMarkerRenderer.java b/game/client/src/main/java/net/minecraft/client/render/BarrierMarkerRenderer.java new file mode 100644 index 000000000..c8909b549 --- /dev/null +++ b/game/client/src/main/java/net/minecraft/client/render/BarrierMarkerRenderer.java @@ -0,0 +1,87 @@ +package net.minecraft.client.render; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.render.block.model.BlockModelDispatcher; +import net.minecraft.client.render.camera.ICamera; +import net.minecraft.client.render.renderer.BlendFactor; +import net.minecraft.client.render.renderer.CompareFunc; +import net.minecraft.client.render.renderer.GLRenderer; +import net.minecraft.client.render.renderer.Shaders; +import net.minecraft.client.render.renderer.State; +import net.minecraft.client.render.terrain.ChunkRenderer; +import net.minecraft.client.render.tessellator.TessellatorParticleShader; +import net.minecraft.client.render.texture.stitcher.IconCoordinate; +import net.minecraft.client.render.texture.stitcher.TextureRegistry; +import net.minecraft.core.block.Block; +import net.minecraft.core.block.BlockLogicBarrier; +import net.minecraft.core.block.Blocks; +import net.minecraft.core.block.tag.BlockTags; +import net.minecraft.core.util.helper.LightIndexHelper; +import net.minecraft.core.world.pos.TilePos; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.opengl.GL41; + +public class BarrierMarkerRenderer { + public record Marker(@NotNull TilePos pos, @NotNull Block block) { } + + private static final float HALF_SIZE = 0.5F; + private static final int BUFFER_BYTES = 40 * 1024; + + private static boolean @Nullable [] marked; + + private @Nullable TessellatorParticleShader tessellator; + + public static boolean marks(@NotNull Block block) { + boolean[] table = marked; + + if (table == null) { + table = new boolean[Blocks.blocksList.length]; + for (Block candidate : Blocks.blocksList) if (candidate != null && candidate.hasTag(BlockTags.BARRIER)) table[candidate.id()] = true; + marked = table; + } + + return table[block.id()]; + } + + public void render(@NotNull Minecraft mc, @NotNull ChunkRenderer @Nullable [] renderers, @NotNull ICamera camera, float partialTick) { + if (renderers == null || !BlockLogicBarrier.revealedFor(mc.thePlayer)) return; + if (this.tessellator == null) this.tessellator = new TessellatorParticleShader(BUFFER_BYTES); + + GLRenderer.pushFrame(); + GLRenderer.setColor4f(1f, 1f, 1f, 1f); + GLRenderer.setShader(Shaders.PARTICLE); + GL41.glActiveTexture(GL41.GL_TEXTURE2); + TextureRegistry.worldAtlas.layerTextureMap.get("emissive").bind(); + GL41.glActiveTexture(GL41.GL_TEXTURE3); + TextureRegistry.worldAtlas.layerTextureMap.get("maskColor").bind(); + GL41.glActiveTexture(GL41.GL_TEXTURE0); + TextureRegistry.worldAtlas.bind(); + GLRenderer.enableState(State.BLEND); + GLRenderer.setBlendFunc(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA); + GLRenderer.enableState(State.DEPTH_TEST); + GLRenderer.setDepthFunc(CompareFunc.LESS); + + TessellatorParticleShader t = this.tessellator; + t.setupParticleValues(camera, partialTick); + t.setTranslation(-camera.getX(partialTick), -camera.getY(partialTick), -camera.getZ(partialTick)); + t.startDrawingParticles(); + t.setLightmapCoord1i(LightIndexHelper.lightIndex2i(15, 15)); + t.setColorOpaque3f(1f, 1f, 1f); + + for (ChunkRenderer renderer : renderers) { + if (!renderer.visible) continue; + + for (Marker marker : renderer.barriers) { + IconCoordinate icon = BlockModelDispatcher.getInstance().getDispatch(marker.block()).getOverlayTexture(0); + if (icon == null) continue; + TilePos pos = marker.pos(); + t.addParticle(pos.x + 0.5D, pos.y + 0.5D, pos.z + 0.5D, HALF_SIZE, icon.getIconUMin(), icon.getIconVMin(), icon.getIconUSize(), icon.getIconVSize()); + } + } + + t.drawParticles(); + t.setTranslation(0, 0, 0); + GLRenderer.popFrame(); + } +} 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 06a32b2fc..ca22965d0 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 @@ -3,8 +3,11 @@ package net.minecraft.client.render; import static net.minecraft.client.render.uniform.UniformBlock.N; import net.minecraft.client.option.GameSettings; +import net.minecraft.client.render.camera.EntityCamera; import net.minecraft.client.world.WorldClient; import net.minecraft.core.block.material.Materials; +import net.minecraft.core.entity.IArmorWearing; +import net.minecraft.core.enums.HumanArmorShape; import net.minecraft.core.world.pos.TilePos; import net.minecraft.core.world.type.tag.WorldTypeTags; import org.jetbrains.annotations.NotNull; @@ -71,17 +74,20 @@ public class FogManager { } switch (cameraState) { - case 1: { + case 1: { // in water dest.fogMode = FogState.Mode.EXP; dest.fogDensity = 0.1F; + if (this.mc.activeCamera instanceof EntityCamera camera && camera.mob.hasUnimpededWaterVision()) { + dest.fogDensity = 0.05f; + } break; } - case 2: { + case 2: { // in lava dest.fogMode = FogState.Mode.EXP; dest.fogDensity = 2.0f; break; } - case 3: { + case 3: { // in acid dest.fogMode = FogState.Mode.EXP; dest.fogDensity = 1.2F; dest.fogStart = 0.0f; 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 183d9d988..a54cfe569 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 @@ -95,6 +95,7 @@ public final class RenderGlobal private final TextureManager textureManager; private final List<@NotNull ChunkRenderer> dirtyChunks = new ObjectArrayList<>(); private ChunkRenderer[] chunkRenderers; + private final @NotNull BarrierMarkerRenderer barrierMarkers = new BarrierMarkerRenderer(); private int xChunks; private int yChunks; private int zChunks; @@ -489,6 +490,10 @@ public final class RenderGlobal } + public void renderBarrierMarkers(@NotNull ICamera camera, float partialTick) { + this.barrierMarkers.render(this.mc, this.chunkRenderers, camera, partialTick); + } + public void renderEntities(ICamera camera, float partialTick) { if (this.noEntityRenderFrames > 0) { this.noEntityRenderFrames--; @@ -1893,7 +1898,7 @@ public final class RenderGlobal public void cull(CameraFrustum frustum, float partialTick) { for (int i = 0; i < this.chunkRenderers.length; i++) { - if (!this.chunkRenderers[i].isEmpty() && (!this.chunkRenderers[i].visible || (i + this.cullStep & 0xf) == 0)) { + if ((!this.chunkRenderers[i].isEmpty() || !this.chunkRenderers[i].barriers.isEmpty()) && (!this.chunkRenderers[i].visible || (i + this.cullStep & 0xf) == 0)) { this.chunkRenderers[i].cull(frustum, partialTick); } } 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 c2cf177e9..ff68e4c5e 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 @@ -6,11 +6,7 @@ import static org.lwjgl.opengl.GL41.*; import java.awt.image.BufferedImage; import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import com.mojang.logging.LogUtils; import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; @@ -62,6 +58,7 @@ public class TextureManager { public final List bufferedTextures = new ObjectArrayList<>(); public final Map downloadedTextures = new Object2ObjectOpenHashMap<>(); public final Map dynamicTextures = new Object2ObjectOpenHashMap<>(); + public final Set proceduralMarkedTextures = new HashSet<>(); public final @NotNull TexturePackList texturePacks; @@ -83,12 +80,10 @@ public class TextureManager { this.dynamicTextures.clear(); addNativeDynamicTextures(GameSettings.TEXTURE_ANIMATIONS.value); - if (GameSettings.CUSTOM_TEXTURE_ANIMATIONS.value && GameSettings.TEXTURE_ANIMATIONS.value == TextureAnimation.CUSTOM) { - try { - loadCustomAnimations(errors); - }catch (final TexturePackException e) { - errors.add(e); - } + try { + loadCustomAnimations(errors); + }catch (final TexturePackException e) { + errors.add(e); } addDynamicTextureOverride(new DynamicTextureClock(this.mc), true); @@ -97,54 +92,65 @@ public class TextureManager { } protected void addNativeDynamicTextures(@NotNull TextureAnimation state) { - 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)); + proceduralMarkedTextures.clear(); + + if (state != TextureAnimation.OFF) { + addProceduralDynamicTexture(new DynamicTextureWaterStill(TextureRegistry.getTexture("minecraft:block/fluid/water/still"), TextureRegistry.getTexture("minecraft:block/fluid/water/overlay_boiling"))); + addProceduralDynamicTexture(new DynamicTextureWaterFlow(TextureRegistry.getTexture("minecraft:block/fluid/water/flowing"))); + addProceduralDynamicTexture(new DynamicTextureLavaStill(TextureRegistry.getTexture("minecraft:block/fluid/lava/still"))); + addProceduralDynamicTexture(new DynamicTextureLavaFlowing(TextureRegistry.getTexture("minecraft:block/fluid/lava/flowing"))); + addProceduralDynamicTexture(new DynamicTextureFire(TextureRegistry.getTexture("minecraft:block/fire"), false, false)); + addProceduralDynamicTexture(new DynamicTextureFire(TextureRegistry.getTexture("minecraft:block/fire_cold"), true, false)); + addProceduralDynamicTexture(new DynamicTextureFire(TextureRegistry.getTexture("minecraft:block/fire_sulfuric"), false, true)); final String[] fireflyColors = {"blue", "orange", "green", "red"}; for (final String color : fireflyColors) { - addDynamicTexture(new DynamicTextureFireflyJar(TextureRegistry.getTexture("minecraft:block/lantern_firefly/" + color))); + addProceduralDynamicTexture(new DynamicTextureFireflyJar(TextureRegistry.getTexture("minecraft:block/lantern_firefly/" + color))); } - addDynamicTexture(new DynamicTextureTrommel(this.mc, TextureRegistry.getTexture("minecraft:block/trommel/active_front"), true)); - addDynamicTexture(new DynamicTextureTrommel(this.mc, TextureRegistry.getTexture("minecraft:block/trommel/active_back"), false)); - } - if (state != TextureAnimation.CUSTOM) { - for (final DyeColor c : DyeColor.values()) { - final IconCoordinate cNether = TextureRegistry.getTexture("minecraft:block/portal_nether/" + c.colorID); - assert cNether.hasMeta("animation") : "Coordinate " + cNether.namespaceId + " is expected to have animation data attached!"; - addDynamicTexture(new DynamicTextureCustom(cNether, cNether.getMeta("animation", AnimationProperties.class))); + addProceduralDynamicTexture(new DynamicTextureTrommel(this.mc, TextureRegistry.getTexture("minecraft:block/trommel/active_front"), true)); + addProceduralDynamicTexture(new DynamicTextureTrommel(this.mc, TextureRegistry.getTexture("minecraft:block/trommel/active_back"), false)); - final IconCoordinate cDrift = TextureRegistry.getTexture("minecraft:block/portal_drift/" + c.colorID); - assert cDrift.hasMeta("animation") : "Coordinate " + cDrift.namespaceId + " is expected to have animation data attached!"; - addDynamicTexture(new DynamicTextureCustom(cDrift, cDrift.getMeta("animation", AnimationProperties.class))); + for (final DyeColor c : DyeColor.values()) { + addProceduralCustomTexture("minecraft:block/portal_nether/" + c.colorID); + addProceduralCustomTexture("minecraft:block/portal_drift/" + c.colorID); } + + addProceduralCustomTexture("minecraft:block/fluid/acid/still"); + addProceduralCustomTexture("minecraft:block/fluid/acid/flowing"); + + addProceduralCustomTexture("minecraft:block/fluid/water/overlay_boiling"); } } + private void addProceduralDynamicTexture(@NotNull final DynamicTexture texture) { + this.addDynamicTexture(texture); + this.proceduralMarkedTextures.add(texture.targetTexture.namespaceId); + } + + private void addProceduralCustomTexture(@NotNull final String textureID) { + final IconCoordinate icon = TextureRegistry.getTexture(textureID); + assert icon.hasMeta("animation") : "Coordinate " + icon.namespaceId + " is expected to have animation data attached!"; + addDynamicTexture(new DynamicTextureCustom(icon, icon.getMeta("animation", AnimationProperties.class), true)); + proceduralMarkedTextures.add(icon.namespaceId); + } + protected void addDynamicTexture(DynamicTexture texture) { addDynamicTextureOverride(texture, false); } + protected void addDynamicTextureOverride(DynamicTexture texture, boolean override) { if (!override && this.dynamicTextures.containsKey(texture.targetTexture.namespaceId)) return; this.dynamicTextures.put(texture.targetTexture.namespaceId, texture); } private void loadCustomAnimations(final Collection errors) { - if(!GameSettings.CUSTOM_TEXTURE_ANIMATIONS.value) { - return; - } - for (final AtlasStitcher stitcher : TextureRegistry.atlases){ for (final IconCoordinate c : stitcher.iconMap.values()) { try { if (c.hasMeta("animation")) { LOGGER.debug("Icon '{}' has 'animation' meta!", c.namespaceId); - addDynamicTextureOverride(new DynamicTextureCustom(c, c.getMeta("animation", AnimationProperties.class)), true); + addDynamicTextureOverride(new DynamicTextureCustom(c, c.getMeta("animation", AnimationProperties.class), proceduralMarkedTextures.contains(c.namespaceId)), true); } } catch (final TexturePackException e) { errors.add(e); 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 0af265e37..af7e43339 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 @@ -11,8 +11,11 @@ import net.minecraft.client.render.renderer.Shaders; import net.minecraft.client.render.renderer.State; import net.minecraft.client.render.window.CursorShape; import net.minecraft.client.render.worldtype.WorldTypeFXDispatcher; +import net.minecraft.core.block.Block; +import net.minecraft.core.block.BlockLogicBarrier; import net.minecraft.core.block.Blocks; import net.minecraft.core.block.material.Materials; +import net.minecraft.core.block.tag.BlockTags; import net.minecraft.core.entity.Mob; import net.minecraft.core.entity.animal.MobPig; import net.minecraft.core.world.pos.TilePos; @@ -63,6 +66,7 @@ import org.lwjgl.opengl.GL41; import org.slf4j.Logger; import java.util.Random; +import java.util.function.Predicate; public class WorldRenderer { private static final Logger LOGGER = LogUtils.getLogger(); @@ -143,7 +147,8 @@ public class WorldRenderer { final boolean interactsWithFluid = playerItem != null && playerItem.interactsWithFluid(); // Raytrace blocks - this.mc.objectMouseOver = this.mc.thePlayer.rayCast(blockReach, partialTicks, interactsWithFluid, false, true); + final Predicate> pickable = BlockLogicBarrier.targetableBy(this.mc.thePlayer) ? null : block -> !block.hasTag(BlockTags.BARRIER); + this.mc.objectMouseOver = this.mc.thePlayer.rayCast(blockReach, partialTicks, interactsWithFluid, false, true, pickable); // mc.objectMouseOver = mc.currentWorld.checkBlockCollisionBetweenPoints(pos1, pos2, false, false, true); // Calculate again because block raytrace changes the values @@ -674,6 +679,7 @@ public class WorldRenderer { GLRenderer.setLightMapStrength(1f); this.mc.renderer.beginRenderParticles(partialTicks); particleEngine.renderParticles(this.mc.activeCamera, partialTicks); + renderGlobal.renderBarrierMarkers(this.mc.activeCamera, partialTicks); this.mc.renderer.endRenderParticles(partialTicks); GLRenderer.popFrame(); @@ -789,7 +795,7 @@ public class WorldRenderer { for (int ii = 0; ii < (int) (100F * rainLevel * rainLevel); ii++) { int x = (cameraX + this.random.nextInt(weatherDiameter)) - this.random.nextInt(weatherDiameter); int z = (cameraZ + this.random.nextInt(weatherDiameter)) - this.random.nextInt(weatherDiameter); - int heightmapPosition = world.findTopSolidBlock(x, z); + int heightmapPosition = world.findPrecipitationHeight(x, z); int blockId = world.getBlockId(x, heightmapPosition - 1, z); final @NotNull Biome biome = world.getBlockBiome(x, heightmapPosition, z); @@ -882,7 +888,7 @@ public class WorldRenderer { for (int x = cameraBlockX - radius; x <= cameraBlockX + radius; x++) { for (int z = cameraBlockZ - radius; z <= cameraBlockZ + radius; z++) { - final int terrainHeight = Math.max(world.findTopSolidBlock(x, z), 0); + final int terrainHeight = Math.max(world.findPrecipitationHeight(x, z), 0); queryPos.set(x, terrainHeight, z); final @NotNull Biome biome = world.getBlockBiome(queryPos); 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 bbb0483c0..5a6a86101 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 @@ -241,6 +241,8 @@ public final class BlockModelDispatcher addDispatch(new BlockModelGeneric<>(Blocks.BRIMSAND, loadDataModel("minecraft:block/brimsand"))); addDispatch(new BlockModelGenericCullBounderies<>(Blocks.BEDROCK, loadDataModel("minecraft:block/bedrock"))); + addDispatch(new BlockModelEmpty<>(Blocks.BARRIER).setAllTextures("minecraft:block/barrier")); + addDispatch(new BlockModelEmpty<>(Blocks.BARRIER_INTANGIBLE).setAllTextures("minecraft:block/barrier_intangible")); addDispatch(new BlockModelGenericFullyRotatable<>(Blocks.BONESHALE, loadDataModel("minecraft:block/bone_shale"))); @@ -513,7 +515,7 @@ public final class BlockModelDispatcher addDispatch(new BlockModelSignPainted<>(Blocks.SIGN_WALL_PLANKS_OAK_PAINTED).setAllTextures("minecraft:block/planks/oak")); addDispatch(new BlockModelGenericLayer<>(Blocks.LAYER_SNOW, "minecraft:block/layer/snow")); - addDispatch(new BlockModelGenericLayer<>(Blocks.LAYER_LEAVES_OAK, "minecraft:block/layer/leaves_oak")); + addDispatch(new BlockModelGenericLayerLeaves<>(Blocks.LAYER_LEAVES_OAK, "minecraft:block/layer/leaves_oak")); addDispatch(new BlockModelGenericLayer<>(Blocks.LAYER_SLATE, "minecraft:block/layer/slate")); addDispatch(new BlockModelGenericLayerAsh<>(Blocks.LAYER_ASH)); diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericLayerLeaves.java b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericLayerLeaves.java new file mode 100644 index 000000000..d298b3b6c --- /dev/null +++ b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericLayerLeaves.java @@ -0,0 +1,40 @@ +package net.minecraft.client.render.block.model.generic; + +import net.minecraft.client.option.GameSettings; +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.BlockLogicLayerBase; +import net.minecraft.core.world.WorldSource; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; +import org.useless.dragonfly.models.block.StaticBlockModel; + +public class BlockModelGenericLayerLeaves extends BlockModelGenericLayer { + public final StaticBlockModel[] fancyModels = new StaticBlockModel[7]; + + public BlockModelGenericLayerLeaves(@NotNull Block block, @NotNull String basekey) { + super(block, basekey); + for (int i = 0; i < this.fancyModels.length; i++) { + this.fancyModels[i] = BlockModelDispatcher.loadDataModel(basekey + "_fancy/" + i).asModel(); + } + } + + @Override + public @NotNull StaticBlockModel getModelFromData(int data) { + final int index = Math.min(data & BlockLogicLayerBase.MASK_HEIGHT, this.models.length - 1); + return switch (GameSettings.LEAVES_QUALITY.value) { + case FANCY, SMART -> this.fancyModels[index]; + case FAST -> this.models[index]; + }; + } + + @Override + public @NotNull StaticBlockModel getModel(@NotNull WorldSource source, @NotNull TilePosc tilePosc) { + final int layer = Math.min(source.getBlockData(tilePosc) & BlockLogicLayerBase.MASK_HEIGHT, this.models.length - 1); + return switch (GameSettings.LEAVES_QUALITY.value) { + case FANCY, SMART -> this.fancyModels[layer]; + case FAST -> this.models[layer]; + }; + } +} diff --git a/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureCustom.java b/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureCustom.java index 73a8af518..e31d864ec 100644 --- a/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureCustom.java +++ b/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureCustom.java @@ -29,10 +29,16 @@ public class DynamicTextureCustom extends DynamicTexture { protected int frameLength = 0; protected final boolean tickWhenPaused; - + protected final boolean isProceduralMarked; + public DynamicTextureCustom(IconCoordinate texture, AnimationProperties animationProperties) { + this(texture, animationProperties, false); + } + + public DynamicTextureCustom(IconCoordinate texture, AnimationProperties animationProperties, boolean proceduralMarked) { super(texture); + this.isProceduralMarked = proceduralMarked; this.properties = animationProperties; try { @@ -196,6 +202,7 @@ public class DynamicTextureCustom extends DynamicTexture { } @Override public boolean runUpdates(boolean isPaused) { - return GameSettings.TEXTURE_ANIMATIONS.value != TextureAnimation.OFF && (!isPaused || this.tickWhenPaused); + final TextureAnimation texAnim = GameSettings.TEXTURE_ANIMATIONS.value; + return texAnim == TextureAnimation.CUSTOM || (texAnim == TextureAnimation.PROCEDURAL && isProceduralMarked) && (!isPaused || this.tickWhenPaused); } } diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererFishingBobber.java b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererFishingBobber.java index 7f6126c30..939f0a95d 100644 --- a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererFishingBobber.java +++ b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererFishingBobber.java @@ -24,11 +24,11 @@ public class EntityRendererFishingBobber extends EntityRendererSprite extends MobRenderer { if (itemstack != null) { GLRenderer.pushFrame(); + GLRenderer.setShader(Shaders.ITEM); if (itemHolder.isLeftHanded()) { if (model != null) model.translateToBone("leftItem"); GLRenderer.modelM4f().scale(1, 1, -1); diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPlayer.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPlayer.java index 11157b82d..b2079de6e 100644 --- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPlayer.java +++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPlayer.java @@ -18,6 +18,8 @@ import net.minecraft.client.render.tileentity.TileEntityRenderer; import net.minecraft.core.block.entity.TileEntity; import net.minecraft.core.block.motion.ICarriedBlock; import net.minecraft.core.entity.player.Player; +import net.minecraft.core.enums.HumanArmorShape; +import net.minecraft.core.item.*; import net.minecraft.core.player.gamemode.Gamemodes; import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.world.BlocksContainer; @@ -73,6 +75,30 @@ public class MobRendererPlayer extends MobRendererBipedArmored { activeModel.getTransform("leftArm").visible = false; } activeModel.render(); + + final ItemStack armorItemStack = player.getItemInArmorSlot(HumanArmorShape.CHEST); + if (armorItemStack == null) { + return; + } + + final Item item = armorItemStack.getItem(); + if (item instanceof IArmorItem armorItem) { + if (armorItem.getArmorMaterial() == null) return; + bindTexture(String.format("/assets/%s/textures/armor/%s_%d.png", armorItem.getArmorMaterial().identifier.namespace(), armorItem.getArmorMaterial().identifier.value(), 1)); + } else { + return; + } + + final StaticEntityModel armorModel = getModel("armor.chestplate"); + armorModel.resetBones(); + armorModel.getTransform("chest").visible = false; + + if (isLeft) { + armorModel.getTransform("rightArm").visible = false; + } else { + armorModel.getTransform("leftArm").visible = false; + } + armorModel.render(); } public void drawHeldObject(final Player player, final float partialTick) { diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererWolf.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererWolf.java index fe8fde2ef..3b509eb7f 100644 --- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererWolf.java +++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererWolf.java @@ -2,6 +2,7 @@ package net.minecraft.client.render.entity; import net.minecraft.client.render.item.model.ItemModelDispatcher; import net.minecraft.client.render.renderer.GLRenderer; +import net.minecraft.client.render.renderer.Shaders; import net.minecraft.client.render.renderer.State; import net.minecraft.client.render.tessellator.TessellatorGeneral; import net.minecraft.core.block.Blocks; @@ -126,6 +127,7 @@ public class MobRendererWolf extends MobRenderer { if (itemstack != null) { GLRenderer.pushFrame(); + GLRenderer.setShader(Shaders.ITEM); final boolean isBlock = itemstack.itemID < Blocks.blocksList.length; getModel("main").translateToBone(isBlock ? "mouthBlock" : "mouthItem"); GLRenderer.modelM4f().scale(MobRenderer.ENTITY_RENDER_SCALE, -MobRenderer.ENTITY_RENDER_SCALE, MobRenderer.ENTITY_RENDER_SCALE); 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 9194db182..2eb5dcc12 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 @@ -461,6 +461,11 @@ public class ItemModelDispatcher extends Dispatcher { addDispatch(new ItemModelStandard(Items.STATUE_PERMAFROST)); addDispatch(new ItemModelStandard(Items.STATUE_SLATE)); + addDispatch(new ItemModelStandard(Items.ARMOR_HELMET_DIVING)); + addDispatch(new ItemModelStandard(Items.ARMOR_CHESTPLATE_DIVING)); + addDispatch(new ItemModelStandard(Items.ARMOR_LEGGINGS_DIVING)); + addDispatch(new ItemModelStandard(Items.ARMOR_BOOTS_DIVING)); + 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 34143c39a..aac868896 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 @@ -17,6 +17,7 @@ import net.minecraft.core.util.collection.NamespaceID; import net.minecraft.core.util.helper.LightIndexHelper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.lwjgl.opengl.GL11; import org.useless.dragonfly.DisplayPos; import java.awt.*; @@ -119,72 +120,77 @@ public class ItemModelStandard extends ItemModel{ coordinate.parentAtlas.bind(); if (items3d) { - final float halfThickness = 0.5f/16f; final int pxH = coordinate.height; final int pxW = coordinate.width; + final double texelW = 1.0 / pxW; + final double texelH = 1.0 / pxH; + final float halfThickness = 0.5f/16f; tessellator.startDrawingQuads(); tessellator.setLightmapCoord1i(lightIndex); tessellator.setColor1i(color); - // front - tessellator.setNormal(0, 0, -1); - tessellator.addVertexWithUV(-0.5, 0.5, -halfThickness, cUMin, cVMin); - tessellator.addVertexWithUV( 0.5, 0.5, -halfThickness, cUMax, cVMin); - tessellator.addVertexWithUV( 0.5, -0.5, -halfThickness, cUMax, cVMax); - tessellator.addVertexWithUV(-0.5, -0.5, -halfThickness, cUMin, cVMax); - - // top bottom - for (int h = 0; h < pxH; h++) { - final double y1 = (double) h /pxH; - final double y2 = (double) (h + 1) /pxH; - final double vMin = coordinate.getSubIconV(y1); - final double vMax = coordinate.getSubIconV(y2); - - // top - tessellator.setNormal(0, 1, 0); - tessellator.addVertexWithUV(-0.5, 0.5 - y1, -halfThickness, cUMin, vMin); - tessellator.addVertexWithUV(-0.5, 0.5 - y1, halfThickness, cUMin, vMax); - tessellator.addVertexWithUV( 0.5, 0.5 - y1, halfThickness, cUMax, vMax); - tessellator.addVertexWithUV( 0.5, 0.5 - y1, -halfThickness, cUMax, vMin); - - // bottom - tessellator.setNormal(0, -1, 0); - tessellator.addVertexWithUV(-0.5, 0.5 - y2, -halfThickness, cUMin, vMin); - tessellator.addVertexWithUV( 0.5, 0.5 - y2, -halfThickness, cUMax, vMin); - tessellator.addVertexWithUV( 0.5, 0.5 - y2, halfThickness, cUMax, vMax); - tessellator.addVertexWithUV(-0.5, 0.5 - y2, halfThickness, cUMin, vMax); - } - // left right - for (int w = 0; w < pxW; w++) { - final double x1 = (double) w / pxW; - final double x2 = (double) (w + 1) / pxW; + // FIXME probably mesh these per IconCoordinate(?) as this is not the best for performance + // and also breaks with mipmaps (currently patched in item.fsh) + for (int x = 0; x < pxW; ++x) { + for (int y = 0; y < pxH; ++y) { + final int rx = mirrorX ? pxW - x - 1 : x; + final double xx = x * texelW - 0.5; + final double yy = y * texelH - 0.5; + final double uMin = coordinate.getSubIconU((rx + 0.25) * texelW); + final double vMin = coordinate.getSubIconV((pxH - y - 1 + 0.25) * texelH); + final double uMax = coordinate.getSubIconU((rx + 0.75) * texelW); + final double vMax = coordinate.getSubIconV((pxH - y - 1 + 0.75) * texelH); + + { // Front + tessellator.setNormal(0, 0, -1); + tessellator.addVertexWithUV(xx , yy + texelH, -halfThickness, uMin, vMax); + tessellator.addVertexWithUV(xx + texelW, yy + texelH, -halfThickness, uMax, vMax); + tessellator.addVertexWithUV(xx + texelW, yy , -halfThickness, uMax, vMin); + tessellator.addVertexWithUV(xx , yy , -halfThickness, uMin, vMin); + } + { // Back + tessellator.setNormal(0, 0, 1); + tessellator.addVertexWithUV(xx + texelW, yy, halfThickness, uMax, vMin); + tessellator.addVertexWithUV(xx + texelW, yy + texelH, halfThickness, uMax, vMax); + tessellator.addVertexWithUV(xx , yy + texelH, halfThickness, uMin, vMax); + tessellator.addVertexWithUV(xx , yy , halfThickness, uMin, vMin); + } - final double uMin = coordinate.getSubIconU(mirrorX ? 1 - x1 : x1); - final double uMax = coordinate.getSubIconU(mirrorX ? 1 - x2 : x2); + { // Top + tessellator.setNormal(0, 1, 0); + tessellator.addVertexWithUV(xx , yy + texelH, -halfThickness, uMin, vMin); + tessellator.addVertexWithUV(xx , yy + texelH, halfThickness, uMin, vMin); + tessellator.addVertexWithUV(xx + texelW, yy + texelH, halfThickness, uMax, vMin); + tessellator.addVertexWithUV(xx + texelW, yy + texelH, -halfThickness, uMax, vMin); + } - // right - tessellator.setNormal(-1, 0, 0); - tessellator.addVertexWithUV(x1 - 0.5, 0.5, -halfThickness, uMin, cVMin); - tessellator.addVertexWithUV(x1 - 0.5, -0.5, -halfThickness, uMax, cVMax); - tessellator.addVertexWithUV(x1 - 0.5, -0.5, halfThickness, uMax, cVMax); - tessellator.addVertexWithUV(x1 - 0.5, 0.5, halfThickness, uMin, cVMin); + { // Bottom + tessellator.setNormal(0, -1, 0); + tessellator.addVertexWithUV(xx , yy, -halfThickness, uMin, vMin); + tessellator.addVertexWithUV(xx + texelW, yy, -halfThickness, uMax, vMin); + tessellator.addVertexWithUV(xx + texelW, yy, halfThickness, uMax, vMin); + tessellator.addVertexWithUV(xx , yy, halfThickness, uMin, vMin); + } - // left - tessellator.setNormal(1, 0, 0); - tessellator.addVertexWithUV(x2 - 0.5, 0.5, -halfThickness, uMin, cVMin); - tessellator.addVertexWithUV(x2 - 0.5, 0.5, halfThickness, uMin, cVMin); - tessellator.addVertexWithUV(x2 - 0.5, -0.5, halfThickness, uMax, cVMax); - tessellator.addVertexWithUV(x2 - 0.5, -0.5, -halfThickness, uMax, cVMax); - } + { // Right + tessellator.setNormal(1, 0, 0); + tessellator.addVertexWithUV(xx + texelW, yy , halfThickness, uMin, vMax); + tessellator.addVertexWithUV(xx + texelW, yy , -halfThickness, uMin, vMin); + tessellator.addVertexWithUV(xx + texelW, yy + texelH, -halfThickness, uMax, vMin); + tessellator.addVertexWithUV(xx + texelW, yy + texelH, halfThickness, uMax, vMax); + } + + { // Left + tessellator.setNormal(-1, 0, 0); + tessellator.addVertexWithUV(xx, yy , halfThickness, uMin, vMax); + tessellator.addVertexWithUV(xx, yy + texelH, halfThickness, uMax, vMax); + tessellator.addVertexWithUV(xx, yy + texelH, -halfThickness, uMax, vMin); + tessellator.addVertexWithUV(xx, yy , -halfThickness, uMin, vMin); + } + }} - // back - tessellator.setNormal(0, 0, 1); - tessellator.addVertexWithUV(-0.5, 0.5, halfThickness, cUMin, cVMin); - tessellator.addVertexWithUV(-0.5, -0.5, halfThickness, cUMin, cVMax); - tessellator.addVertexWithUV( 0.5, -0.5, halfThickness, cUMax, cVMax); - tessellator.addVertexWithUV( 0.5, 0.5, halfThickness, cUMax, cVMin); tessellator.draw(); } else { tessellator.startDrawingQuads(); diff --git a/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRenderer.java b/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRenderer.java index 0a6db20a8..592043ae4 100644 --- a/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRenderer.java +++ b/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRenderer.java @@ -10,6 +10,7 @@ import org.jetbrains.annotations.Nullable; import org.joml.Vector3i; import org.joml.primitives.AABBd; +import net.minecraft.client.render.BarrierMarkerRenderer; import net.minecraft.client.render.camera.ICamera; import net.minecraft.client.render.culling.CameraFrustum; import net.minecraft.core.entity.Entity; @@ -29,6 +30,7 @@ public abstract class ChunkRenderer { protected final @NotNull Vector3i size = new Vector3i(); protected final @NotNull List<@NotNull TileEntity> renderableBlockEntities = new ArrayList<>(); protected final @NotNull List<@NotNull TileEntity> globalRenderableBlockEntities; + public final @NotNull List barriers = new ArrayList<>(); protected boolean compiled = false; private final @NotNull Vector3i middlePos = new Vector3i(); @@ -99,6 +101,7 @@ public abstract class ChunkRenderer { this.visible = false; this.compiled = false; + this.barriers.clear(); } public void delete() { 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 c3eb22959..9c743059f 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 @@ -4,6 +4,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import net.minecraft.client.render.BarrierMarkerRenderer; import net.minecraft.client.render.TileEntityRenderDispatcher; import net.minecraft.client.render.block.model.BlockModel; import net.minecraft.client.render.block.model.BlockModelDispatcher; @@ -68,6 +69,7 @@ public class ChunkRendererMultiDraw extends ChunkRenderer { Chunk.isLit = false; final Set lastSpecialTileEntities = new HashSet<>(this.renderableBlockEntities); this.renderableBlockEntities.clear(); + this.barriers.clear(); updates++; @@ -89,6 +91,8 @@ public class ChunkRendererMultiDraw extends ChunkRenderer { final RenderRegion region = this.terrainRenderer.getRenderRegionAtBlockPos(this.pos.x, this.pos.z); TESSELLATOR.setTranslation(-(region.posX << TerrainRendererMultiDraw.REGION_SIZE), 0.0, -(region.posZ << TerrainRendererMultiDraw.REGION_SIZE)); } + if (renderPass == 0 && BarrierMarkerRenderer.marks(block)) this.barriers.add(new BarrierMarkerRenderer.Marker(new TilePos(pos), block)); + if (renderPass == 0 && block.isEntityTile()) { final TileEntity tileentity = chunkCache.getTileEntity(pos); if (tileentity != null && TileEntityRenderDispatcher.instance.hasRenderer(tileentity)) { 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 a0074aa9d..abf515855 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 @@ -5,6 +5,7 @@ import net.minecraft.client.render.TextureManager; import net.minecraft.client.render.item.model.ItemModelDispatcher; import net.minecraft.client.render.renderer.BlendFactor; import net.minecraft.client.render.renderer.GLRenderer; +import net.minecraft.client.render.renderer.Shaders; import net.minecraft.client.render.renderer.State; import net.minecraft.client.render.tessellator.TessellatorGeneral; import net.minecraft.core.Global; @@ -88,6 +89,9 @@ public class TileEntityRendererStatue extends TileEntityRenderer { + if (this.mc == null || this.mc.currentScreen == null) return; + List files = new ArrayList<>(count); + for (int i = 0; i < count; i++) files.add(new File(GLFWDropCallback.getName(names, i))); + this.mc.currentScreen.filesDropped(files); + }); + // Setup Icon if (Minecraft.getOs() != EnumOS.macos) { // MacOs doesn't support icons iconLabel: diff --git a/game/client/src/main/java/net/minecraft/client/util/helper/FileOpener.java b/game/client/src/main/java/net/minecraft/client/util/helper/FileOpener.java index 98f48dd54..2dda8667d 100644 --- a/game/client/src/main/java/net/minecraft/client/util/helper/FileOpener.java +++ b/game/client/src/main/java/net/minecraft/client/util/helper/FileOpener.java @@ -3,35 +3,305 @@ package net.minecraft.client.util.helper; import com.mojang.logging.LogUtils; import net.minecraft.client.Minecraft; import net.minecraft.core.enums.EnumOS; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import java.io.File; import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; public final class FileOpener { private static final Logger LOGGER = LogUtils.getLogger(); + private static final long CLIPBOARD_TIMEOUT_S = 15L; - public static boolean toClipboard(final String path) { - final EnumOS os = Minecraft.getOs(); - switch (os) { - case windows: - return (run("powershell", "-Command %s", "Get-ChildItem \"" + path + "\" | Set-Clipboard")); - case macos: - return (run("osascript", "-e %s", "set the clipboard to (read (POSIX file \"" + path + "\") as {«class PNGf»})")); - case linux: - case solaris: - default: - // Need to use wl-copy instead of xclip for wayland - String XDGSessionType = System.getenv("XDG_SESSION_TYPE"); - - if (XDGSessionType != null && XDGSessionType.equals("wayland")) { - return run("bash", "-c %s", "wl-copy < " + path); - } else { - return run("xclip-copyfile", "%s", path); + private static final ExecutorService CLIPBOARD_THREAD = Executors.newSingleThreadExecutor(r -> { + Thread thread = new Thread(r, "Clipboard image copy"); + thread.setDaemon(true); + return thread; + }); + + private static final String WINDOWS_SCRIPT = """ + $ErrorActionPreference = 'Stop' + Add-Type -AssemblyName System.Windows.Forms, System.Drawing + $path = '%s' + $bytes = [IO.File]::ReadAllBytes($path) + $image = [Drawing.Image]::FromStream((New-Object IO.MemoryStream(,$bytes))) + $data = New-Object Windows.Forms.DataObject + $data.SetImage($image) + $data.SetData('PNG', (New-Object IO.MemoryStream(,$bytes))) + $files = New-Object Collections.Specialized.StringCollection + [void]$files.Add($path) + $data.SetFileDropList($files) + [Windows.Forms.Clipboard]::SetDataObject($data, $true, 20, 100) + """; + + private static final String WINDOWS_COPY_FILE_SCRIPT = """ + $ErrorActionPreference = 'Stop' + Add-Type -AssemblyName System.Windows.Forms + $files = New-Object Collections.Specialized.StringCollection + [void]$files.Add('%s') + $data = New-Object Windows.Forms.DataObject + $data.SetFileDropList($files) + [Windows.Forms.Clipboard]::SetDataObject($data, $true, 20, 100) + """; + + private static final String WINDOWS_READ_SCRIPT = """ + $ErrorActionPreference = 'Stop' + Add-Type -AssemblyName System.Windows.Forms, System.Drawing + [Console]::OutputEncoding = [Text.Encoding]::UTF8 + $out = '%s' + $files = [Windows.Forms.Clipboard]::GetFileDropList() + if ($files.Count -gt 0) { [Console]::Out.Write($files[0]); exit 0 } + $png = [Windows.Forms.Clipboard]::GetData('PNG') + if ($png -is [IO.MemoryStream]) { [IO.File]::WriteAllBytes($out, $png.ToArray()); [Console]::Out.Write($out); exit 0 } + $image = [Windows.Forms.Clipboard]::GetImage() + if ($image) { $image.Save($out, [Drawing.Imaging.ImageFormat]::Png); [Console]::Out.Write($out); exit 0 } + exit 1 + """; + + private static final String MAC_READ_SCRIPT = """ + on run argv + try + return POSIX path of (the clipboard as «class furl») + end try + set f to open for access POSIX file (item 1 of argv) with write permission + set eof f to 0 + write (the clipboard as «class PNGf») to f + close access f + return item 1 of argv + end run + """; + + // GTK fallback + private static final String GTK_COPY_SCRIPT = """ + import os, sys + read, write = os.pipe() + if os.fork(): + os.close(write) + sys.exit(0 if os.read(read, 1) == b'1' else 1) + os.close(read) + os.setsid() + import gi + gi.require_version('Gtk', '3.0') + from gi.repository import Gtk, Gdk, GdkPixbuf + clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) + clipboard.set_image(GdkPixbuf.Pixbuf.new_from_file(sys.argv[1])) + def lost(*_): + if clipboard.get_owner() is None: + Gtk.main_quit() + clipboard.connect('owner-change', lost) + os.write(write, b'1') + os.close(write) + Gtk.main() + """; + + public enum CopyResult {COPIED, FAILED, NEEDS_TOOL} + + public static @NotNull CompletableFuture copyImage(final @NotNull File png) { + return CompletableFuture.supplyAsync(() -> copyImageNow(png), CLIPBOARD_THREAD); + } + + public static @NotNull CompletableFuture copyFile(final @NotNull File file) { + return CompletableFuture.supplyAsync(() -> copyFileNow(file), CLIPBOARD_THREAD); + } + + public static @NotNull CompletableFuture<@Nullable File> readClipboardFile() { + return CompletableFuture.supplyAsync(FileOpener::readClipboardFileNow, CLIPBOARD_THREAD); + } + + private static @NotNull CopyResult copyFileNow(final @NotNull File file) { + String path = file.getAbsolutePath(); + List builders = switch (Minecraft.getOs()) { + case windows -> List.of(powershell(WINDOWS_COPY_FILE_SCRIPT.formatted(path.replace("'", "''")))); + case macos -> List.of(new ProcessBuilder("osascript", "-e", "on run argv", "-e", "set the clipboard to (POSIX file (item 1 of argv))", "-e", "end run", path)); + default -> { + File list = temporary(".uri"); + if (list == null) yield List.of(); + + try { + Files.writeString(list.toPath(), file.toURI() + "\r\n"); + } catch (IOException e) { + yield List.of(); + } + + yield linuxCopy("text/uri-list", list); + } + }; + + return copy(builders, path); + } + + private static @Nullable File readClipboardFileNow() { + File png = temporary(".png"); + if (png == null) return null; + String out = png.getAbsolutePath(); + + String printed = switch (Minecraft.getOs()) { + case windows -> runQuietly(powershell(WINDOWS_READ_SCRIPT.formatted(out.replace("'", "''"))), "clipboard"); + case macos -> runQuietly(new ProcessBuilder("osascript", "-e", MAC_READ_SCRIPT, out), "clipboard"); + default -> readLinuxClipboard(png); + }; + + if (printed == null || printed.isBlank()) return null; + File file = new File(printed.strip()); + + return file.isFile() ? file : null; + } + + private static @Nullable String readLinuxClipboard(@NotNull File png) { + String uris = runQuietly(linuxPaste(new ProcessBuilder("wl-paste", "--no-newline", "--type", "text/uri-list"), + new ProcessBuilder("xclip", "-selection", "clipboard", "-o", "-t", "text/uri-list")), "clipboard"); + + if (uris != null) { + for (String line : uris.split("\r?\n")) { + if (!line.startsWith("file:")) continue; + + try { + return new File(URI.create(line.strip())).getAbsolutePath(); + } catch (IllegalArgumentException ignored) { + } + } + } + + List image = linuxPaste(new ProcessBuilder("wl-paste", "--type", "image/png").redirectOutput(png), + new ProcessBuilder("xclip", "-selection", "clipboard", "-o", "-t", "image/png").redirectOutput(png)); + if (runQuietly(image, "clipboard") == null || png.length() == 0) return null; + + return png.getAbsolutePath(); + } + + private static boolean wayland() { + String display = System.getenv("WAYLAND_DISPLAY"); + + return display != null && !display.isEmpty() || "wayland".equals(System.getenv("XDG_SESSION_TYPE")); + } + + private static @NotNull List linuxPaste(@NotNull ProcessBuilder wlPaste, @NotNull ProcessBuilder xclip) { + return wayland() ? List.of(wlPaste, xclip) : List.of(xclip); + } + + private static @NotNull List linuxCopy(@NotNull String type, @NotNull File source) { + ProcessBuilder xclip = new ProcessBuilder("xclip", "-selection", "clipboard", "-t", type, "-i", source.getAbsolutePath()); + if (!wayland()) return List.of(xclip); + + return List.of(new ProcessBuilder("wl-copy", "--type", type).redirectInput(source), xclip); + } + + private static @NotNull ProcessBuilder powershell(@NotNull String script) { + return new ProcessBuilder("powershell", "-NoProfile", "-NonInteractive", "-STA", "-EncodedCommand", + Base64.getEncoder().encodeToString(script.getBytes(StandardCharsets.UTF_16LE))); + } + + private static @Nullable File temporary(@NotNull String extension) { + try { + File file = File.createTempFile("design", extension); + file.deleteOnExit(); + + return file; + } catch (IOException e) { + LOGGER.error("Couldn't make a temporary file", e); + return null; + } + } + + private static @Nullable String runQuietly(@NotNull List builders, @NotNull String what) { + for (ProcessBuilder builder : builders) { + String printed = runQuietly(builder, what); + if (printed != null) return printed; + } + + return null; + } + + private static @Nullable String runQuietly(@NotNull ProcessBuilder builder, @NotNull String what) { + try { + Process process = builder.redirectError(ProcessBuilder.Redirect.DISCARD).start(); + CompletableFuture printed = CompletableFuture.supplyAsync(() -> { + try { + return process.getInputStream().readAllBytes(); + } catch (IOException e) { + return new byte[0]; } + }); + + if (!process.waitFor(CLIPBOARD_TIMEOUT_S, TimeUnit.SECONDS)) { + process.destroyForcibly(); + LOGGER.warn("Timed out using the clipboard for {}", what); + return null; + } + + return process.exitValue() == 0 ? new String(printed.join(), StandardCharsets.UTF_8) : null; + } catch (IOException e) { + LOGGER.debug("Couldn't run {} for {}", builder.command().get(0), what, e); + return null; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return null; } } + private static @NotNull CopyResult copyImageNow(final @NotNull File png) { + String path = png.getAbsolutePath(); + List builders = switch (Minecraft.getOs()) { + case windows -> List.of(powershell(WINDOWS_SCRIPT.formatted(path.replace("'", "''")))); + case macos -> List.of(new ProcessBuilder("osascript", "-e", "on run argv", + "-e", "set the clipboard to (read (POSIX file (item 1 of argv)) as {«class PNGf»})", "-e", "end run", path)); + default -> { + List linux = new ArrayList<>(linuxCopy("image/png", png)); + ProcessBuilder gtk = new ProcessBuilder("python3", "-c", GTK_COPY_SCRIPT, path); + gtk.environment().put("GDK_BACKEND", "x11"); + linux.add(gtk); + + yield linux; + } + }; + + return copy(builders, path); + } + + private static @NotNull CopyResult copy(@NotNull List builders, @NotNull String path) { + for (ProcessBuilder builder : builders) { + String command = builder.command().get(0); + + try { + Process process = builder.redirectOutput(ProcessBuilder.Redirect.DISCARD).redirectError(ProcessBuilder.Redirect.DISCARD).start(); + + if (!process.waitFor(CLIPBOARD_TIMEOUT_S, TimeUnit.SECONDS)) { + process.destroyForcibly(); + LOGGER.warn("Timed out copying {} to the clipboard with {}", path, command); + continue; + } + + if (process.exitValue() == 0) return CopyResult.COPIED; + + LOGGER.warn("Couldn't copy {} to the clipboard ({} exited with {})", path, command, process.exitValue()); + } catch (IOException e) { + LOGGER.debug("Couldn't run {}", command, e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return CopyResult.FAILED; + } + } + + EnumOS os = Minecraft.getOs(); + if (os == EnumOS.windows || os == EnumOS.macos || builders.isEmpty()) return CopyResult.FAILED; + + LOGGER.warn("Couldn't copy {} to the clipboard with any of {}, installing xclip (X11) or wl-clipboard (Wayland) should fix it", path, + builders.stream().map(builder -> builder.command().get(0)).toList()); + + return CopyResult.NEEDS_TOOL; + } + public static void open(final File file) { if (!openSystem(file.getPath())) { LOGGER.error("unable to open file {}", System.getProperty("os.name")); @@ -42,22 +312,16 @@ public final class FileOpener { private static boolean openSystem(final String what) { final EnumOS os = Minecraft.getOs(); - switch (os) { - case windows: - return (run("explorer", "%s", what)); - case macos: - return (run("open", "%s", what)); - case linux: - case solaris: - default: - return run("kde-open", "%s", what) || run("gnome-open", "%s", what) || run("xdg-open", "%s", what); - - } + return switch (os) { + case windows -> (run("explorer", what)); + case macos -> (run("open", what)); + default -> run("kde-open", what) || run("gnome-open", what) || run("xdg-open", what); + }; } - private static boolean run(final String command, final String arg, final String file) { + private static boolean run(final String command, final String file) { - final String[] args = arg.split(" "); + final String[] args = "%s".split(" "); final String[] parts = new String[args.length + 1]; parts[0] = command; for (int i = 0; i < args.length; i++) { diff --git a/game/client/src/main/java/net/minecraft/client/util/helper/ScreenShot.java b/game/client/src/main/java/net/minecraft/client/util/helper/ScreenShot.java index 55a79d076..4e33f78a3 100644 --- a/game/client/src/main/java/net/minecraft/client/util/helper/ScreenShot.java +++ b/game/client/src/main/java/net/minecraft/client/util/helper/ScreenShot.java @@ -6,7 +6,7 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Objects; -import java.util.function.Supplier; +import java.util.concurrent.CompletableFuture; import com.mojang.logging.LogUtils; @@ -20,6 +20,12 @@ import org.slf4j.Logger; public class ScreenShot { + private enum ScreenShotState { + NONE, + AWAITING_SCREENSHOT, + AWAITING_CLIPBOARD, + } + private static final Logger LOGGER = LogUtils.getLogger(); private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss"); @@ -27,12 +33,15 @@ public class ScreenShot private static int pboWidth = -1; private static int pboHeight = -1; - private static long fence = -1; + private static long glFence = -1; private static @Nullable File destFile = null; + private static @Nullable CompletableFuture copyImageResult = null; + + private static @NotNull ScreenShotState state = ScreenShotState.NONE; public static void saveScreenshot(Minecraft mc, File mcDir, int width, int height) { // Cancel if already screenshotting - if (fence >= 0) { + if (state != ScreenShotState.NONE) { return; } @@ -67,7 +76,7 @@ public class ScreenShot GL41.glBindBuffer(GL41.GL_PIXEL_PACK_BUFFER, transferPbo); // Insert fence - fence = GL41.glFenceSync(GL41.GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + glFence = GL41.glFenceSync(GL41.GL_SYNC_GPU_COMMANDS_COMPLETE, 0); // Copy from FBO to PBO (asynchronous, returns immediately) GL41.glPixelStorei(GL41.GL_PACK_ALIGNMENT, 1); @@ -77,62 +86,85 @@ public class ScreenShot // Unbind PBO GL41.glBindBuffer(GL41.GL_PIXEL_PACK_BUFFER, 0); + state = ScreenShotState.AWAITING_SCREENSHOT; } catch(Exception exception) { LOGGER.error("Failed to save screenshot!", exception); } } public static @Nullable String tickScreenShot() { - if (fence < 0) { + if (state == ScreenShotState.NONE) { + assert(glFence < 0); + assert(copyImageResult == null); + return null; } - // Test fence result (returns immediately) - final int syncResult = GL41.glClientWaitSync(fence, 0, 0); - if (syncResult == GL41.GL_ALREADY_SIGNALED || syncResult == GL41.GL_CONDITION_SATISFIED) { - GL41.glDeleteSync(fence); - fence = -1; + if (state == ScreenShotState.AWAITING_SCREENSHOT) { + assert(glFence >= 0); + assert(copyImageResult == null); - // Bind PBO - GL41.glBindBuffer(GL41.GL_PIXEL_PACK_BUFFER, transferPbo); + // Test fence result (returns immediately) + final int syncResult = GL41.glClientWaitSync(glFence, 0, 0); + if (syncResult == GL41.GL_ALREADY_SIGNALED || syncResult == GL41.GL_CONDITION_SATISFIED) { + GL41.glDeleteSync(glFence); + glFence = -1; - // Map PBO - final @NotNull ByteBuffer pboBuffer = Objects.requireNonNull(GL41.glMapBuffer(GL41.GL_PIXEL_PACK_BUFFER, GL41.GL_READ_ONLY)); + // Bind PBO + GL41.glBindBuffer(GL41.GL_PIXEL_PACK_BUFFER, transferPbo); - // Create flipped buffer - final @NotNull ByteBuffer flipBuffer = MemoryUtil.memCalloc(pboWidth * pboHeight * 4); - for (int y = 0; y < pboHeight; y++) { // Flip image vertically - final int index = y * pboWidth * 4; - flipBuffer.put(index, pboBuffer, pboHeight * pboWidth * 4 - (y + 1) * pboWidth * 4, pboWidth * 4); - } + // Map PBO + final @NotNull ByteBuffer pboBuffer = Objects.requireNonNull(GL41.glMapBuffer(GL41.GL_PIXEL_PACK_BUFFER, GL41.GL_READ_ONLY)); - if (!STBImageWrite.stbi_write_png(destFile.getAbsolutePath(), pboWidth, pboHeight, 4, flipBuffer, pboWidth * 4)) { - LOGGER.error("Failed to save screenshot!"); - return "Failed to save screenshot."; - } + // Create flipped buffer + final @NotNull ByteBuffer flipBuffer = MemoryUtil.memCalloc(pboWidth * pboHeight * 4); + for (int y = 0; y < pboHeight; y++) { // Flip image vertically + final int index = y * pboWidth * 4; + flipBuffer.put(index, pboBuffer, pboHeight * pboWidth * 4 - (y + 1) * pboWidth * 4, pboWidth * 4); + } - // Free flip buffer - MemoryUtil.memFree(flipBuffer); + if (!STBImageWrite.stbi_write_png(destFile.getAbsolutePath(), pboWidth, pboHeight, 4, flipBuffer, pboWidth * 4)) { + LOGGER.error("Failed to save screenshot!"); + state = ScreenShotState.NONE; + return "Failed to save screenshot."; + } - // Unmap PBO - GL41.glUnmapBuffer(GL41.GL_PIXEL_PACK_BUFFER); + // Free flip buffer + MemoryUtil.memFree(flipBuffer); - // Unbind PBO - GL41.glBindBuffer(GL41.GL_PIXEL_PACK_BUFFER, 0); + // Unmap PBO + GL41.glUnmapBuffer(GL41.GL_PIXEL_PACK_BUFFER); - try { - final boolean copiedImage = FileOpener.toClipboard(destFile.getAbsolutePath()); - if (copiedImage) { - return "Saved screenshot as " + destFile.getName() + " and copied to clipboard."; - } - } catch (final @NotNull Exception e) { - return "Saved screenshot as " + destFile.getName(); + // Unbind PBO + GL41.glBindBuffer(GL41.GL_PIXEL_PACK_BUFFER, 0); + + copyImageResult = FileOpener.copyImage(destFile); + state = ScreenShotState.AWAITING_CLIPBOARD; + } else if (syncResult == GL41.GL_WAIT_FAILED) { + GL41.glDeleteSync(glFence); + glFence = -1; + + state = ScreenShotState.NONE; + + throw new IllegalStateException("PBO sync wait failed!"); } - } else if (syncResult == GL41.GL_WAIT_FAILED) { - GL41.glDeleteSync(fence); - fence = -1; + } + + if (state == ScreenShotState.AWAITING_CLIPBOARD) { + assert(glFence < 0); + assert(copyImageResult != null); + + if (copyImageResult.isDone()) { + var result = copyImageResult.getNow(FileOpener.CopyResult.FAILED); + copyImageResult = null; - throw new IllegalStateException("PBO sync wait failed!"); + state = ScreenShotState.NONE; + + return switch (result) { + case COPIED -> "Saved screenshot as " + destFile.getName() + " and copied to clipboard."; + default -> "Saved screenshot as " + destFile.getName() + "."; + }; + } } return null; diff --git a/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/CompiledBlockModelMojangData.java b/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/CompiledBlockModelMojangData.java index 5dfde475f..090c14804 100644 --- a/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/CompiledBlockModelMojangData.java +++ b/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/CompiledBlockModelMojangData.java @@ -133,7 +133,7 @@ public class CompiledBlockModelMojangData { } public static class C_Element { - public static final float UV_INSET = 1/32.0F; + public static final float UV_INSET = 1/1024.0F; public static final int VERTEX_TOP_LEFT = 0; public static final int VERTEX_TOP_RIGHT = 3; @@ -240,10 +240,12 @@ public class CompiledBlockModelMojangData { Direction d = e.getKey(); Face f = e.getValue(); - float minU = (f.u1 + UV_INSET) * BLOCKS_PER_UNIT; - float maxU = (f.u2 - UV_INSET) * BLOCKS_PER_UNIT; - float minV = (f.v1 + UV_INSET) * BLOCKS_PER_UNIT; - float maxV = (f.v2 - UV_INSET) * BLOCKS_PER_UNIT; + float insetU = Math.copySign(UV_INSET, f.u2 - f.u1), + insetV = Math.copySign(UV_INSET, f.v2 - f.v1); + float minU = (f.u1 + insetU) * BLOCKS_PER_UNIT; + float maxU = (f.u2 - insetU) * BLOCKS_PER_UNIT; + float minV = (f.v1 + insetV) * BLOCKS_PER_UNIT; + float maxV = (f.v2 - insetV) * BLOCKS_PER_UNIT; this.tintIndices[i] = f.tintIndex; this.cullfaces[i] = f.cullFace; diff --git a/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/0.json b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/0.json index dd98fd4d1..0287aee1b 100644 --- a/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/0.json +++ b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/0.json @@ -1,8 +1,8 @@ { "parent": "minecraft:block/layer/tinted_height0", "textures": { - "top": "minecraft:block/leaves/oak_fancy", - "bottom": "minecraft:block/leaves/oak_fancy", - "side": "minecraft:block/leaves/oak_fancy" + "top": "minecraft:block/leaves/oak", + "bottom": "minecraft:block/leaves/oak", + "side": "minecraft:block/leaves/oak" } } \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/1.json b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/1.json index 8468c274e..b8175c5b1 100644 --- a/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/1.json +++ b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/1.json @@ -1,8 +1,8 @@ { "parent": "minecraft:block/layer/tinted_height1", "textures": { - "top": "minecraft:block/leaves/oak_fancy", - "bottom": "minecraft:block/leaves/oak_fancy", - "side": "minecraft:block/leaves/oak_fancy" + "top": "minecraft:block/leaves/oak", + "bottom": "minecraft:block/leaves/oak", + "side": "minecraft:block/leaves/oak" } } \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/2.json b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/2.json index 85cfa598e..232d83706 100644 --- a/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/2.json +++ b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/2.json @@ -1,8 +1,8 @@ { "parent": "minecraft:block/layer/tinted_height2", "textures": { - "top": "minecraft:block/leaves/oak_fancy", - "bottom": "minecraft:block/leaves/oak_fancy", - "side": "minecraft:block/leaves/oak_fancy" + "top": "minecraft:block/leaves/oak", + "bottom": "minecraft:block/leaves/oak", + "side": "minecraft:block/leaves/oak" } } \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/3.json b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/3.json index 2ebba1665..4b99584e8 100644 --- a/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/3.json +++ b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/3.json @@ -1,8 +1,8 @@ { "parent": "minecraft:block/layer/tinted_height3", "textures": { - "top": "minecraft:block/leaves/oak_fancy", - "bottom": "minecraft:block/leaves/oak_fancy", - "side": "minecraft:block/leaves/oak_fancy" + "top": "minecraft:block/leaves/oak", + "bottom": "minecraft:block/leaves/oak", + "side": "minecraft:block/leaves/oak" } } \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/4.json b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/4.json index 3bb6dc209..b25210cf5 100644 --- a/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/4.json +++ b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/4.json @@ -1,8 +1,8 @@ { "parent": "minecraft:block/layer/tinted_height4", "textures": { - "top": "minecraft:block/leaves/oak_fancy", - "bottom": "minecraft:block/leaves/oak_fancy", - "side": "minecraft:block/leaves/oak_fancy" + "top": "minecraft:block/leaves/oak", + "bottom": "minecraft:block/leaves/oak", + "side": "minecraft:block/leaves/oak" } } \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/5.json b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/5.json index 84e5ef80e..a78d1ccec 100644 --- a/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/5.json +++ b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/5.json @@ -1,8 +1,8 @@ { "parent": "minecraft:block/layer/tinted_height5", "textures": { - "top": "minecraft:block/leaves/oak_fancy", - "bottom": "minecraft:block/leaves/oak_fancy", - "side": "minecraft:block/leaves/oak_fancy" + "top": "minecraft:block/leaves/oak", + "bottom": "minecraft:block/leaves/oak", + "side": "minecraft:block/leaves/oak" } } \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/6.json b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/6.json index 76914fd1d..0208ef576 100644 --- a/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/6.json +++ b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak/6.json @@ -1,8 +1,8 @@ { "parent": "minecraft:block/layer/tinted_height6", "textures": { - "top": "minecraft:block/leaves/oak_fancy", - "bottom": "minecraft:block/leaves/oak_fancy", - "side": "minecraft:block/leaves/oak_fancy" + "top": "minecraft:block/leaves/oak", + "bottom": "minecraft:block/leaves/oak", + "side": "minecraft:block/leaves/oak" } } \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak_fancy/0.json b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak_fancy/0.json new file mode 100644 index 000000000..dd98fd4d1 --- /dev/null +++ b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak_fancy/0.json @@ -0,0 +1,8 @@ +{ + "parent": "minecraft:block/layer/tinted_height0", + "textures": { + "top": "minecraft:block/leaves/oak_fancy", + "bottom": "minecraft:block/leaves/oak_fancy", + "side": "minecraft:block/leaves/oak_fancy" + } +} \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak_fancy/1.json b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak_fancy/1.json new file mode 100644 index 000000000..8468c274e --- /dev/null +++ b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak_fancy/1.json @@ -0,0 +1,8 @@ +{ + "parent": "minecraft:block/layer/tinted_height1", + "textures": { + "top": "minecraft:block/leaves/oak_fancy", + "bottom": "minecraft:block/leaves/oak_fancy", + "side": "minecraft:block/leaves/oak_fancy" + } +} \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak_fancy/2.json b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak_fancy/2.json new file mode 100644 index 000000000..85cfa598e --- /dev/null +++ b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak_fancy/2.json @@ -0,0 +1,8 @@ +{ + "parent": "minecraft:block/layer/tinted_height2", + "textures": { + "top": "minecraft:block/leaves/oak_fancy", + "bottom": "minecraft:block/leaves/oak_fancy", + "side": "minecraft:block/leaves/oak_fancy" + } +} \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak_fancy/3.json b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak_fancy/3.json new file mode 100644 index 000000000..2ebba1665 --- /dev/null +++ b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak_fancy/3.json @@ -0,0 +1,8 @@ +{ + "parent": "minecraft:block/layer/tinted_height3", + "textures": { + "top": "minecraft:block/leaves/oak_fancy", + "bottom": "minecraft:block/leaves/oak_fancy", + "side": "minecraft:block/leaves/oak_fancy" + } +} \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak_fancy/4.json b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak_fancy/4.json new file mode 100644 index 000000000..3bb6dc209 --- /dev/null +++ b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak_fancy/4.json @@ -0,0 +1,8 @@ +{ + "parent": "minecraft:block/layer/tinted_height4", + "textures": { + "top": "minecraft:block/leaves/oak_fancy", + "bottom": "minecraft:block/leaves/oak_fancy", + "side": "minecraft:block/leaves/oak_fancy" + } +} \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak_fancy/5.json b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak_fancy/5.json new file mode 100644 index 000000000..84e5ef80e --- /dev/null +++ b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak_fancy/5.json @@ -0,0 +1,8 @@ +{ + "parent": "minecraft:block/layer/tinted_height5", + "textures": { + "top": "minecraft:block/leaves/oak_fancy", + "bottom": "minecraft:block/leaves/oak_fancy", + "side": "minecraft:block/leaves/oak_fancy" + } +} \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak_fancy/6.json b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak_fancy/6.json new file mode 100644 index 000000000..76914fd1d --- /dev/null +++ b/game/client/src/main/resources/assets/minecraft/models/block/layer/leaves_oak_fancy/6.json @@ -0,0 +1,8 @@ +{ + "parent": "minecraft:block/layer/tinted_height6", + "textures": { + "top": "minecraft:block/leaves/oak_fancy", + "bottom": "minecraft:block/leaves/oak_fancy", + "side": "minecraft:block/leaves/oak_fancy" + } +} \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/textures/armor/diving_1.png b/game/client/src/main/resources/assets/minecraft/textures/armor/diving_1.png new file mode 100644 index 000000000..0537e320b Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/armor/diving_1.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/armor/diving_2.png b/game/client/src/main/resources/assets/minecraft/textures/armor/diving_2.png new file mode 100644 index 000000000..f573807eb Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/armor/diving_2.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/barrier.png b/game/client/src/main/resources/assets/minecraft/textures/block/barrier.png new file mode 100644 index 000000000..5cb438d9a Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/barrier.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/barrier_intangible.png b/game/client/src/main/resources/assets/minecraft/textures/block/barrier_intangible.png new file mode 100644 index 000000000..8621ffe6a Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/barrier_intangible.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_boots_diving/full.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_boots_diving/full.png new file mode 100644 index 000000000..0fea798ca Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_boots_diving/full.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_boots_diving/half.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_boots_diving/half.png new file mode 100644 index 000000000..bb99b79b7 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_boots_diving/half.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_boots_diving/half_flipped.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_boots_diving/half_flipped.png new file mode 100644 index 000000000..bc7a0f1db Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_boots_diving/half_flipped.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_chestplate_diving/full.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_chestplate_diving/full.png new file mode 100644 index 000000000..d1c443a91 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_chestplate_diving/full.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_chestplate_diving/half.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_chestplate_diving/half.png new file mode 100644 index 000000000..cf7e62beb Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_chestplate_diving/half.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_chestplate_diving/half_flipped.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_chestplate_diving/half_flipped.png new file mode 100644 index 000000000..2ecc43772 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_chestplate_diving/half_flipped.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_helmet_diving/full.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_helmet_diving/full.png new file mode 100644 index 000000000..258bc0ea8 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_helmet_diving/full.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_helmet_diving/half.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_helmet_diving/half.png new file mode 100644 index 000000000..df8979dc5 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_helmet_diving/half.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_helmet_diving/half_flipped.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_helmet_diving/half_flipped.png new file mode 100644 index 000000000..5af617648 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_helmet_diving/half_flipped.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_leggings_diving/full.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_leggings_diving/full.png new file mode 100644 index 000000000..92315135b Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_leggings_diving/full.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_leggings_diving/half.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_leggings_diving/half.png new file mode 100644 index 000000000..c4ef0c87f Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_leggings_diving/half.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_leggings_diving/half_flipped.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_leggings_diving/half_flipped.png new file mode 100644 index 000000000..516b14897 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/armor_bar/item/armor_leggings_diving/half_flipped.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/armor_boots_diving.png b/game/client/src/main/resources/assets/minecraft/textures/item/armor_boots_diving.png new file mode 100644 index 000000000..147f84055 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/armor_boots_diving.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/armor_chestplate_diving.png b/game/client/src/main/resources/assets/minecraft/textures/item/armor_chestplate_diving.png new file mode 100644 index 000000000..5d0050774 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/armor_chestplate_diving.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/armor_helmet_diving.png b/game/client/src/main/resources/assets/minecraft/textures/item/armor_helmet_diving.png new file mode 100644 index 000000000..9da93a293 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/armor_helmet_diving.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/armor_leggings_diving.png b/game/client/src/main/resources/assets/minecraft/textures/item/armor_leggings_diving.png new file mode 100644 index 000000000..564d3a011 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/armor_leggings_diving.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/misc/divingblur.png b/game/client/src/main/resources/assets/minecraft/textures/misc/divingblur.png new file mode 100644 index 000000000..0646bd5f9 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/misc/divingblur.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/misc/divingblur.png.mcmeta b/game/client/src/main/resources/assets/minecraft/textures/misc/divingblur.png.mcmeta new file mode 100644 index 000000000..7275ccde7 --- /dev/null +++ b/game/client/src/main/resources/assets/minecraft/textures/misc/divingblur.png.mcmeta @@ -0,0 +1,5 @@ +{ + "texture": { + "blur": true + } +} \ No newline at end of file diff --git a/game/client/src/main/resources/credits.txt b/game/client/src/main/resources/credits.txt index 7d4766ad1..5d35c7e89 100644 --- a/game/client/src/main/resources/credits.txt +++ b/game/client/src/main/resources/credits.txt @@ -5,10 +5,11 @@ jonkadelic *Developers Bestsoft100 Bigjango -Flamarine +big sir (@.xdddd) Kirisamé Soup (@kirisoup) Martin (@sunsetsatellite) MelonMojito (@melon_mojito) +moechakucha NebulaBC Useless (@uselessbullets) @@ -17,17 +18,22 @@ afk (@away.from.keyboard) Shign (@shign.bright) thaboar +*Music +FullDisplayCollapse +--Mintii (@mintadvance) +--Shign (@shign.bright) + *Community Moderators +camoweed_ Jej Chainstar Orknarok_666 (@derperu) -Silvycakes (@sx22.) +phoebruary *Community Helpers -camoweed_ Cruxy icanttellyou -phoebruary -Snek +Silvycakes (@sx22.) +Snek (@snek8611) *Special Thanks AndroidDr (@Pedro270707) @@ -47,6 +53,7 @@ cloud54 --Marigold flower textures --Stacked flower textures --Timer texture +--Diving suit texture Crowbar --Retired BTA helper DirtPiper @@ -58,6 +65,7 @@ Doop (@brokendoop) --Sorched Logs --Crude steel texture --Statue item textures +--Diving suit textures Gungun974 --Improved packet processing --Bug fixes diff --git a/game/client/src/main/resources/shaders/item.fsh b/game/client/src/main/resources/shaders/item.fsh index af27bde3e..3c2c56da4 100644 --- a/game/client/src/main/resources/shaders/item.fsh +++ b/game/client/src/main/resources/shaders/item.fsh @@ -74,6 +74,7 @@ void main() { vec2 emissiveBrightness = texture(emissivetex, TexCoord).xy; vec4 lightColor = mix(vec4(1, 1, 1, 1), texture(lighttex, vec2(max(LightMapCoord.x, emissiveBrightness.x), max(LightMapCoord.y, emissiveBrightness.y))), uLightMapStrength); vec4 texColor = texture(colortex, TexCoord); + float baseAlpha = textureLod(colortex, TexCoord, 0).a; vec4 maskColor = texture(colormasktex, TexCoord); vec4 c = vec4(mix(vec3(1, 1, 1), Color.rgb, maskColor.r), 1) * uColor; @@ -86,7 +87,7 @@ void main() { FragColor = fColor; - if (FragColor.a < uAlphaTest) { + if (baseAlpha < uAlphaTest) { // Compare against mip level 0 discard; } } diff --git a/game/client/src/main/resources/shaders/terrain.vsh b/game/client/src/main/resources/shaders/terrain.vsh index 15e3df320..a13f24da3 100644 --- a/game/client/src/main/resources/shaders/terrain.vsh +++ b/game/client/src/main/resources/shaders/terrain.vsh @@ -47,5 +47,5 @@ void main() { Shade = unpackShade(aLightShade); TexCoord = aUV; LightMapCoord = unpackLightCoord(aLightShade); - gl_Position = matrices.projection * matrices.view * model * vec4(aPos, 1); + gl_Position = matrices.projection * (matrices.view * (model * vec4(aPos, 1))); } \ No newline at end of file diff --git a/game/client/src/main/resources/shaders/world.vsh b/game/client/src/main/resources/shaders/world.vsh index aebf0b0d8..d33796d50 100644 --- a/game/client/src/main/resources/shaders/world.vsh +++ b/game/client/src/main/resources/shaders/world.vsh @@ -34,7 +34,7 @@ vec2 unpackLightCoord() { void main() { vec4 p = vec4(aPos, 1); - gl_Position = matrices.projection * matrices.view * model * p; + gl_Position = matrices.projection * (matrices.view * (model * p)); TexCoord = (texture * vec4(aUV, 0.0, 1.0)).xy; Color = aColor; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBarrier.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBarrier.java new file mode 100644 index 000000000..b2fc4bcda --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBarrier.java @@ -0,0 +1,49 @@ +package net.minecraft.core.block; + +import net.minecraft.core.block.material.Material; +import net.minecraft.core.block.tag.BlockTags; +import net.minecraft.core.entity.player.Player; +import net.minecraft.core.item.ItemStack; +import net.minecraft.core.item.block.ItemBlock; +import net.minecraft.core.player.gamemode.Gamemodes; +import net.minecraft.core.world.World; +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.joml.primitives.AABBdc; + +public class BlockLogicBarrier + extends BlockLogicTransparent { + private final boolean tangible; + + public static boolean revealedFor(@Nullable Player player) { + ItemStack held = player != null ? player.getHeldItem() : null; + + return held != null && held.getItem() instanceof ItemBlock item && item.getBlock().hasTag(BlockTags.BARRIER); + } + + public static boolean targetableBy(@Nullable Player player) { + return player != null && player.getGamemode() == Gamemodes.CREATIVE || revealedFor(player); + } + + public BlockLogicBarrier(final @NotNull Block block, final @NotNull Material material, final boolean tangible) { + super(block, material); + this.tangible = tangible; + } + + @Override + public boolean isCubeShaped() { + return this.tangible; + } + + @Override + public @Nullable AABBdc getCollisionAABB(final @NotNull WorldSource source, final @NotNull TilePosc tilePos) { + return this.tangible ? super.getCollisionAABB(source, tilePos) : null; + } + + @Override + public int getPistonPushReaction(@NotNull World world, @NotNull TilePosc tilePos) { + return Material.PISTON_CANT_PUSH; + } +} diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerBase.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerBase.java index fdcda18e8..a9b9d220b 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerBase.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerBase.java @@ -10,14 +10,14 @@ import net.minecraft.core.world.World; 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.joml.primitives.AABBd; import org.joml.primitives.AABBdc; public abstract class BlockLogicLayerBase extends BlockLogic implements BlockLogic.MatcherDataEquivalency { - public final @Nullable Block fullBlock; + public final @NotNull Block fullBlock; public static final int MASK_HEIGHT = 0b111; + public static final int MAX_HEIGHT = 6; public BlockLogicLayerBase(@NotNull Block block, @NotNull Block fullBlock, @NotNull Material material) { @@ -63,7 +63,7 @@ public abstract class BlockLogicLayerBase extends BlockLogic implements BlockLog } protected @NotNull AABBd getBoundsFromStateMut(@NotNull WorldSource source, @NotNull TilePosc tilePos) { - int data = Math.min(source.getBlockData(tilePos) & MASK_HEIGHT, 6); + int data = Math.min(source.getBlockData(tilePos) & MASK_HEIGHT, MAX_HEIGHT); float f = (float)(2 * (1 + data)) / 16F; return new AABBd(0.0F, 0.0F, 0.0F, 1.0F, f, 1.0F); } 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 228e9804a..1b1231fff 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 @@ -430,6 +430,12 @@ public final class Blocks { public static final @NotNull Block BONESHALE = register("boneshale", "minecraft:block/boneshale", 261, (b) -> new BlockLogicBoneShale(b, Materials.STONE)) .withSound(BlockSounds.STONE).withHardness(16F).withBlastResistance(6000000F) .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT, BlockTags.NETHER_MOBS_SPAWN); + public static final @NotNull Block BARRIER = register("barrier", "minecraft:block/barrier", 262, (b) -> new BlockLogicBarrier(b, Materials.STONE, true)) + .withSound(BlockSounds.STONE).withSetUnbreakable().withBlastResistance(6000000F) + .withTags(BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.PREVENT_MOB_SPAWNS, BlockTags.BARRIER, BlockTags.CREATIVE_PLACEMENT_ONLY, BlockTags.PRECIPITATION_PASSES_THROUGH); + public static final @NotNull Block BARRIER_INTANGIBLE = register("barrier.intangible", "minecraft:block/barrier_intangible", 263, (b) -> new BlockLogicBarrier(b, Materials.STONE, false)) + .withSound(BlockSounds.STONE).withSetUnbreakable().withBlastResistance(6000000F) + .withTags(BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.PREVENT_MOB_SPAWNS, BlockTags.BARRIER, BlockTags.CREATIVE_PLACEMENT_ONLY, BlockTags.PRECIPITATION_PASSES_THROUGH); public static final @NotNull Block FLUID_WATER_FLOWING = register("fluid.water.flowing", "minecraft:block/fluid_water_flowing", 270, (BlockLogicSupplier) b -> new BlockLogicFluidFlowing(b, Materials.WATER, new FluidWater(), Blocks.FLUID_WATER_STILL)) .withHardness(100F).withLitInteriorSurface(true).withLightBlock(3).withDisabledStats() 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 ea1db34c2..d99f0bf09 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 @@ -1,6 +1,7 @@ package net.minecraft.core.block.tag; import com.mojang.logging.LogUtils; +import net.minecraft.core.block.BlockLogicBarrier; import net.minecraft.core.block.BlockLogicCactus; import net.minecraft.core.block.BlockLogicFence; import net.minecraft.core.block.BlockLogicFenceChainlink; @@ -145,6 +146,18 @@ public abstract class BlockTags * Prevent mobs from spawning inside these blocks. Used for blocks with no collision like rails and redstone components */ public static final Tag> PREVENT_MOB_SPAWNS = Tag.of("prevent_mob_spawns"); + /** + * This block is a barrier {@link BlockLogicBarrier barrierBlock} + */ + public static final Tag> BARRIER = Tag.of("barrier"); + /** + * Block can only be placed in Creative + */ + public static final Tag> CREATIVE_PLACEMENT_ONLY = Tag.of("creative_placement_only"); + /** + * All precipitation types can fall through this block + */ + public static final Tag> PRECIPITATION_PASSES_THROUGH = Tag.of("precipitation_passes_through"); /** * Block can be planted inside a {@link BlockLogicJar JarBlock} */ 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 26685f8cf..b8b74e54d 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 @@ -125,7 +125,6 @@ public abstract class Entity // Water public int airSupply = 300; - protected int airMaxSupply = 300; protected boolean wasInWater = false; // Fire 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 e1a497171..8b9bb2a79 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 @@ -28,12 +28,12 @@ import org.jetbrains.annotations.Nullable; import org.joml.Vector3d; import org.joml.Vector3dc; import org.joml.primitives.AABBd; -import org.joml.primitives.AABBdc; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Predicate; public abstract class Mob extends Entity { public static boolean SPAWN_NO_AI = false; @@ -334,7 +334,12 @@ public abstract class Mob extends Entity { } public void trySuffocate() { + final int maxAirSupply = this.getMaxAirSupply(); + if (isAlive() && isUnderAcidOrWater() && !canBreatheUnderwater()) { + if (this.airSupply > maxAirSupply) { + this.airSupply = maxAirSupply; + } this.airSupply--; if (this.airSupply == -20) { this.airSupply = 0; @@ -349,10 +354,14 @@ public abstract class Mob extends Entity { } this.remainingFireTicks = 0; } else { - this.airSupply = this.airMaxSupply; + this.airSupply = maxAirSupply; } } + public int getMaxAirSupply() { + return 300; + } + public void spawnExplosionParticle() { for (int i = 0; i < 20; i++) { double d = this.random.nextGaussian() * 0.02D; @@ -687,6 +696,18 @@ public abstract class Mob extends Entity { return false; } + public boolean hasUnimpededWaterMovement() { + return false; + } + + public boolean hasUnimpededWaterJumping() { + return false; + } + + public boolean hasUnimpededWaterVision() { + return false; + } + public void moveEntityWithHeading(float moveStrafing, float moveForward) { Block floorBlock = this.world.getBlock(MathHelper.floor(this.x), MathHelper.floor(this.bb.minY) - 1, MathHelper.floor(this.z)); Block floorAboveBlock = this.world.getBlock(MathHelper.floor(this.x), MathHelper.floor(this.bb.minY), MathHelper.floor(this.z)); @@ -726,18 +747,38 @@ public abstract class Mob extends Entity { this.zd *= mult; } else if (isInWater()) { double d = this.y; - moveRelative(moveStrafing, moveForward, 0.02F); + float movementScale = 0.8f; + if (this.hasUnimpededWaterMovement()) { + movementScale = 0.9f; + if (this.onGround) { + if (BlockTags.OVERRIDE_FRICTION.appliesTo(floorAboveBlock)) { + movementScale = floorAboveBlock.friction * 0.9f; + } else { + movementScale = floorBlock.friction * 0.9f; + } + } + + float speedScale = 0.15F / (movementScale * movementScale * movementScale); + moveRelative(moveStrafing, moveForward, this.onGround ? this.speed * speedScale : this.flySpeed); + } else { + moveRelative(moveStrafing, moveForward, 0.02F); + } move(this.xd, this.yd, this.zd); - this.xd *= 0.8D; - this.yd *= 0.8D; - this.zd *= 0.8D; - this.yd -= 0.02D; + this.xd *= movementScale; + this.zd *= movementScale; + if (this.hasUnimpededWaterJumping()) { + this.yd -= 0.04; + this.yd *= 0.9; + } else { + this.yd *= 0.8; + this.yd -= 0.02; + } 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 = 0.6f; - if (b != null) { + if (b != Blocks.AIR) { 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)) { @@ -811,7 +852,6 @@ public abstract class Mob extends Entity { } else { float movementScale = 0.91F; if (this.onGround) { - movementScale = 0.5460001F; if (BlockTags.OVERRIDE_FRICTION.appliesTo(floorAboveBlock)) { movementScale = floorAboveBlock.friction * 0.91F; } else { @@ -819,8 +859,8 @@ public abstract class Mob extends Entity { } } - float f3 = 0.1627714F / (movementScale * movementScale * movementScale); - moveRelative(moveStrafing, moveForward, this.onGround ? this.speed * f3 : this.flySpeed); + float speedScale = 0.1627714F / (movementScale * movementScale * movementScale); + moveRelative(moveStrafing, moveForward, this.onGround ? this.speed * speedScale : this.flySpeed); if (canClimb()) { float f4 = 0.15F; if (this.xd < (double) (-f4)) { @@ -949,7 +989,7 @@ public abstract class Mob extends Entity { boolean inLava = isInLava(); boolean inAcid = isInAcid(); if (this.isJumping) { - if (inWater) { + if (inWater && !this.hasUnimpededWaterJumping()) { this.yd += 0.04D; } else if (inLava) { this.yd += 0.04D; @@ -1157,11 +1197,15 @@ public abstract class Mob extends Entity { public @Nullable HitResult rayCast(double distance, float partialTick, boolean collideWithFluids, boolean ignoreNonColliderBlocks, boolean useSelectorBoxes) { + return this.rayCast(distance, partialTick, collideWithFluids, ignoreNonColliderBlocks, useSelectorBoxes, null); + } + + public @Nullable HitResult rayCast(double distance, float partialTick, boolean collideWithFluids, boolean ignoreNonColliderBlocks, boolean useSelectorBoxes, @Nullable Predicate> pickable) { Vector3dc head = getPosition(partialTick, true); Vector3dc viewDirection = getViewVector(partialTick); assert viewDirection != null; Vector3dc furthestPoint = head.add(viewDirection.x() * distance, viewDirection.y() * distance, viewDirection.z() * distance, new Vector3d()); - return this.world.checkBlockCollisionBetweenPoints(head, furthestPoint, collideWithFluids, ignoreNonColliderBlocks, useSelectorBoxes); + return this.world.checkBlockCollisionBetweenPoints(head, furthestPoint, collideWithFluids, ignoreNonColliderBlocks, useSelectorBoxes, pickable); } public int getMaxSpawnedInChunk() { diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/MobSquid.java b/game/core/src/main/java/net/minecraft/core/entity/animal/MobSquid.java index d21bc8bc2..921242402 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/animal/MobSquid.java +++ b/game/core/src/main/java/net/minecraft/core/entity/animal/MobSquid.java @@ -139,7 +139,7 @@ public class MobSquid extends MobWaterAnimal remainingFireTicks = 0; } else { - airSupply = airMaxSupply; + airSupply = this.getMaxAirSupply(); } } 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 3efdef043..4ddb57fc3 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 @@ -1,8 +1,10 @@ package net.minecraft.core.entity.player; import com.mojang.nbt.tags.*; +import net.minecraft.core.Global; import net.minecraft.core.block.BlockLogicBed; import net.minecraft.core.block.entity.*; +import net.minecraft.core.block.material.Materials; import net.minecraft.core.data.registry.Registries; import net.minecraft.core.entity.*; import net.minecraft.core.entity.animal.MobPig; @@ -664,6 +666,39 @@ public abstract class Player addStat(StatList.mobEncounterStats.get(entity.getDispatcherId()), 1); } + @Override + public int getMaxAirSupply() { + final @Nullable ItemStack headArmor = this.getItemInArmorSlot(HumanArmorShape.HEAD); + if (headArmor != null && headArmor.getItem() == Items.ARMOR_HELMET_DIVING) { + return 5 * 60 * Global.TICKS_PER_SECOND; // 5 minutes' breath time + } + + return super.getMaxAirSupply(); + } + + @Override + public boolean hasUnimpededWaterMovement() { + final @Nullable ItemStack legsArmor = this.getItemInArmorSlot(HumanArmorShape.LEGS); + return legsArmor != null && legsArmor.getItem() == Items.ARMOR_LEGGINGS_DIVING; + } + + @Override + public boolean hasUnimpededWaterJumping() { + final @Nullable ItemStack bootsArmor = this.getItemInArmorSlot(HumanArmorShape.BOOTS); + return bootsArmor != null && bootsArmor.getItem() == Items.ARMOR_BOOTS_DIVING; + } + + @Override + public boolean hasUnimpededWaterVision() { + final @Nullable ItemStack helmetArmor = this.getItemInArmorSlot(HumanArmorShape.HEAD); + return helmetArmor != null && helmetArmor.getItem() == Items.ARMOR_HELMET_DIVING; + } + + public boolean hasUnimpededWaterMining() { + final @Nullable ItemStack chestArmor = this.getItemInArmorSlot(HumanArmorShape.CHEST); + return chestArmor != null && chestArmor.getItem() == Items.ARMOR_CHESTPLATE_DIVING; + } + public int getScore() { return this.score; } @@ -900,7 +935,14 @@ public abstract class Player float defaultBreakSpeed = (this.inventory.getCurrentItem() != null && this.inventory.getCurrentItem().getItem() instanceof ItemToolSword) ? 1.51f : 1.01f; if (this.getGamemode().isProperToolNeededToMine() && str <= defaultBreakSpeed) return 0; // Requires to break and not effective against block - if (isUnderAcidOrWater()) { + if (isUnderLiquid(Materials.WATER)) { + if (hasUnimpededWaterMining()) { + str /= 1.25f; + } else { + str /= 5f; + } + } + if (isUnderLiquid(Materials.ACID)) { str /= 5F; } if (!this.onGround && !canClimb() && this.vehicle == null) { 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 index 6a1183704..124b79dfb 100644 --- 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 @@ -88,7 +88,7 @@ public class ProjectileArrowFlaming extends ProjectileArrow { } else if (hitResult instanceof HitResult.Tile hitTile && !this.world.isClientSide) block_interaction: { final var hitBlock = world.getBlockType(hitTile.tilePos); if (hitBlock == Blocks.BRAZIER_INACTIVE) { - world.setBlockType(hitTile.tilePos, Blocks.BRAZIER_ACTIVE); + world.setBlockTypeNotify(hitTile.tilePos, Blocks.BRAZIER_ACTIVE); break block_interaction; } @@ -103,7 +103,7 @@ public class ProjectileArrowFlaming extends ProjectileArrow { } if (hitBlock == Blocks.ICE) { - world.setBlockTypeNotify(hitTile.tilePos, Blocks.FLUID_WATER_STILL); + world.setBlockTypeNotify(hitTile.tilePos, Blocks.FLUID_WATER_FLOWING); break block_interaction; } 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 8af4c85fd..9f934f079 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 @@ -228,6 +228,11 @@ public final class Items { public static Item STATUE_NETHERRACK; public static Item STATUE_GLOOMSTONE; + public static Item ARMOR_HELMET_DIVING; + public static Item ARMOR_CHESTPLATE_DIVING; + public static Item ARMOR_LEGGINGS_DIVING; + public static Item ARMOR_BOOTS_DIVING; + private static boolean hasInit = false; public static void init(){ if (hasInit) return; @@ -474,5 +479,9 @@ public final class Items { 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); + ARMOR_HELMET_DIVING = (new ItemArmor<>("armor.helmet.diving", "minecraft:item/armor_helmet_diving", 16575, ArmorMaterial.DIVING, HumanArmorShape.HEAD)); + ARMOR_CHESTPLATE_DIVING = (new ItemArmor<>("armor.chestplate.diving", "minecraft:item/armor_chestplate_diving", 16576, ArmorMaterial.DIVING, HumanArmorShape.CHEST)); + ARMOR_LEGGINGS_DIVING = (new ItemArmor<>("armor.leggings.diving", "minecraft:item/armor_leggings_diving", 16577, ArmorMaterial.DIVING, HumanArmorShape.LEGS)); + ARMOR_BOOTS_DIVING = (new ItemArmor<>("armor.boots.diving", "minecraft:item/armor_boots_diving", 16578, ArmorMaterial.DIVING, HumanArmorShape.BOOTS)); } } diff --git a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlock.java b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlock.java index 7f2228482..067fd5b11 100644 --- a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlock.java +++ b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlock.java @@ -3,10 +3,12 @@ package net.minecraft.core.item.block; import net.minecraft.core.block.Block; import net.minecraft.core.block.BlockLogic; 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.IPlaceable; import net.minecraft.core.item.Item; import net.minecraft.core.item.ItemStack; +import net.minecraft.core.player.gamemode.Gamemodes; import net.minecraft.core.util.helper.Direction; import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.World; @@ -45,6 +47,8 @@ public class ItemBlock extends Item implements IPlaceable. @NotNull ItemStack selfStack, @NotNull World world, @Nullable Player player, @NotNull TilePosc blockPos, @NotNull Side side, double xHit, double yHit ) { + if (this.block.hasTag(BlockTags.CREATIVE_PLACEMENT_ONLY) && (player == null || player.getGamemode() != Gamemodes.CREATIVE)) return false; + return this.placeOnBlock(selfStack, world, player, blockPos, side, xHit, yHit); } @@ -54,6 +58,7 @@ public class ItemBlock extends Item implements IPlaceable. @NotNull TileEntityActivator activator, @NotNull Random random, @NotNull TilePosc blockPos, @NotNull Direction direction, double offX, double offY, double offZ ) { + if (this.block.hasTag(BlockTags.CREATIVE_PLACEMENT_ONLY)) return; this.placeByActivator(selfStack, world, activator, random, blockPos, direction, offX, offY, offZ); } } diff --git a/game/core/src/main/java/net/minecraft/core/item/material/ArmorMaterial.java b/game/core/src/main/java/net/minecraft/core/item/material/ArmorMaterial.java index a97e2f046..497210d9b 100644 --- a/game/core/src/main/java/net/minecraft/core/item/material/ArmorMaterial.java +++ b/game/core/src/main/java/net/minecraft/core/item/material/ArmorMaterial.java @@ -88,4 +88,6 @@ public class ArmorMaterial { .withProtectionPercentage(FIRE, 55.0f) .withProtectionPercentage(FALL, 55.0f) ); + public static final ArmorMaterial DIVING = register(new ArmorMaterial(NamespaceID.fromPool("minecraft", "diving"), 800) + ); } diff --git a/game/core/src/main/java/net/minecraft/core/net/packet/PacketCustomPayload.java b/game/core/src/main/java/net/minecraft/core/net/packet/PacketCustomPayload.java index ca444b787..faa12834d 100644 --- a/game/core/src/main/java/net/minecraft/core/net/packet/PacketCustomPayload.java +++ b/game/core/src/main/java/net/minecraft/core/net/packet/PacketCustomPayload.java @@ -52,11 +52,9 @@ public class PacketCustomPayload extends Packet { public void read(DataInputStream in) throws IOException { this.channel = readStringUTF8(in, MAX_CHANNEL_SIZE); int length = in.readInt(); - - if(length > 0 && length < 32768) { - this.data = new byte[length]; - in.readFully(data); - } + if (length < 0 || length > 32768) throw new IOException("Payload of " + length + " bytes is out of range"); + this.data = new byte[length]; + in.readFully(data); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/net/packet/PacketServerIcon.java b/game/core/src/main/java/net/minecraft/core/net/packet/PacketServerIcon.java index 5116f4138..70ebdb7fc 100644 --- a/game/core/src/main/java/net/minecraft/core/net/packet/PacketServerIcon.java +++ b/game/core/src/main/java/net/minecraft/core/net/packet/PacketServerIcon.java @@ -8,6 +8,7 @@ import java.io.DataOutputStream; import java.io.IOException; public class PacketServerIcon extends Packet { + private static final int MAX_SIZE = 1 << 20; public byte[] image; public PacketServerIcon() { @@ -19,8 +20,11 @@ public class PacketServerIcon extends Packet { @Override public void read(DataInputStream dis) throws IOException { - image = new byte[dis.readInt()]; - dis.read(image); + int length = dis.readInt(); + if (length < 0 || length > MAX_SIZE) throw new IOException("Server icon of " + length + " bytes is too large"); + image = new byte[length]; + dis.readFully(image); // read() can return before the whole icon has arrived + } @Override diff --git a/game/core/src/main/java/net/minecraft/core/player/inventory/CreativeMenuContents.java b/game/core/src/main/java/net/minecraft/core/player/inventory/CreativeMenuContents.java index 88a17f3af..08c882825 100644 --- a/game/core/src/main/java/net/minecraft/core/player/inventory/CreativeMenuContents.java +++ b/game/core/src/main/java/net/minecraft/core/player/inventory/CreativeMenuContents.java @@ -128,6 +128,9 @@ public final class CreativeMenuContents { addRecords(list); newPage(list); + + addCreatives(list); + newPage(list); } private static void addTools(@NotNull List list) { @@ -193,7 +196,7 @@ public final class CreativeMenuContents { list.add(new ItemStack(Items.WAND_MONSTER_SPAWNER)); list.add(new ItemStack(Items.WAND_NBT)); list.add(new ItemStack(Items.TOOL_FISHINGROD)); - addGap(list, 1); + list.add(new ItemStack(Items.ARMOR_QUIVER)); list.add(new ItemStack(Items.TOOL_COMPASS)); newLine(list); @@ -201,7 +204,7 @@ public final class CreativeMenuContents { list.add(new ItemStack(Items.AMMO_ARROW)); list.add(new ItemStack(Items.AMMO_ARROW_GOLD)); list.add(new ItemStack(Items.AMMO_ARROW_FLAMING)); - addGap(list, 1); + list.add(new ItemStack(Items.ARMOR_QUIVER_GOLD)); list.add(new ItemStack(Items.TOOL_CLOCK)); newLine(list); @@ -629,7 +632,7 @@ public final class CreativeMenuContents { list.add(new ItemStack(Items.ARMOR_LEGGINGS_LEATHER)); list.add(new ItemStack(Items.ARMOR_BOOTS_LEATHER)); list.add(new ItemStack(Items.ARMOR_WOLF_LEATHER)); - list.add(new ItemStack(Items.ARMOR_QUIVER)); + list.add(new ItemStack(Items.ARMOR_BOOTS_ICESKATES)); newLine(list); list.add(new ItemStack(Items.ARMOR_HELMET_CHAINMAIL)); @@ -637,7 +640,7 @@ public final class CreativeMenuContents { list.add(new ItemStack(Items.ARMOR_LEGGINGS_CHAINMAIL)); list.add(new ItemStack(Items.ARMOR_BOOTS_CHAINMAIL)); list.add(new ItemStack(Items.ARMOR_WOLF_CHAINMAIL)); - list.add(new ItemStack(Items.ARMOR_QUIVER_GOLD)); + list.add(new ItemStack(Items.ARMOR_HELMET_DIVING)); newLine(list); list.add(new ItemStack(Items.ARMOR_HELMET_IRON)); @@ -645,7 +648,7 @@ public final class CreativeMenuContents { list.add(new ItemStack(Items.ARMOR_LEGGINGS_IRON)); list.add(new ItemStack(Items.ARMOR_BOOTS_IRON)); list.add(new ItemStack(Items.ARMOR_WOLF_IRON)); - list.add(new ItemStack(Items.ARMOR_BOOTS_ICESKATES)); + list.add(new ItemStack(Items.ARMOR_CHESTPLATE_DIVING)); newLine(list); list.add(new ItemStack(Items.ARMOR_HELMET_GOLD)); @@ -653,6 +656,7 @@ public final class CreativeMenuContents { list.add(new ItemStack(Items.ARMOR_LEGGINGS_GOLD)); list.add(new ItemStack(Items.ARMOR_BOOTS_GOLD)); list.add(new ItemStack(Items.ARMOR_WOLF_GOLD)); + list.add(new ItemStack(Items.ARMOR_LEGGINGS_DIVING)); newLine(list); list.add(new ItemStack(Items.ARMOR_HELMET_DIAMOND)); @@ -660,6 +664,7 @@ public final class CreativeMenuContents { list.add(new ItemStack(Items.ARMOR_LEGGINGS_DIAMOND)); list.add(new ItemStack(Items.ARMOR_BOOTS_DIAMOND)); list.add(new ItemStack(Items.ARMOR_WOLF_DIAMOND)); + list.add(new ItemStack(Items.ARMOR_BOOTS_DIVING)); newLine(list); list.add(new ItemStack(Items.ARMOR_HELMET_STEEL)); @@ -915,6 +920,11 @@ public final class CreativeMenuContents { list.add(new ItemStack(Items.RECORD_DOG)); } + private static void addCreatives(@NotNull List list){ + addBlock(list, Blocks.BARRIER); + addBlock(list, Blocks.BARRIER_INTANGIBLE); + } + private static void addBucketVariants(List list, Item item) { if (item instanceof ItemBucket itemBucket) { list.add(new ItemStack(item)); 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 6386362a1..301a08b7f 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 @@ -79,6 +79,7 @@ import java.util.Random; import java.util.Set; import java.util.TreeSet; import java.util.UUID; +import java.util.function.Predicate; import static net.minecraft.core.Global.DAY_LENGTH_TICKS; import static net.minecraft.core.Global.isServer; @@ -142,6 +143,9 @@ public abstract class World implements MutableWorldSource { private long runtime = 0; public int dayCountLastTick; + private float celestialAngleLast; + private float celestialAngle; + private final @NotNull ChunkProvider chunkProvider; private final @NotNull LevelStorage levelStorage; private final @NotNull LevelData levelData; @@ -221,6 +225,7 @@ public abstract class World implements MutableWorldSource { } } this.updateSkyBrightness(); + this.celestialAngle = this.celestialAngleLast = this.getWorldType().getCelestialAngle(this, this.getWorldTime(), 0); } // Usually called when a world is loaded or generated (Singleplayer & Server) @@ -1111,6 +1116,10 @@ public abstract class World implements MutableWorldSource { } public @Nullable HitResult checkBlockCollisionBetweenPoints(@NotNull final Vector3dc start, @NotNull final Vector3dc end, final boolean shouldCollideWithFluids, final boolean ignoreNonColliderBlocks, final boolean useSelectorBoxes) { + return this.checkBlockCollisionBetweenPoints(start, end, shouldCollideWithFluids, ignoreNonColliderBlocks, useSelectorBoxes, null); + } + + public @Nullable HitResult checkBlockCollisionBetweenPoints(@NotNull final Vector3dc start, @NotNull final Vector3dc end, final boolean shouldCollideWithFluids, final boolean ignoreNonColliderBlocks, final boolean useSelectorBoxes, final @Nullable Predicate> pickable) { if (!start.isFinite()) { return null; } @@ -1129,7 +1138,7 @@ public abstract class World implements MutableWorldSource { } else { aabb = block.getCollisionAABB(this, blockStart); } - if ((!ignoreNonColliderBlocks || aabb != null) && block.canCollideCheck(meta, shouldCollideWithFluids)) { + if ((!ignoreNonColliderBlocks || aabb != null) && block.canCollideCheck(meta, shouldCollideWithFluids) && (pickable == null || pickable.test(block))) { final HitResult hitResult = block.collisionRayTrace(this, blockStart, start2, end2, useSelectorBoxes); if (hitResult != null) { return hitResult; @@ -1237,7 +1246,7 @@ public abstract class World implements MutableWorldSource { aabb1 = block1.getCollisionAABB(this, blockStart); } final int metadata1 = this.getBlockData(blockStart); - if ((!ignoreNonColliderBlocks || aabb1 != null) && block1.canCollideCheck(metadata1, shouldCollideWithFluids)) { + if ((!ignoreNonColliderBlocks || aabb1 != null) && block1.canCollideCheck(metadata1, shouldCollideWithFluids) && (pickable == null || pickable.test(block1))) { final HitResult hitResult = block1.collisionRayTrace(this, blockStart, start2, end2, useSelectorBoxes); if (hitResult != null) { return hitResult; @@ -1510,11 +1519,10 @@ public abstract class World implements MutableWorldSource { return bright * 0.8f + 0.2f; } - public float getCelestialAngle(float partialTick) { - if (!this.getGameRuleValue(GameRules.DO_DAY_CYCLE)) { - partialTick = 1.0f; - } - return this.getWorldType().getCelestialAngle(this, this.levelData.getWorldTime(), partialTick); + public float getCelestialAngle(final float partialTick) { + if (!this.getGameRuleValue(GameRules.DO_DAY_CYCLE)) return this.celestialAngle; + + return org.joml.Math.lerp(this.celestialAngleLast, this.celestialAngle, partialTick); } @@ -1535,6 +1543,19 @@ public abstract class World implements MutableWorldSource { return -1; } + public int findPrecipitationHeight(final int x, final int z) { + final Chunk chunk = this.getChunkFromBlockCoords(x, z); + final ChunkTilePos pos = new ChunkTilePos(x & (Chunk.CHUNK_SIZE_X - 1), this.getHeightBlocks() - 1, z & (Chunk.CHUNK_SIZE_Z - 1)); + + for (; pos.y >= 0; pos.y--) { + final Block block = Blocks.getBlock(chunk.getBlockId(pos)); + final Material material = block.getMaterial(); + if ((material.blocksMotion() || material.isLiquid()) && !block.hasTag(BlockTags.PRECIPITATION_PASSES_THROUGH)) return pos.y + 1; + } + + return -1; + } + public int findTopSolidNonLiquidBlock(int x, int z) { final Chunk chunk = this.getChunkFromBlockCoords(x, z); int y = this.getHeightBlocks() - 1; @@ -2146,6 +2167,9 @@ public abstract class World implements MutableWorldSource { } public void tick() { + this.celestialAngleLast = this.celestialAngle; + this.celestialAngle = this.getWorldType().getCelestialAngle(this, this.levelData.getWorldTime(), 0); + Debug.push("misc"); this.immediatelyUpdatedPositions.clear(); Debug.change("weather"); @@ -2782,6 +2806,15 @@ public abstract class World implements MutableWorldSource { return this.levelData.getWorldTime(); } + /** + * Used for getting the current day for user facing display, where starting the + * count from 1 would be more intuitive. + * @return the current day, rounded towards positive infinity (ceil). + */ + public long getDayNatural() { + return Math.floorDiv(this.getWorldTime(), DAY_LENGTH_TICKS) + 1; + } + public long getTotalWorldTime() { return this.levelData.getTotalWorldTime(); } diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureLabyrinth.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureLabyrinth.java index f922fa452..f1753595e 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureLabyrinth.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureLabyrinth.java @@ -21,6 +21,7 @@ import net.minecraft.core.world.biome.Biome; import net.minecraft.core.block.Blocks; import net.minecraft.core.world.biome.Biomes; import net.minecraft.core.world.pos.TilePos; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Random; @@ -163,7 +164,16 @@ public class WorldFeatureLabyrinth extends WorldFeature treasureItem = Items.ARMOR_BOOTS_ICESKATES.getDefaultStack(); } else { spawnerMonsters.addEntry("ArmouredZombie", 2); - treasureItem = Items.ARMOR_QUIVER_GOLD.getDefaultStack(); + + final @NotNull Item @NotNull[] treasureItems = { + Items.ARMOR_QUIVER_GOLD, + Items.ARMOR_BOOTS_DIVING, + Items.ARMOR_LEGGINGS_DIVING, + Items.ARMOR_CHESTPLATE_DIVING, + Items.ARMOR_HELMET_DIVING + }; + int treasureIndex = random.nextInt(0, treasureItems.length); + treasureItem = treasureItems[treasureIndex].getDefaultStack(); } if(canReplace(world, x, y, z)) { diff --git a/game/core/src/main/java/net/minecraft/core/world/season/SeasonManager.java b/game/core/src/main/java/net/minecraft/core/world/season/SeasonManager.java index df8473bbc..b161c89f8 100644 --- a/game/core/src/main/java/net/minecraft/core/world/season/SeasonManager.java +++ b/game/core/src/main/java/net/minecraft/core/world/season/SeasonManager.java @@ -33,10 +33,12 @@ public abstract class SeasonManager * The current world this season manager applies to. */ protected final World world; + protected final int seasonOffsetTicks; // Temporary until 8.1 public SeasonManager(World world) { this.world = world; + this.seasonOffsetTicks = this.world.getWorldType().getSeasonTimeOffsetTicks(); } /** diff --git a/game/core/src/main/java/net/minecraft/core/world/season/SeasonManagerCycle.java b/game/core/src/main/java/net/minecraft/core/world/season/SeasonManagerCycle.java index e3a3997c7..0e9976989 100644 --- a/game/core/src/main/java/net/minecraft/core/world/season/SeasonManagerCycle.java +++ b/game/core/src/main/java/net/minecraft/core/world/season/SeasonManagerCycle.java @@ -76,7 +76,7 @@ public final class SeasonManagerCycle @Override public Season getCurrentSeason() { - long worldTime = world.getWorldTime(); + long worldTime = world.getWorldTime() + this.seasonOffsetTicks; if (worldTime == lastQueryTime) return lastQueredSeason; int yearTime = (int)(worldTime % yearLengthTicks); int acc = 0; @@ -106,7 +106,7 @@ public final class SeasonManagerCycle @Override public float getSeasonProgress() { - long worldTime = world.getWorldTime(); + long worldTime = world.getWorldTime() + this.seasonOffsetTicks; int yearTime = (int)(worldTime % yearLengthTicks); int acc = 0; int seasonTime = -1; @@ -130,7 +130,7 @@ public final class SeasonManagerCycle public float getYearProgress() { - long worldTime = world.getWorldTime(); + long worldTime = world.getWorldTime() + this.seasonOffsetTicks; int yearTime = (int)(worldTime % yearLengthTicks); return (float)yearTime / (float)yearLengthTicks; diff --git a/game/core/src/main/java/net/minecraft/core/world/type/WorldType.java b/game/core/src/main/java/net/minecraft/core/world/type/WorldType.java index 4d1a3dd74..239d9df8d 100644 --- a/game/core/src/main/java/net/minecraft/core/world/type/WorldType.java +++ b/game/core/src/main/java/net/minecraft/core/world/type/WorldType.java @@ -47,6 +47,7 @@ public abstract class WorldType private final int fillerBlockId; private final int dayNightCycleTicks; private final boolean mayRespawn; + private final int seasonTimeOffsetTicks; public WorldType(Properties properties) { this.languageKey = properties.languageKey; @@ -81,6 +82,7 @@ public abstract class WorldType this.fillerBlockId = properties.fillerBlock == null ? 0 : properties.fillerBlock.id(); this.dayNightCycleTicks = properties.dayNightCycleTicks; this.mayRespawn = properties.mayRespawn; + this.seasonTimeOffsetTicks = properties.seasonTimeOffsetTicks; for (final @NotNull Tag tag : properties.tags) { tag.tag(this); @@ -119,6 +121,10 @@ public abstract class WorldType return seasonConfig; } + public int getSeasonTimeOffsetTicks() { + return seasonTimeOffsetTicks; + } + public int getMinY(final @NotNull WorldSource world) { // return world.getWorldSetting(WorldSettingNodes.WORLD_HEIGHT_BOTTOM) * WorldHeightSettingNode.VALUE_SCALE; return this.minY; @@ -339,6 +345,7 @@ public abstract class WorldType private int dayNightCycleTicks = Global.DAY_LENGTH_TICKS; private boolean mayRespawn = false; private final @NotNull List> tags = new ArrayList<>(); + private int seasonTimeOffsetTicks; private Properties(String languageKey) { this.languageKey = languageKey; @@ -373,6 +380,11 @@ public abstract class WorldType return this; } + public @NotNull Properties withSeasonTimeOffset(final int offsetTicks) { + this.seasonTimeOffsetTicks = offsetTicks; + return this; + } + public @NotNull Properties brightnessRamp(float[] brightnessRamp) { this.brightnessRamp = brightnessRamp; return this; diff --git a/game/core/src/main/java/net/minecraft/core/world/type/nether/WorldTypeNether.java b/game/core/src/main/java/net/minecraft/core/world/type/nether/WorldTypeNether.java index da9180de2..ddbf1ad0d 100644 --- a/game/core/src/main/java/net/minecraft/core/world/type/nether/WorldTypeNether.java +++ b/game/core/src/main/java/net/minecraft/core/world/type/nether/WorldTypeNether.java @@ -22,6 +22,7 @@ public class WorldTypeNether .oceanBlocks(Blocks.FLUID_LAVA_STILL, Blocks.FLUID_WATER_STILL) .fillerBlock(Blocks.COBBLE_NETHERRACK) .withCeiling() + .withSeasonTimeOffset(72000) .bounds(0, 255, 64 + 32); } @@ -35,13 +36,6 @@ public class WorldTypeNether return brightnessRamp; } - @Override - public void onWorldCreation(World world) { - super.onWorldCreation(world); - - world.setWorldTime(72000); - } - @Override public @NotNull BiomeProvider createBiomeProvider(World world) { return new BiomeProviderNether(world); diff --git a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworld.java b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworld.java index b7dd03970..95c773c59 100644 --- a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworld.java +++ b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworld.java @@ -24,7 +24,7 @@ public class WorldTypeOverworld extends WorldType { public void onWorldCreation(World world) { super.onWorldCreation(world); - world.setWorldTime(72000 + 3000); + world.setWorldTime(3000); } public static @NotNull Properties defaultProperties(@NotNull String translationKey) { @@ -39,6 +39,7 @@ public class WorldTypeOverworld extends WorldType { ) .oceanBlocks(Blocks.FLUID_WATER_STILL) .fillerBlock(Blocks.STONE) + .withSeasonTimeOffset(72000) .allowRespawn(); } diff --git a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherSnow.java b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherSnow.java index 29b900c7b..8ed2f6db6 100644 --- a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherSnow.java +++ b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherSnow.java @@ -48,7 +48,7 @@ public class WeatherSnow int worldX = chunk.pos.x * 16 + x; for (int z = 0; z < 16; z++) { int worldZ = chunk.pos.z * 16 + z; - int y = world.findTopSolidBlock(worldX, worldZ); + int y = world.findPrecipitationHeight(worldX, worldZ); Biome biome = world.getBlockBiome(worldX, y, worldZ); if (biome.blockedWeathers.contains(this)) { @@ -86,7 +86,7 @@ public class WeatherSnow boolean snow = rand.nextInt(probability) == 0; - int y = world.findTopSolidBlock(x, z); + int y = world.findPrecipitationHeight(x, z); int blockId = world.getBlockId(x, y, z); int blockIdBelow = world.getBlockId(x, y - 1, z); 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 479a773cf..a08a98466 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 @@ -154,6 +154,14 @@ item.armor.leggings.steel.name=Steel Leggings item.armor.leggings.steel.desc=A pair of durable steel leggings. item.armor.boots.iceskates.name=Ice Skates item.armor.boots.iceskates.desc=A pair of ice skates. Go have some fun! +item.armor.helmet.diving.name=Diving Helmet +item.armor.helmet.diving.desc=The helmet of a diving suit. It allows the wearer to breathe underwater for 5 minutes. +item.armor.chestplate.diving.name=Diving Chestplate +item.armor.chestplate.diving.desc=The chestplate of a diving suit. It allows the wearer to mine at near-normal speeds underwater. +item.armor.leggings.diving.name=Diving Leggings +item.armor.leggings.diving.desc=The legs of a diving suit. They allow the wearer to move unimpeded underwater. +item.armor.boots.diving.name=Diving Boots +item.armor.boots.diving.desc=The boots of a diving suit. They allow the wearer to jump and sink rapidly underwater. item.flint.name=Flint item.flint.desc=Light chips of stone. Can be used to strike a fire. item.food.porkchop.raw.name=Raw Porkchop 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 b0ad03edd..78aeae5cf 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 @@ -501,6 +501,10 @@ tile.brimsand.desc=Scorched sulfuric sand rich in gunpowder. tile.bedrock.name=Bedrock tile.bedrock.desc=The toughest substance known to man. +tile.barrier.name=Barrier +tile.barrier.desc=Unbreakable, invisible block that prevents entities from passing through. +tile.barrier.intangible.name=Intangible Barrier +tile.barrier.intangible.desc=Unbreakable, invisible block that allows entities to pass through. tile.boneshale.name=Boneshale tile.boneshale.desc=An incredibly tough white rock torn from the deepest depths. tile.boneshale.cobbled.name=Fractured Boneshale diff --git a/game/server/src/main/java/net/minecraft/server/MinecraftServer.java b/game/server/src/main/java/net/minecraft/server/MinecraftServer.java index 1ef8e522f..b245fbe00 100644 --- a/game/server/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/game/server/src/main/java/net/minecraft/server/MinecraftServer.java @@ -88,7 +88,6 @@ import org.slf4j.Logger; import java.io.BufferedReader; import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; import java.net.InetAddress; import java.net.UnknownHostException; @@ -203,11 +202,8 @@ public class MinecraftServer File icon = new File("icon.png"); if (icon.exists()) { - try(InputStream stream = Files.newInputStream(new File("icon.png").toPath())) { - iconBytes = new byte[stream.available()]; - for (int i = 0; i < iconBytes.length; i++) { - iconBytes[i] = (byte) stream.read(); - } + try { + iconBytes = Files.readAllBytes(icon.toPath()); } catch (Exception e) { LOGGER.error("", e); } @@ -552,7 +548,7 @@ public class MinecraftServer { final @NotNull WorldConfiguration worldConfiguration = new WorldConfiguration(); for (final @NotNull WorldTypeGroups.Group group : WorldTypeGroups.GROUPS) { - if (group.get(dimension).equals(this.defaultWorldType)) { + if (group.get(Dimension.OVERWORLD).equals(this.defaultWorldType)) { worldConfiguration.setWorldTypeGroup(group); break; } diff --git a/gradle.properties b/gradle.properties index 1b34def90..9550e0258 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,6 +3,6 @@ org.gradle.daemon = true org.gradle.caching = true bta.group = net.minecraft -bta.version = 8.0.1 +bta.version = 8.1 bta.assetPackFormat = 4 bta.buildChannel = BuildChannel.DEVELOPMENT \ No newline at end of file