diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b6d6732a..0f2c33983 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ ## [8.0.2] ### Features +- Added Frame Timer Precision option. Higher values improve timing precision, but increase CPU usage. +- Entities can now turn either left or right during death animation ### Fixes - Properly masked axis bits when calculating axis in BlockLogicAxisAligned @@ -36,4 +38,37 @@ - Trommels - Dispensers - Fix unban command banning player instead -- Fix fence bounding box not being offset \ No newline at end of file +- Fix fence bounding box not being offset +- 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 +- Fixed ghast freezing the game when spawned too far from world origin +- Fixed Cherry on Top achievement being unobtainable +- Fixed default gamemode server property not working +- Fixed flung basket dropping items at the wrong position +- Fixed frame timer precision issues +- Fixed boulders setting fire immune entities on fire +- Fixed boulders burning items +- Fixed unban command banning player instead +- Fixed fence bounding box not being offset +- Fixed hitting blocks when selecting a painting +- Fixed dispenser not being able to fire flaming arrows +- Fixed game over screen not appearing when another screen is open +- Fixed pumpkin overlay rendering +- Fixed wolves flashing at the end of the shaking animation +- Fixed wolves holding items and blocks weird +- Fixed optional .geo.json fields being mandatory +- Fixed model bone limit being 4 times smaller than intended (models can now have up to 128 bones) +- Fixed models with more than 128 bones crashing the game +- Fixed zombie model having too many bones +- Fixed mob hurt effect glowing in the dark and generally being incorrect +- Fixed z-fighting on sitting pig model +- Fixed mobs fully or partially clipping into the ground during their death animation +- 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 diff --git a/game/client/src/main/java/net/minecraft/client/Minecraft.java b/game/client/src/main/java/net/minecraft/client/Minecraft.java index b90454d22..8b5ec6ebb 100644 --- a/game/client/src/main/java/net/minecraft/client/Minecraft.java +++ b/game/client/src/main/java/net/minecraft/client/Minecraft.java @@ -138,7 +138,6 @@ import net.minecraft.core.world.chunk.ChunkCoordinates; import net.minecraft.core.world.chunk.ChunkLoader; import net.minecraft.core.world.chunk.provider.ChunkProvider; import net.minecraft.core.world.pos.TilePos; -import net.minecraft.core.world.pos.TilePosc; import net.minecraft.core.world.save.DimensionData; import net.minecraft.core.world.save.ISaveConverter; import net.minecraft.core.world.save.ISaveFormat; @@ -151,14 +150,12 @@ import net.minecraft.core.world.settings.WorldConfiguration; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; -import org.joml.primitives.AABBd; -import org.joml.primitives.AABBdc; import org.lwjgl.LWJGLException; import org.lwjgl.glfw.GLFW; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL41; -import org.lwjgl.system.APIUtil; import org.lwjgl.system.Configuration; import org.slf4j.Logger; import org.useless.dragonfly.data.entity.mojang.EntityGeometryMojangData; @@ -271,6 +268,7 @@ public class Minecraft public TerrainRenderer terrainRenderer; private static final TimeKeeper STARTUP_TIKE_KEEPER = new TimeKeeper(); + private static final int MAX_STEPS_PER_FRAME = 10; /** * Keep this as the only constructor in this class for now, @@ -464,6 +462,7 @@ public class Minecraft new Registries(); GameSettings.init(this.mcDataDir); + this.timer.setTargetFps(GameSettings.CUSTOM_FPS_LIMIT.value); UUIDHelper.urlUUID = GameSettings.UUID_SERVER.value; @@ -804,7 +803,7 @@ public class Minecraft } if (screen == null && this.currentWorld == null) { screen = new ScreenMainMenu(); - } else if (screen == null && this.thePlayer.getHealth() <= 0) { + } else if (screen == null && this.thePlayer != null && this.thePlayer.getHealth() <= 0) { screen = new ScreenGameOver(); } if (screen instanceof ScreenMainMenu) { @@ -889,6 +888,11 @@ public class Minecraft Time.tick(); ObjectPool.resetAllPools(); + // Swapping before sleep seems to have better input latency, especially at lower frame rates + Debug.push("finishDisplay"); + this.gameWindow.update(); + Debug.pop(); + if (this.gameWindow.shouldClose()) shutdown(); if (this.isGamePaused && this.currentWorld != null && !(this.currentScreen instanceof ScreenModelViewer)) { float temp = this.timer.partialTicks; @@ -914,7 +918,7 @@ public class Minecraft this.currentScreen.tick(); } - for (int tick = 0; tick < this.timer.frames; tick++) { + for (int tick = 0; tick < this.timer.getGameSteps(MAX_STEPS_PER_FRAME); tick++) { this.ticksRan++; try { runTick(); @@ -952,9 +956,6 @@ public class Minecraft GameSettings.THIRD_PERSON_VIEW.value = 0; } - Debug.change("displayupdate"); // 2 - this.gameWindow.update(); - Debug.change("render"); // 2 Debug.push("post"); // 3 @@ -1027,6 +1028,20 @@ public class Minecraft Debug.change("post"); // 3 this.renderer.endRenderGame(this.timer.partialTicks); + GL11.glFlush(); + + Debug.push("sleep"); + final boolean isWorldNull = this.currentWorld == null; + final boolean vsync = GameSettings.ENABLE_VSYNC.value; + // Don't spin in main menu + final Timer.Precision precision = isWorldNull ? Timer.Precision.POWER_SAVING : GameSettings.TIMER_PRECISION.value; + + if (vsync) this.timer.setTargetFps(gameWindow.getFrequency()); + if (isWorldNull) this.timer.setTargetFps(60); + this.timer.sleep(precision); + if (isWorldNull || vsync) this.timer.setTargetFps(GameSettings.CUSTOM_FPS_LIMIT.value); + Debug.pop(); + Debug.pop(); // 3 @@ -1045,24 +1060,12 @@ public class Minecraft currentTime += 1000L; fpsCounter = 0; } - if (this.currentWorld == null) { - long now = System.currentTimeMillis(); - // Limit FPS in menu - long sleepTime = (1000 / 60 - (now - tickStartTime)) - 1; - if (sleepTime > 0) { - long currentSleep = 0; - while (currentSleep < sleepTime - 1) { - Thread.sleep(1L); - currentSleep += 1L; - if (this.currentWorld instanceof WorldClientMP worldClientMP) { - worldClientMP.processPackets(); - } + if (this.currentWorld instanceof WorldClientMP worldClientMP) { + worldClientMP.processPackets(); + } - if (this.currentScreen instanceof ScreenSelectServer) { - this.currentScreen.tick(); - } - } - } + if (this.currentScreen instanceof ScreenSelectServer) { + this.currentScreen.tick(); } Debug.pop(); // 2 @@ -1071,6 +1074,8 @@ public class Minecraft DebugRender.render(this.font); } + GL11.glFlush(); + screenshotListener(); } catch (MinecraftException minecraftexception) { this.currentWorld = null; @@ -1348,10 +1353,10 @@ public class Minecraft TextureRegistry.worldAtlas.bind(); this.textureManager.updateDynamicTextures(this.isGamePaused && this.currentScreen instanceof ScreenPause); Debug.change("misc"); - if (this.currentScreen == null && this.thePlayer != null) { + if (this.thePlayer != null) { if (this.thePlayer.getHealth() <= 0) { - displayScreen(null); - } else if (this.thePlayer.isPlayerSleeping() && this.currentWorld != null) { + displayScreen(new ScreenGameOver()); + } else if (this.currentScreen == null && this.thePlayer.isPlayerSleeping() && this.currentWorld != null) { if (this.currentWorld.isClientSide) { displayScreen(new ScreenSleepMP()); } else { @@ -1373,13 +1378,16 @@ public class Minecraft } } + // Bandaid fix for passEvents being lost if the Screen is removed during Screen::tick() + boolean passEvents = false; if (this.currentScreen != null) { this.currentScreen.updateEvents(); if (this.currentScreen != null) { + passEvents = this.currentScreen.passEvents; this.currentScreen.tick(); } } - if (this.currentScreen == null || this.currentScreen.passEvents) { + if (this.currentScreen == null || passEvents) { while (Mouse.next()) { long delta = System.currentTimeMillis() - this.systemTime; if (delta <= 200L) { @@ -1555,9 +1563,9 @@ public class Minecraft boolean placeBlockPressed = GameSettings.KEY_INTERACT.isPressed() || (this.controllerInput != null && this.controllerInput.buttonLeftTrigger.isPressed()); if (this.currentScreen == null) { - if (breakBlockPressed && (float) (this.ticksRan - this.mouseTicksRan) >= this.timer.ticksPerSecond / 5F && this.inGameHasFocus) + if (breakBlockPressed && (float) (this.ticksRan - this.mouseTicksRan) >= this.timer.getTps() / 5F && this.inGameHasFocus) clickMouse(0, GameSettings.AUTO_HIT.value, true); - if (placeBlockPressed && (float) (this.ticksRan - this.mouseTicksRan) >= this.timer.ticksPerSecond / 5F && this.inGameHasFocus) + if (placeBlockPressed && (float) (this.ticksRan - this.mouseTicksRan) >= this.timer.getTps() / 5F && this.inGameHasFocus) clickMouse(1, GameSettings.AUTO_HIT.value, true); } mineBlocks(this.currentScreen == null && breakBlockPressed && this.inGameHasFocus); diff --git a/game/client/src/main/java/net/minecraft/client/gui/ItemElement.java b/game/client/src/main/java/net/minecraft/client/gui/ItemElement.java index 297a8dab0..37eae4df8 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/ItemElement.java +++ b/game/client/src/main/java/net/minecraft/client/gui/ItemElement.java @@ -59,7 +59,7 @@ public class ItemElement extends Gui { if (itemStack != null) { final ItemModel itemModel = ItemModelDispatcher.getInstance().getDispatch(itemStack.getItem()); if (!discovered) GLRenderer.setColor1i(0xFF000000); - itemModel.renderGui(GLRenderer.getTessellator(), null, itemStack, x, y, LightIndexHelper.lightIndex2i(15, 15), 1f); + itemModel.renderGui(GLRenderer.getTessellator(), this.mc.thePlayer, itemStack, x, y, LightIndexHelper.lightIndex2i(15, 15), 1f); if (!discovered) GLRenderer.setColor1i(0xFFFFFFFF); if (slot instanceof SlotGuidebook slotGuidebook) { if (slotGuidebook.recipe instanceof RecipeEntryTrommel recipeEntryTrommel && slotGuidebook.item != null && slotGuidebook.isOutput) { 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 5820f286c..d71a3d56d 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 @@ -593,7 +593,9 @@ public class HudIngame extends Gui { } protected void renderPumpkinBlur(int xSize, int ySize) { + 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); @@ -605,9 +607,7 @@ public class HudIngame extends Gui { tessellator.addVertexWithUV(xSize, 0.0D, -90D, 1.0D, 0.0D); tessellator.addVertexWithUV(0.0D, 0.0D, -90D, 0.0D, 0.0D); tessellator.draw(); - GLRenderer.setDepthMask(true); - GLRenderer.enableState(State.DEPTH_TEST); - GLRenderer.setColor4f(1.0F, 1.0F, 1.0F, 1.0F); + GLRenderer.popFrame(); } protected void renderVignette(float intensity, int xSize, int ySize) { diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHotbar.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHotbar.java index 14d94a685..0e8716688 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHotbar.java +++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHotbar.java @@ -243,7 +243,7 @@ public class HudComponentHotbar extends HudComponentMovable { GLRenderer.modelM4f().scale(1.0F / f2, (f2 + 1.0F) / 2.0F, 1.0F); GLRenderer.modelM4f().translate(-(x + 8), -(y + 12), 0.0F); } - itemModel.renderGui(GLRenderer.getTessellator(), null, itemstack, x, y, LightIndexHelper.lightIndex2i(15, 15), partialTick); + itemModel.renderGui(GLRenderer.getTessellator(), mc.thePlayer, itemstack, x, y, LightIndexHelper.lightIndex2i(15, 15), partialTick); if (animProgress > 0.0F) { GLRenderer.popFrame(); } @@ -252,7 +252,7 @@ public class HudComponentHotbar extends HudComponentMovable { private void renderItem(Minecraft mc, ItemStack itemStack, int x, int y) { ItemModel itemModel = ItemModelDispatcher.getInstance().getDispatch(itemStack.getItem()); - itemModel.renderGui(GLRenderer.getTessellator(), null, itemStack, x, y, LightIndexHelper.lightIndex2i(15, 15), 1f); + itemModel.renderGui(GLRenderer.getTessellator(), mc.thePlayer, itemStack, x, y, LightIndexHelper.lightIndex2i(15, 15), 1f); itemModel.renderItemOverlayIntoGUI(GLRenderer.getTessellator(), mc.font, mc.textureManager, itemStack, x, y, null, 1.0f); } } \ No newline at end of file diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java b/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java index 90f30cf3f..8a6feedd0 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java +++ b/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java @@ -156,6 +156,7 @@ public abstract class OptionsPages { .withComponent(new FloatOptionComponent(GameSettings.GAMMA)) .withComponent(new BooleanOptionComponent(GameSettings.ENABLE_VSYNC)) .withComponent(new FramerateOptionComponent(GameSettings.CUSTOM_FPS_LIMIT)) + .withComponent(new ToggleableOptionComponent<>(GameSettings.TIMER_PRECISION)) .withComponent(new ToggleableOptionComponent<>(GameSettings.RENDER_SCALE)) .withComponent(new ToggleableOptionComponent<>(GameSettings.COLORBLINDNESS_FIX)) ) diff --git a/game/client/src/main/java/net/minecraft/client/option/GameSettings.java b/game/client/src/main/java/net/minecraft/client/option/GameSettings.java index 03761aeb1..66c89a3fd 100644 --- a/game/client/src/main/java/net/minecraft/client/option/GameSettings.java +++ b/game/client/src/main/java/net/minecraft/client/option/GameSettings.java @@ -16,6 +16,7 @@ import net.minecraft.client.option.enums.*; import net.minecraft.client.render.font.Fonts; import net.minecraft.client.render.tileentity.TileEntityRendererSign; import net.minecraft.client.world.chunk.provider.SelectedProvider; +import net.minecraft.core.Timer; import net.minecraft.core.entity.player.Player; import net.minecraft.core.enums.*; import net.minecraft.core.sound.SoundCategory; @@ -248,6 +249,7 @@ public final class GameSettings { public static final @NotNull OptionEnum chatVisibility = register(new OptionEnum<>("chatVisibility", ChatVisibility.class, ChatVisibility.SHOW_ALL)); public static final @NotNull OptionRange CUSTOM_FPS_LIMIT = register(new OptionRange("customFpsLimit", 165, 301) .withStep(5) + .addOnChangeCallback((mc, opt) -> mc.timer.setTargetFps(opt.value)) .withDisplayStringProvider((mc, i18n, option) -> { int value = option.value; int maxValue = 300; @@ -263,6 +265,7 @@ public final class GameSettings { } return option.toOptionsString(); })); + public static final @NotNull OptionEnum TIMER_PRECISION = register(new OptionEnum<>("timerPrecision", Timer.Precision.class, Timer.Precision.AUTO)); public static final @NotNull OptionGuiScale GUI_SCALE = register(new OptionGuiScale("guiScale", 0) .addOnChangeCallback((mc, option) -> { int max = ScaledResolution.getMaxScale(mc.gameWindow.getWidthScreenCoords(), mc.gameWindow.getHeightScreenCoords()); @@ -689,9 +692,11 @@ public final class GameSettings { loadOptions(); - if (!SEEN_HUD_EDITOR_ONBOARDING.value) { - HudComponents.INSTANCE.resetToDefault(); - } + // FIXME this was used to fix 7.3 > 8.0 migration, but this resets options exposed outside + // the hud editor. Files which may need to handle migration should track a version number + //if (!SEEN_HUD_EDITOR_ONBOARDING.value) { + // HudComponents.INSTANCE.resetToDefault(); + //} saveOptions(); } diff --git a/game/client/src/main/java/net/minecraft/client/render/LightingCache.java b/game/client/src/main/java/net/minecraft/client/render/LightingCache.java index 878879a66..c955c9feb 100644 --- a/game/client/src/main/java/net/minecraft/client/render/LightingCache.java +++ b/game/client/src/main/java/net/minecraft/client/render/LightingCache.java @@ -10,19 +10,22 @@ import net.minecraft.core.world.pos.TilePos; import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; +import java.lang.reflect.Array; +import java.util.Arrays; + final public class LightingCache { private final Minecraft mc = Minecraft.getMinecraft(); - private static final int CACHE_RANGE = 1; + private static final int CACHE_RANGE = 3; private static final int CACHE_SIZE = CACHE_RANGE * 2 + 1; - private int brightnessCached = 0; // new boolean[CACHE_SIZE * CACHE_SIZE * CACHE_SIZE]; + private final long[] brightnessCached = new long[MathHelper.ceil(CACHE_SIZE * CACHE_SIZE * CACHE_SIZE / (Long.BYTES * 8f))]; // new boolean[CACHE_SIZE * CACHE_SIZE * CACHE_SIZE]; private final float[] brightnessValue = new float[CACHE_SIZE * CACHE_SIZE * CACHE_SIZE]; - private int opacityCached = 0; // new boolean[CACHE_SIZE * CACHE_SIZE * CACHE_SIZE]; - private int opacityValue = 0; // new boolean[CACHE_SIZE * CACHE_SIZE * CACHE_SIZE]; + private final long[] opacityCached = new long[MathHelper.ceil(CACHE_SIZE * CACHE_SIZE * CACHE_SIZE / (Long.BYTES * 8f))]; // new boolean[CACHE_SIZE * CACHE_SIZE * CACHE_SIZE]; + private final long[] opacityValue = new long[MathHelper.ceil(CACHE_SIZE * CACHE_SIZE * CACHE_SIZE / (Long.BYTES * 8f))]; // new boolean[CACHE_SIZE * CACHE_SIZE * CACHE_SIZE]; - private int lightIndexCached = 0; // new boolean[CACHE_SIZE * CACHE_SIZE * CACHE_SIZE]; + private final long[] lightIndexCached = new long[MathHelper.ceil(CACHE_SIZE * CACHE_SIZE * CACHE_SIZE / (Long.BYTES * 8f))]; // new boolean[CACHE_SIZE * CACHE_SIZE * CACHE_SIZE]; private final byte[] lightIndexValue = new byte[CACHE_SIZE * CACHE_SIZE * CACHE_SIZE]; private final @NotNull TilePos offset = new TilePos(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE); @@ -40,9 +43,9 @@ final public class LightingCache { if (!tilePos.equals(this.offset) || this.block != block || this.access != source) { this.block = block; this.access = source; - this.brightnessCached = 0; - this.opacityCached = 0; - this.lightIndexCached = 0; + Arrays.fill(this.brightnessCached, 0); + Arrays.fill(this.opacityCached, 0); + Arrays.fill(this.lightIndexCached, 0); this.offset.set(tilePos); } } @@ -63,7 +66,7 @@ final public class LightingCache { if (!bitGet(this.brightnessCached, index)) { this.brightnessValue[index] = calcBrightness(this.offset.add(relX, relY, relZ, this.queryPos)); - this.brightnessCached = bitSet(this.brightnessCached, index); + bitSet(this.brightnessCached, index); } return this.brightnessValue[index]; @@ -76,8 +79,8 @@ final public class LightingCache { int index = (relX + CACHE_RANGE) * CACHE_SIZE * CACHE_SIZE + (relY + CACHE_RANGE) * CACHE_SIZE + (relZ + CACHE_RANGE); if (!bitGet(this.opacityCached, index)) { - this.opacityValue = bitSetState(this.opacityValue, index, this.access.getBlockType(this.offset.add(relX, relY, relZ, this.queryPos)).solid()); - this.opacityCached = bitSet(this.opacityCached, index); + bitSetState(this.opacityValue, index, this.access.getBlockType(this.offset.add(relX, relY, relZ, this.queryPos)).solid()); + bitSet(this.opacityCached, index); } return bitGet(this.opacityValue, index); } @@ -91,24 +94,27 @@ final public class LightingCache { if (!bitGet(this.lightIndexCached, index)) { int lightEmission = this.block.emission; this.lightIndexValue[index] = this.access.getLightIndex(this.offset.add(relX, relY, relZ, this.queryPos), lightEmission); - this.lightIndexCached = bitSet(this.lightIndexCached, index); + bitSet(this.lightIndexCached, index); } return this.lightIndexValue[index]; } - private static boolean bitGet(int value, int index) { - return (value & (1 << index)) != 0; + private static boolean bitGet(long[] bitset, int index) { + final int longIndex = index / (Long.BYTES * 8); + return (bitset[longIndex] & (1L << (index & 0x3f))) != 0; } - private static int bitSet(int value, int index) { - return (value | (1 << index)); + private static void bitSet(long[] bitset, int index) { + final int longIndex = index / (Long.BYTES * 8); + bitset[longIndex] |= (1L << (index & 0x3f)); } - private static int bitSetState(int value, int index, boolean state) { + private static void bitSetState(long[] bitset, int index, boolean state) { + final int longIndex = index / (Long.BYTES * 8); if (state) { - return (value | (1 << index)); + bitset[longIndex] |= (1L << (index & 0x3f)); } else { - return (value & ~(1 << index)); + bitset[longIndex] &= ~(1L << (index & 0x3f)); } } } \ No newline at end of file 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 d7db4cc43..183d9d988 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 @@ -866,63 +866,70 @@ public final class RenderGlobal return GameSettings.CLOUD_HEIGHT.value * 128; } - public void renderClouds(float partialTick) { - WorldTypeFX worldTypeFX = WorldTypeFXDispatcher.getInstance().getDispatch(this.mc.currentWorld.getWorldType()); - if (!worldTypeFX.hasClouds()) { - return; - } - if (this.mc.currentScreen instanceof ScreenPhotoMode) { + /** Controls the size of clouds. Used in Fast cloud rendering. **/ + private static final double CLOUD_UV_DIVISOR = 2048.0; + /** The size of a cloud segment (a single quad) in blocks. Raising this value too high will cause + * severe flashing/stuttering artifacts when viewed at certain angles. + * Used in Fast cloud rendering. **/ + private static final int CLOUD_SEGMENT_SIZE = 64; + private static final double CLOUD_OFFSET_MAGIC = 0.03; // It's magic :-) + + public void renderClouds(final float partialTick) { + final WorldTypeFX worldTypeFX = WorldTypeFXDispatcher.getInstance().getDispatch(this.mc.currentWorld.getWorldType()); + if (!worldTypeFX.hasClouds() || this.mc.currentScreen instanceof ScreenPhotoMode) { return; } + if (GameSettings.CLOUD_QUALITY.value == CloudQuality.FANCY) { renderCloudsFancy(partialTick); return; } + GLRenderer.pushFrame(); GLRenderer.setShader(Shaders.CLOUDS); - GLRenderer.setLightmapCoord2i(15, 15); + + GLRenderer.setBlendFunc(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA); + GLRenderer.enableState(State.BLEND); GLRenderer.disableState(State.CULL_FACE); - float cameraY = (float) this.mc.activeCamera.getY(partialTick); - byte cloudRadius = 32; - int i = 256 / cloudRadius; - TessellatorGeneral tessellator = GLRenderer.getTessellator(); + GLRenderer.setLightmapCoord2i(15, 15); + this.textureManager.loadTexture("/assets/minecraft/textures/environment/clouds.png").bind(); - GLRenderer.enableState(State.BLEND); - GLRenderer.setBlendFunc(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA); - Vector3fc dimensionColor = this.world.getDimensionColor(this.mc.activeCamera, partialTick); - float r = dimensionColor.x(); - float g = dimensionColor.y(); - float b = dimensionColor.z(); - float f6 = 1f / 2048f; - double posX = this.mc.activeCamera.getX(partialTick) + (double) (org.joml.Math.lerp(this.lastCloudOffsetX, this.cloudOffsetX, partialTick) * 0.03F); - double posZ = this.mc.activeCamera.getZ(partialTick) + (double) (org.joml.Math.lerp(this.lastCloudOffsetZ, this.cloudOffsetZ, partialTick) * 0.03F); - int j = MathHelper.floor(posX / 2048D); - int k = MathHelper.floor(posZ / 2048D); - posX -= j * 2048; - posZ -= k * 2048; - float cloudHeight = (worldTypeFX.getCloudHeight(world) - cameraY) + 0.33F + getCloudHeightModifier(); - float f10 = (float) (posX * (double) f6); - float f11 = (float) (posZ * (double) f6); - tessellator.startDrawingQuads(); - tessellator.setColor4f(r, g, b, 0.8F); - int dist = (int) (cloudRadius * i * 2 * GameSettings.CLOUD_RENDER_DISTANCE.value); - int cloudZ = -cloudRadius * i; - int cloudX = -cloudRadius * i; - tessellator.addVertexWithUV( - cloudX, cloudHeight, cloudZ + cloudRadius * dist, - cloudX * f6 + f10, (cloudZ + cloudRadius * dist) * f6 + f11); - tessellator.addVertexWithUV( - cloudX + cloudRadius * dist, cloudHeight, cloudZ + cloudRadius * dist, - (cloudX + cloudRadius * dist) * f6 + f10, (cloudZ + cloudRadius * dist) * f6 + f11); - tessellator.addVertexWithUV( - cloudX + cloudRadius * dist, cloudHeight, cloudZ, - (cloudX + cloudRadius * dist) * f6 + f10, cloudZ * f6 + f11); - tessellator.addVertexWithUV( - cloudX, cloudHeight, cloudZ, - (cloudX) * f6 + f10, cloudZ * f6 + f11); - tessellator.draw(); - GLRenderer.disableState(State.BLEND); - GLRenderer.enableState(State.CULL_FACE); + final double cloudLx = org.joml.Math.lerp(this.lastCloudOffsetX, this.cloudOffsetX, partialTick); + final double cloudLz = org.joml.Math.lerp(this.lastCloudOffsetZ, this.cloudOffsetZ, partialTick); + final double posX = Math.fma(cloudLx, CLOUD_OFFSET_MAGIC, this.mc.activeCamera.getX(partialTick)) % CLOUD_UV_DIVISOR; + final double posZ = Math.fma(cloudLz, CLOUD_OFFSET_MAGIC, this.mc.activeCamera.getZ(partialTick)) % CLOUD_UV_DIVISOR; + final double cameraY = this.mc.activeCamera.getY(partialTick); + final double cloudHeight = (worldTypeFX.getCloudHeight(world) - cameraY) + 0.33 + getCloudHeightModifier(); + + final double viewRadiusBlocks = 16 * 16 * GameSettings.CLOUD_RENDER_DISTANCE.value; + final double viewDistanceBlocks = viewRadiusBlocks * 2; + final int segments = MathHelper.ceil(viewDistanceBlocks / CLOUD_SEGMENT_SIZE) * CLOUD_SEGMENT_SIZE; + + final Vector3fc dimensionColor = this.world.getDimensionColor(this.mc.activeCamera, partialTick); + final float r = dimensionColor.x(); + final float g = dimensionColor.y(); + final float b = dimensionColor.z(); + final TessellatorGeneral tess = GLRenderer.getTessellator(); + tess.startDrawingQuads(); + tess.setColor4f(r, g, b, 0.8F); + + // BigSir: I think clouds appear somewhat smaller than before, although the difference seems negligible + for (int cx = 0; cx < segments; cx += CLOUD_SEGMENT_SIZE) for (int cz = 0; cz < segments; cz += CLOUD_SEGMENT_SIZE) { + final double x = -viewRadiusBlocks + cx; + final double z = -viewRadiusBlocks + cz; + + final double minU = (x + posX) / CLOUD_UV_DIVISOR; + final double minV = (z + posZ) / CLOUD_UV_DIVISOR; + final double maxU = (x + posX + CLOUD_SEGMENT_SIZE) / CLOUD_UV_DIVISOR; + final double maxV = (z + posZ + CLOUD_SEGMENT_SIZE) / CLOUD_UV_DIVISOR; + + tess.addVertexWithUV(x , cloudHeight, z , minU, minV); + tess.addVertexWithUV(x + CLOUD_SEGMENT_SIZE, cloudHeight, z , maxU, minV); + tess.addVertexWithUV(x + CLOUD_SEGMENT_SIZE, cloudHeight, z + CLOUD_SEGMENT_SIZE, maxU, maxV); + tess.addVertexWithUV(x , cloudHeight, z + CLOUD_SEGMENT_SIZE, minU, maxV); + } + + tess.draw(); GLRenderer.popFrame(); } 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 08b4c481e..0af265e37 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 @@ -529,22 +529,6 @@ public class WorldRenderer { } else { renderWorld(partialTick, this.systemTime + (nsPerSecond / c)); } - Debug.change("misc"); - if (GameSettings.ENABLE_VSYNC.value || GameSettings.CUSTOM_FPS_LIMIT.value > 0) // Power saver - { - Debug.change("sleep"); - long timeToSleep = ((this.systemTime + (nsPerSecond / c)) - System.nanoTime()); - long millis = timeToSleep / 1_000_000L; - int nanos = (int) (timeToSleep - (millis * 1_000_000L)); - if (millis > 0L && millis < 500L) { - try { - Thread.sleep(millis, nanos); - } catch (InterruptedException e) { - LOGGER.error("", e); - } - } - Debug.change("misc"); - } this.systemTime = System.nanoTime(); Debug.change("hud"); @@ -555,21 +539,6 @@ public class WorldRenderer { GLRenderer.viewM4f().identity(); GLRenderer.modelM4f().identity(); setupScaledResolution(); - if (GameSettings.ENABLE_VSYNC.value || GameSettings.CUSTOM_FPS_LIMIT.value > 0) { - Debug.change("sleep"); - long l2 = ((this.systemTime + (1_000_000_000L / c)) - System.nanoTime()) / 1_000_000L; - if (l2 < 0L) { - l2 += 10L; - } - if (l2 > 0L && l2 < 500L) { - try { - Thread.sleep(l2); - } catch (InterruptedException e) { - LOGGER.error("", e); - } - } - Debug.change("misc"); - } this.systemTime = System.nanoTime(); } diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererArrow.java b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererArrow.java index 24a8d2b50..a36a6eaf7 100644 --- a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererArrow.java +++ b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererArrow.java @@ -1,7 +1,10 @@ package net.minecraft.client.render.entity; +import net.minecraft.client.render.renderer.BlendFactor; import net.minecraft.client.render.renderer.GLRenderer; +import net.minecraft.client.render.renderer.State; import net.minecraft.client.render.tessellator.TessellatorGeneral; +import net.minecraft.core.entity.EntityItem; import net.minecraft.core.entity.projectile.ProjectileArrow; import net.minecraft.core.util.helper.MathHelper; import org.jetbrains.annotations.NotNull; @@ -11,17 +14,21 @@ public class EntityRendererArrow extends EntityRenderer { @Override public void render(@NotNull TessellatorGeneral tessellator, @NotNull ProjectileArrow arrow, double x, double y, double z, float yaw, float partialTick) { - int prime = ((ProjectileArrow.LIFETIME * 3)/4); - if ((arrow.ticksInGround + partialTick) > prime) { - int pastPrime = arrow.ticksInGround - prime; - double toDeath = 1 - ((pastPrime + partialTick) * 4d)/ProjectileArrow.LIFETIME; // progress of age from 75% of lifetime to 100% - if (java.lang.Math.cos(((pastPrime + partialTick) * java.lang.Math.PI)/ (2.5 + 5.5 * toDeath)) > 0) return; - } bindTexture("/assets/minecraft/textures/entity/arrows.png"); float imgWidth = 16f; float imgHeight = 64f; + final float fadeAlpha = EntityItem.getDespawnFadeAlpha(arrow.ticksInGround, ProjectileArrow.LIFETIME, partialTick); + if (arrow.ticksInGround >= ProjectileArrow.LIFETIME && fadeAlpha <= EntityItem.DESPAWN_ALPHA_THRESHOLD) { + return; + } GLRenderer.pushFrame(); + if (fadeAlpha < 1.0f) { + GLRenderer.enableState(State.BLEND); + GLRenderer.setBlendFunc(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA); + GLRenderer.setColor4f(1.0f, 1.0f, 1.0f, fadeAlpha); + } + GLRenderer.modelM4f().translate((float) x, (float) y, (float) z); GLRenderer.modelM4f().rotateY(Math.toRadians(Math.lerp(arrow.yRotO, arrow.yRot, partialTick) - 90F)); diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRenderer.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRenderer.java index 57bdb44a4..d8ebff53c 100644 --- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRenderer.java +++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRenderer.java @@ -55,6 +55,11 @@ public abstract class MobRenderer extends EntityRenderer { for (int layer = 0; layer <= maxRenderLayer; layer++) { try { GLRenderer.pushFrame(); + final int hurtColor = entity.hurtTime > 0 || entity.deathTime > 0 ? this.getHurtColor(entity, partialTick, layer) : 0; + final int legacyOverlayColor = this.getOverlayColor(entity, partialTick); // Remove this in 8.1 :] + final int overlayColor = this.getOverlayColor(entity, partialTick, layer); + GLRenderer.setOverlayColor1i(Color.blendARGB(hurtColor, legacyOverlayColor != 0 ? legacyOverlayColor : overlayColor)); + final StaticEntityModel model = getAndSetupModelForLayer(entity, 1f, partialTick, layer); this.setupModels.add(model); if (model != null) { @@ -74,40 +79,6 @@ public abstract class MobRenderer extends EntityRenderer { } renderAdditional(tessellator, entity, partialTick); - final int argb = getOverlayColor(entity, partialTick); - final boolean hasOverlayAlpha = Color.alphaFromInt(argb) > 0; - if (hasOverlayAlpha || entity.hurtTime > 0 || entity.deathTime > 0) { - this.renderDispatcher.textureManager.loadTexture("/assets/minecraft/textures/misc/white.png").bind(); - GLRenderer.pushFrame(); - GLRenderer.setLightmapCoord2i(15, 15); - GLRenderer.setShader(Shaders.COLOR_WORLD); - GLRenderer.enableState(State.BLEND); - GLRenderer.setBlendFunc(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA); - GLRenderer.setDepthFunc(CompareFunc.EQUAL); - if (entity.hurtTime > 0 || entity.deathTime > 0) { - for (int layer = 0; layer <= maxRenderLayer; layer++) { - final StaticEntityModel model = this.setupModels.get(layer); - if (model != null) { - GLRenderer.setColor4f(1f, 0.0F, 0.0F, 0.4F); - model.render(); - } - } - - } - if (hasOverlayAlpha) { - for (int layer = 0; layer <= maxRenderLayer; layer++) { - final StaticEntityModel model = this.setupModels.get(layer); - if (model != null) { - GLRenderer.setColor1i(argb); - model.render(); - } - } - } - GLRenderer.setDepthFunc(CompareFunc.LESS_EQUAL); - GLRenderer.disableState(State.BLEND); - GLRenderer.popFrame(); - } - GLRenderer.popFrame(); GLRenderer.enableState(State.CULL_FACE); @@ -121,12 +92,14 @@ public abstract class MobRenderer extends EntityRenderer { GLRenderer.modelM4f().scale(1 / ENTITY_RENDER_SCALE, 1 / ENTITY_RENDER_SCALE, -1 / ENTITY_RENDER_SCALE); if (entity.deathTime > 0) { - float rotationProgress = (((entity.deathTime + partialTick) - 1.0F) / 20F) * 1.6F; - rotationProgress = MathHelper.sqrt_float(rotationProgress); - if (rotationProgress > 1.0F) { - rotationProgress = 1.0F; - } - GLRenderer.modelM4f().rotateZ(Math.toRadians(rotationProgress * getMaxDeathRotation(entity))); + final float rotationProgress = Math.min(Math.sqrt((entity.deathTime + partialTick - 1.0F) / 20F * 1.6F), 1.0F); + final float rotationYOffset = this.getDeathRotationYOffset(entity) * ENTITY_RENDER_SCALE; + final int rotationDir = this.getDeathRotationDir(entity); + + GLRenderer.modelM4f() + .translate(0, rotationYOffset, 0) + .rotateZ(Math.toRadians(rotationDir * rotationProgress * getMaxDeathRotation(entity))) + .translate(0, -rotationYOffset, 0); } if (entity instanceof AgedMob agedMob) { @@ -188,14 +161,35 @@ public abstract class MobRenderer extends EntityRenderer { } } + /** + * @deprecated Use {@link MobRenderer#getOverlayColor(Mob, float, int)} + */ + @Deprecated protected int getOverlayColor(final @NotNull T entity, final float partialTick) { + return 0; // Remove this in 8.1 :] + } + + protected int getOverlayColor(final @NotNull T entity, final float partialTick, final int layer) { return 0; } + protected int getHurtColor(final @NotNull T entity, final float partialTick, final int layer) { + return 0x66FF0000; + } + protected float getMaxDeathRotation(final @NotNull T entity) { return 90F; } + protected int getDeathRotationDir(final @NotNull T entity) { + return (entity.id & 1) == 0 ? 1 : -1; + } + + protected float getDeathRotationYOffset(final @NotNull T entity) { + // BigSir: this should probably be controlled by a model property (?) or something in the future + return entity.bbWidth * 0.5F; + } + protected int maxRenderLayer(final @NotNull T entity) { return 0; } diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererCreeper.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererCreeper.java index d13a5aa59..6bded5038 100644 --- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererCreeper.java +++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererCreeper.java @@ -18,7 +18,7 @@ public class MobRendererCreeper extends MobRenderer { } @Override - protected int getOverlayColor(final @NotNull MobCreeper creeper, final float partialTick) { + protected int getOverlayColor(final @NotNull MobCreeper creeper, final float partialTick, final int layer) { final float step = creeper.getSwelling(partialTick); if ((int) (step * 10.0f) % 2 == 0) { return 0; diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererHuman.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererHuman.java index d91656156..6333decf6 100644 --- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererHuman.java +++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererHuman.java @@ -25,12 +25,14 @@ public class MobRendererHuman extends MobRendererBiped { GLRenderer.modelM4f().scale(scale, scale, scale); if (entity.deathTime > 0) { - float rotationProgress = (((entity.deathTime + partialTick) - 1.0F) / 20F) * 1.6F; - rotationProgress = MathHelper.sqrt_float(rotationProgress); - if (rotationProgress > 1.0F) { - rotationProgress = 1.0F; - } - GLRenderer.modelM4f().rotateZ(Math.toRadians(rotationProgress * getMaxDeathRotation(entity))); + final float rotationProgress = org.joml.Math.min(org.joml.Math.sqrt((entity.deathTime + partialTick - 1.0F) / 20F * 1.6F), 1.0F); + final float rotationYOffset = this.getDeathRotationYOffset(entity) * ENTITY_RENDER_SCALE; + final int rotationDir = this.getDeathRotationDir(entity); + + GLRenderer.modelM4f() + .translate(0, rotationYOffset, 0) + .rotateZ(Math.toRadians(rotationDir * rotationProgress * getMaxDeathRotation(entity))) + .translate(0, -rotationYOffset, 0); } } diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPig.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPig.java index 512c0b7c6..f39089d1f 100644 --- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPig.java +++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPig.java @@ -115,6 +115,8 @@ public class MobRendererPig extends MobRendererQuadruped { final BoneTransform body = model.getTransform("body"); final BoneTransform leg0 = model.getTransform("leg0"); final BoneTransform leg1 = model.getTransform("leg1"); + final BoneTransform leg2 = model.getTransform("leg2"); + final BoneTransform leg3 = model.getTransform("leg3"); body.rotX = -27.5 * MathHelper.DEG_TO_RAD; body.posY = -4; @@ -130,6 +132,10 @@ public class MobRendererPig extends MobRendererQuadruped { leg1.posX = 1; leg1.posY = -4; + leg2.posX = 0.125; + + leg3.posX = -0.125; + head.posZ = 1; head.rotX += headPitch; head.rotY += headYaw; 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 6ed6552e2..11157b82d 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 @@ -193,12 +193,14 @@ public class MobRendererPlayer extends MobRendererBipedArmored { } if (entity.deathTime > 0) { - float rotationProgress = (((entity.deathTime + partialTick) - 1.0F) / 20F) * 1.6F; - rotationProgress = MathHelper.sqrt_float(rotationProgress); - if (rotationProgress > 1.0F) { - rotationProgress = 1.0F; - } - GLRenderer.modelM4f().rotateZ(org.joml.Math.toRadians(rotationProgress * getMaxDeathRotation(entity))); + final float rotationProgress = org.joml.Math.min(org.joml.Math.sqrt((entity.deathTime + partialTick - 1.0F) / 20F * 1.6F), 1.0F); + final float rotationYOffset = this.getDeathRotationYOffset(entity) * ENTITY_RENDER_SCALE; + final int rotationDir = this.getDeathRotationDir(entity); + + GLRenderer.modelM4f() + .translate(0, rotationYOffset, 0) + .rotateZ(org.joml.Math.toRadians(rotationDir * rotationProgress * getMaxDeathRotation(entity))) + .translate(0, -rotationYOffset, 0); } @@ -271,7 +273,7 @@ public class MobRendererPlayer extends MobRendererBipedArmored { GLRenderer.modelM4f().translate(0, (MathHelper.cos(walkProgress / 2 * 2 / 3f + MathHelper.PI) / 12f * walkSpeed + 0.1f - swing / 4f) * ENTITY_RENDER_SCALE, 0); GLRenderer.modelM4f().translate(0, 1.25f * ENTITY_RENDER_SCALE, 0); if (player.isSneaking()) { - GLRenderer.modelM4f().translate(0, 0, 4); + GLRenderer.modelM4f().translate(0, -4.5f, 3.0F); } GLRenderer.modelM4f().scale(-ENTITY_RENDER_SCALE, -ENTITY_RENDER_SCALE, ENTITY_RENDER_SCALE); drawHeldObject(player, partialTick); diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererSpider.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererSpider.java index 64310d8da..565771865 100644 --- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererSpider.java +++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererSpider.java @@ -99,6 +99,11 @@ public class MobRendererSpider extends MobRenderer { return 180; } + @Override + protected float getDeathRotationYOffset(@NotNull MobSpider entity) { + return 0.4F; + } + @Override protected int maxRenderLayer(@NotNull final MobSpider entity) { return 1; 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 8c481379f..fe8fde2ef 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 @@ -1,10 +1,10 @@ package net.minecraft.client.render.entity; -import net.minecraft.client.option.GameSettings; import net.minecraft.client.render.item.model.ItemModelDispatcher; import net.minecraft.client.render.renderer.GLRenderer; import net.minecraft.client.render.renderer.State; import net.minecraft.client.render.tessellator.TessellatorGeneral; +import net.minecraft.core.block.Blocks; import net.minecraft.core.entity.animal.MobWolf; import net.minecraft.core.item.IArmorItem; import net.minecraft.core.item.ItemStack; @@ -93,7 +93,7 @@ public class MobRendererWolf extends MobRenderer { tail.rotZ = entity.getShakeAngle(partialTick, -0.2F); if (entity.getWolfShaking()) { - final float shading = brightness * entity.getShadingWhileShaking(partialTick); + final float shading = Math.min(brightness * entity.getShadingWhileShaking(partialTick), 1.0F); GLRenderer.setColor3f(shading, shading, shading); } @@ -126,10 +126,11 @@ public class MobRendererWolf extends MobRenderer { if (itemstack != null) { GLRenderer.pushFrame(); - getModel("main").translateToBone("mouthItem"); + 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); GLRenderer.enableState(State.BLEND); - ItemModelDispatcher.getInstance().getDispatch(itemstack).render(GLRenderer.getTessellator(), entity, itemstack, DisplayPos.GROUND, GameSettings.ITEMS_3D.value, 1, entity.getLightIndex(partialTick), partialTick, true); + ItemModelDispatcher.getInstance().getDispatch(itemstack).render(GLRenderer.getTessellator(), entity, itemstack, DisplayPos.GROUND, true, 1, entity.getLightIndex(partialTick), partialTick, true); GLRenderer.disableState(State.BLEND); GLRenderer.popFrame(); } diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelBow.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelBow.java index 53a97b5ce..d8bf6e2f2 100644 --- a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelBow.java +++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelBow.java @@ -20,7 +20,6 @@ public class ItemModelBow extends ItemModelStandard { @Override protected void renderSingle(@NotNull TessellatorGeneral tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, boolean items3d, byte lightIndex, int color, float partialTick, boolean mirrorX) { - super.renderSingle(tessellator, holder, itemStack, items3d, lightIndex, color, partialTick, mirrorX); Item nextArrow = null; if (holder instanceof Player player) { nextArrow = getNextArrow(player); @@ -39,6 +38,8 @@ public class ItemModelBow extends ItemModelStandard { renderCoordinate(tessellator, ItemModelDispatcher.getInstance().getDispatch(nextArrow).getIcon(holder, nextArrow.getDefaultStack()), lightIndex, color, items3d, !mirrorX); GLRenderer.popFrame(); } + // Rendered late to fix arrow rendering above bow in the inventory + super.renderSingle(tessellator, holder, itemStack, items3d, lightIndex, color, partialTick, mirrorX); } public Item getNextArrow(Player player) { diff --git a/game/client/src/main/java/net/minecraft/client/render/renderer/GLRenderer.java b/game/client/src/main/java/net/minecraft/client/render/renderer/GLRenderer.java index ca38a8a69..102c932b9 100644 --- a/game/client/src/main/java/net/minecraft/client/render/renderer/GLRenderer.java +++ b/game/client/src/main/java/net/minecraft/client/render/renderer/GLRenderer.java @@ -85,6 +85,9 @@ public class GLRenderer { private final int[] colorStack = new int[RENDER_FRAMES_STACK_SIZE]; private int currentColor = Color.intToIntARGB(255, 255, 255, 255); + private final int[] overlayColorStack = new int[RENDER_FRAMES_STACK_SIZE]; + private int currentOverlayColor = 0; + private final Shader[] shaderStack = new Shader[RENDER_FRAMES_STACK_SIZE]; private @NotNull Shader currentShader = Shaders.INTERFACE; @@ -164,6 +167,7 @@ public class GLRenderer { shader.uniformFloat("uLightMapStrength", instance.currentLightMapStrength); shader.uniformFloat("uAlphaTest", instance.currentAlphaTest); shader.uniformVec4f("uColor", Color.redFromInt(instance.currentColor)/255f, Color.greenFromInt(instance.currentColor)/255f, Color.blueFromInt(instance.currentColor)/255f, Color.alphaFromInt(instance.currentColor)/255f); + shader.uniformVec4f("uOverlayColor", Color.redFromInt(instance.currentOverlayColor)/255f, Color.greenFromInt(instance.currentOverlayColor)/255f, Color.blueFromInt(instance.currentOverlayColor)/255f, Color.alphaFromInt(instance.currentOverlayColor)/255f); shader.uniformFloat("uCelestialAngle", (instance.mc.currentWorld != null ? instance.mc.currentWorld.getCelestialAngle(instance.mc.timer.partialTicks) : 0f)); shader.uniformFloat("uCurrentTick", instance.mc.ticksRan + instance.mc.timer.partialTicks); shader.uniformFloat("uPartialTick", instance.mc.timer.partialTicks); @@ -369,6 +373,37 @@ public class GLRenderer { return instance.currentLightMapStrength; } + // BigSir: The overlay color functions don't have Color3* versions as its primary use + // is to be mixed with the texture color before lighting is applied, so having a function set the alpha to + // 1 does not make much sense imo + public static void setOverlayColor1i(final int argb) { + instance.currentOverlayColor = argb; + } + + public static void setOverlayColor4f(final float r, final float g, final float b, final float a) { + setOverlayColor1i(Color.floatToIntARGB(a, r, g, b)); + } + + public static void setOverlayColor4d(final double r, final double g, final double b, final double a) { + setOverlayColor1i(Color.doubleToIntARGB(a, r, g, b)); + } + + public static void setOverlayColor4i(final int r, final int g, final int b, final int a) { + setOverlayColor1i(Color.intToIntARGB(a, r, g, b)); + } + + public static void setOverlayColor(@NotNull final Color color) { + setOverlayColor1i(color.value); + } + + public static void setOverlayColor4fv(@NotNull final Vector4fc colorVec) { + setOverlayColor4f(colorVec.x(), colorVec.y(), colorVec.z(), colorVec.w()); + } + + public static void setOverlayColor4dv(@NotNull final Vector4dc colorVec) { + setOverlayColor4d(colorVec.x(), colorVec.y(), colorVec.z(), colorVec.w()); + } + public static void setColor1i(int argb) { instance.currentColor = argb; } @@ -427,6 +462,7 @@ public class GLRenderer { public static void pushFrame() { instance.stateConfigStack[instance.stackIndex] = instance.currentStateConfig; instance.colorStack[instance.stackIndex] = instance.currentColor; + instance.overlayColorStack[instance.stackIndex] = instance.currentOverlayColor; instance.shaderStack[instance.stackIndex] = instance.currentShader; instance.currentFogState.copy(instance.fogStateStack[instance.stackIndex]); instance.depthFuncStack[instance.stackIndex] = instance.currentDepthFunc; @@ -494,6 +530,7 @@ public class GLRenderer { instance.currentStateConfig = newConfig; instance.currentColor = instance.colorStack[instance.stackIndex]; + instance.currentOverlayColor = instance.overlayColorStack[instance.stackIndex]; instance.currentShader = instance.shaderStack[instance.stackIndex]; if (!instance.currentFogState.equals(instance.fogStateStack[instance.stackIndex])) { diff --git a/game/client/src/main/java/net/minecraft/client/render/uniform/UniformBlockManager.java b/game/client/src/main/java/net/minecraft/client/render/uniform/UniformBlockManager.java index 72eb0f5e3..41d78b7c2 100644 --- a/game/client/src/main/java/net/minecraft/client/render/uniform/UniformBlockManager.java +++ b/game/client/src/main/java/net/minecraft/client/render/uniform/UniformBlockManager.java @@ -30,7 +30,7 @@ public class UniformBlockManager { return dest; } }); - public static final @NotNull UniformBlock BLOCK_ENTITY_BONES = register("Bones", 3, N * 4 * StaticEntityModelMojang.MAX_BONES, Matrix4f::get); + public static final @NotNull UniformBlock BLOCK_ENTITY_BONES = register("Bones", 3, N * 16 * StaticEntityModelMojang.MAX_BONES, Matrix4f::get); public static UniformBlock register(@NotNull String name, int index, int size, @NotNull BufferAdapter adapter) { UniformBlock block = new UniformBlock<>(name, index, size, adapter); diff --git a/game/client/src/main/java/net/minecraft/client/util/debug/DebugRender.java b/game/client/src/main/java/net/minecraft/client/util/debug/DebugRender.java index 63634b71b..0c577d933 100644 --- a/game/client/src/main/java/net/minecraft/client/util/debug/DebugRender.java +++ b/game/client/src/main/java/net/minecraft/client/util/debug/DebugRender.java @@ -123,6 +123,8 @@ public class DebugRender { int fps = Debug.getFps(); if (fps >= 0) { sr.render("fps: " + fps, x1, y1 - 2 * lineHeight).call(); + sr.render("min: " + (int) Minecraft.getMinecraft().timer.getFpsMin(), x1, y1 - 4 * lineHeight).call(); + sr.render("max: " + (int) Minecraft.getMinecraft().timer.getFpsMax(), x1, y1 - 3 * lineHeight).call(); } sr.render("avg: " + (getAvgTime(frametimes) / 1000.0) + " ms", x1, y1 - lineHeight).call(); sr.render(selectedProfiler.name + ": ", x1, y1).call(); 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 e48dcc3c2..5dfde475f 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,6 +133,8 @@ public class CompiledBlockModelMojangData { } public static class C_Element { + public static final float UV_INSET = 1/32.0F; + public static final int VERTEX_TOP_LEFT = 0; public static final int VERTEX_TOP_RIGHT = 3; public static final int VERTEX_BOTTOM_RIGHT = 2; @@ -238,10 +240,10 @@ public class CompiledBlockModelMojangData { Direction d = e.getKey(); Face f = e.getValue(); - float minU = f.u1 * BLOCKS_PER_UNIT; - float maxU = f.u2 * BLOCKS_PER_UNIT; - float minV = f.v1 * BLOCKS_PER_UNIT; - float maxV = f.v2 * BLOCKS_PER_UNIT; + 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; this.tintIndices[i] = f.tintIndex; this.cullfaces[i] = f.cullFace; diff --git a/game/client/src/main/java/org/useless/dragonfly/data/entity/mojang/EntityGeometryMojangData.java b/game/client/src/main/java/org/useless/dragonfly/data/entity/mojang/EntityGeometryMojangData.java index cae9dc94a..771614ff7 100644 --- a/game/client/src/main/java/org/useless/dragonfly/data/entity/mojang/EntityGeometryMojangData.java +++ b/game/client/src/main/java/org/useless/dragonfly/data/entity/mojang/EntityGeometryMojangData.java @@ -159,7 +159,10 @@ public class EntityGeometryMojangData implements EntityModelData { final Builder builder; if (object.has("description")) { // New desc layout final JsonObject description = object.getAsJsonObject("description"); - builder = new Builder(description.get("visible_bounds_width").getAsDouble(), description.get("visible_bounds_height").getAsDouble()); + + final double visibleBoundsWidth = description.has("visible_bounds_width") ? description.get("visible_bounds_width").getAsDouble() : 0; + final double visibleBoundsHeight = description.has("visible_bounds_height") ? description.get("visible_bounds_height").getAsDouble() : 0; + builder = new Builder(visibleBoundsWidth, visibleBoundsHeight); if (description.has("visible_bounds_offset")) { final double[] offset = GsonHelper.getAsDoubleArray(description.get("visible_bounds_offset"), 3); builder.setVisualBoundsOffset(offset[0], offset[1], offset[2]); @@ -170,7 +173,9 @@ public class EntityGeometryMojangData implements EntityModelData { builder.setTextureSize(width, height); } } else { // Old desc layout - builder = new Builder(object.get("visible_bounds_width").getAsDouble(), object.get("visible_bounds_height").getAsDouble()); + final double visibleBoundsWidth = object.has("visible_bounds_width") ? object.get("visible_bounds_width").getAsDouble() : 0; + final double visibleBoundsHeight = object.has("visible_bounds_height") ? object.get("visible_bounds_height").getAsDouble() : 0; + builder = new Builder(visibleBoundsWidth, visibleBoundsHeight); if (object.has("visible_bounds_offset")) { final double[] offset = GsonHelper.getAsDoubleArray(object.get("visible_bounds_offset"), 3); builder.setVisualBoundsOffset(offset[0], offset[1], offset[2]); diff --git a/game/client/src/main/java/org/useless/dragonfly/models/block/mojang/StaticBlockModelMojang.java b/game/client/src/main/java/org/useless/dragonfly/models/block/mojang/StaticBlockModelMojang.java index 30f3cdd43..ffc867439 100644 --- a/game/client/src/main/java/org/useless/dragonfly/models/block/mojang/StaticBlockModelMojang.java +++ b/game/client/src/main/java/org/useless/dragonfly/models/block/mojang/StaticBlockModelMojang.java @@ -9,11 +9,7 @@ import net.minecraft.client.render.block.model.generic.BlockModelGeneric; import net.minecraft.client.render.tessellator.TessellatorGeneral; import net.minecraft.client.render.texture.stitcher.IconCoordinate; import net.minecraft.core.block.BlockLogic; -import net.minecraft.core.util.helper.Axis; -import net.minecraft.core.util.helper.Color; -import net.minecraft.core.util.helper.Direction; -import net.minecraft.core.util.helper.LightIndexHelper; -import net.minecraft.core.util.helper.Side; +import net.minecraft.core.util.helper.*; import net.minecraft.core.world.WorldSource; import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; @@ -255,6 +251,10 @@ public class StaticBlockModelMojang implements StaticBlockModel { b = 1; } + final int cenX = MathHelper.floor((element.maxX + element.minX) / 2f); + final int cenY = MathHelper.floor((element.maxY + element.minY) / 2f); + final int cenZ = MathHelper.floor((element.maxZ + element.minZ) / 2f); + final int dirX = element.flip ? -direction.offsetX() : direction.offsetX(); final int dirY = element.flip ? -direction.offsetY() : direction.offsetY(); final int dirZ = element.flip ? -direction.offsetZ() : direction.offsetZ(); @@ -271,13 +271,13 @@ public class StaticBlockModelMojang implements StaticBlockModel { final int dirY2; final int dirZ2; if (!isFullCube) { - dirX2 = 0; - dirY2 = 0; - dirZ2 = 0; + dirX2 = cenX; + dirY2 = cenY; + dirZ2 = cenZ; } else { - dirX2 = dirX; - dirY2 = dirY; - dirZ2 = dirZ; + dirX2 = cenX + dirX; + dirY2 = cenY + dirY; + dirZ2 = cenZ + dirZ; } final boolean topT = LIGHTING_CACHE.getOpacity(dirX2 + topX, dirY2 + topY, dirZ2 + topZ); @@ -309,9 +309,9 @@ public class StaticBlockModelMojang implements StaticBlockModel { } else { final byte lmc; if (!isFullCube) { - lmc = getLightIndex(0, 0, 0, element.lightEmission); + lmc = getLightIndex(cenX, cenY, cenZ, element.lightEmission); } else { - lmc = getLightIndex(dirX, dirY, dirZ, element.lightEmission); + lmc = getLightIndex(cenX + dirX, cenY + dirY, cenZ + dirZ, element.lightEmission); } lightIndexTopLeft = lightIndexBottomLeft = lightIndexBottomRight = lightIndexTopRight = lmc; } @@ -323,19 +323,19 @@ public class StaticBlockModelMojang implements StaticBlockModel { if (useAO) { { - final float dirB = getBrightness(dirX, dirY, dirZ, minBrightness); - final boolean lefT = LIGHTING_CACHE.getOpacity(dirX + lefX, dirY + lefY, dirZ + lefZ); - final boolean botT = LIGHTING_CACHE.getOpacity(dirX - topX, dirY - topY, dirZ - topZ); - final boolean topT = LIGHTING_CACHE.getOpacity(dirX + topX, dirY + topY, dirZ + topZ); - final boolean rigT = LIGHTING_CACHE.getOpacity(dirX - lefX, dirY - lefY, dirZ - lefZ); - final float lB = getBrightness(dirX + lefX, dirY + lefY, dirZ + lefZ, minBrightness); - final float bB = getBrightness(dirX - topX, dirY - topY, dirZ - topZ, minBrightness); - final float tB = getBrightness(dirX + topX, dirY + topY, dirZ + topZ, minBrightness); - final float rB = getBrightness(dirX - lefX, dirY - lefY, dirZ - lefZ, minBrightness); - final float blB = botT && lefT ? lB : getBrightness(dirX + lefX - topX, dirY + lefY - topY, dirZ + lefZ - topZ, minBrightness); - final float tlB = topT && lefT ? lB : getBrightness(dirX + lefX + topX, dirY + lefY + topY, dirZ + lefZ + topZ, minBrightness); - final float brB = botT && rigT ? rB : getBrightness(dirX - lefX - topX, dirY - lefY - topY, dirZ - lefZ - topZ, minBrightness); - final float trB = topT && rigT ? rB : getBrightness(dirX - lefX + topX, dirY - lefY + topY, dirZ - lefZ + topZ, minBrightness); + final float dirB = getBrightness(cenX + dirX, cenY + dirY, cenZ + dirZ, minBrightness); + final boolean lefT = LIGHTING_CACHE.getOpacity(cenX + dirX + lefX, cenY + dirY + lefY, cenZ + dirZ + lefZ); + final boolean botT = LIGHTING_CACHE.getOpacity(cenX + dirX - topX, cenY + dirY - topY, cenZ + dirZ - topZ); + final boolean topT = LIGHTING_CACHE.getOpacity(cenX + dirX + topX, cenY + dirY + topY, cenZ + dirZ + topZ); + final boolean rigT = LIGHTING_CACHE.getOpacity(cenX + dirX - lefX, cenY + dirY - lefY, cenZ + dirZ - lefZ); + final float lB = getBrightness(cenX + dirX + lefX, cenY + dirY + lefY, cenZ + dirZ + lefZ, minBrightness); + final float bB = getBrightness(cenX + dirX - topX, cenY + dirY - topY, cenZ + dirZ - topZ, minBrightness); + final float tB = getBrightness(cenX + dirX + topX, cenY + dirY + topY, cenZ + dirZ + topZ, minBrightness); + final float rB = getBrightness(cenX + dirX - lefX, cenY + dirY - lefY, cenZ + dirZ - lefZ, minBrightness); + final float blB = botT && lefT ? lB : getBrightness(cenX + dirX + lefX - topX, cenY + dirY + lefY - topY, cenZ + dirZ + lefZ - topZ, minBrightness); + final float tlB = topT && lefT ? lB : getBrightness(cenX + dirX + lefX + topX, cenY + dirY + lefY + topY, cenZ + dirZ + lefZ + topZ, minBrightness); + final float brB = botT && rigT ? rB : getBrightness(cenX + dirX - lefX - topX, cenY + dirY - lefY - topY, cenZ + dirZ - lefZ - topZ, minBrightness); + final float trB = topT && rigT ? rB : getBrightness(cenX + dirX - lefX + topX, cenY + dirY - lefY + topY, cenZ + dirZ - lefZ + topZ, minBrightness); lightTL = (tlB + lB + tB + dirB) / 4.0F; lightTR = (tB + dirB + trB + rB) / 4.0F; lightBR = (dirB + bB + rB + brB) / 4.0F; @@ -343,18 +343,18 @@ public class StaticBlockModelMojang implements StaticBlockModel { } if (!isFullCube) { final float dirB = getBrightness(0, 0, 0, minBrightness); - final boolean lefT = LIGHTING_CACHE.getOpacity(lefX, lefY, lefZ); - final boolean botT = LIGHTING_CACHE.getOpacity(-topX, -topY, -topZ); - final boolean topT = LIGHTING_CACHE.getOpacity(topX, topY, topZ); - final boolean rigT = LIGHTING_CACHE.getOpacity(-lefX, -lefY, -lefZ); - final float lB = getBrightness(lefX, lefY, lefZ, minBrightness); - final float bB = getBrightness(-topX, -topY, -topZ, minBrightness); - final float tB = getBrightness(topX, topY, topZ, minBrightness); - final float rB = getBrightness(-lefX, -lefY, -lefZ, minBrightness); - final float blB = botT && lefT ? lB : getBrightness(lefX - topX, lefY - topY, lefZ - topZ, minBrightness); - final float tlB = topT && lefT ? lB : getBrightness(lefX + topX, lefY + topY, lefZ + topZ, minBrightness); - final float brB = botT && rigT ? rB : getBrightness(-lefX - topX, -lefY - topY, -lefZ - topZ, minBrightness); - final float trB = topT && rigT ? rB : getBrightness(-lefX + topX, -lefY + topY, -lefZ + topZ, minBrightness); + final boolean lefT = LIGHTING_CACHE.getOpacity(cenX + lefX, cenY + lefY, cenZ + lefZ); + final boolean botT = LIGHTING_CACHE.getOpacity(cenX - topX, cenY - topY, cenZ - topZ); + final boolean topT = LIGHTING_CACHE.getOpacity(cenX + topX, cenY + topY, cenZ + topZ); + final boolean rigT = LIGHTING_CACHE.getOpacity(cenX - lefX, cenY - lefY, cenZ - lefZ); + final float lB = getBrightness(cenX + lefX, cenY + lefY, cenZ + lefZ, minBrightness); + final float bB = getBrightness(cenX - topX, cenY - topY, cenZ - topZ, minBrightness); + final float tB = getBrightness(cenX + topX, cenY + topY, cenZ + topZ, minBrightness); + final float rB = getBrightness(cenX - lefX, cenY - lefY, cenZ - lefZ, minBrightness); + final float blB = botT && lefT ? lB : getBrightness(cenX + lefX - topX, cenY + lefY - topY, cenZ + lefZ - topZ, minBrightness); + final float tlB = topT && lefT ? lB : getBrightness(cenX + lefX + topX, cenY + lefY + topY, cenZ + lefZ + topZ, minBrightness); + final float brB = botT && rigT ? rB : getBrightness(cenX - lefX - topX, cenY - lefY - topY, cenZ - lefZ - topZ, minBrightness); + final float trB = topT && rigT ? rB : getBrightness(cenX - lefX + topX, cenY - lefY + topY, cenZ - lefZ + topZ, minBrightness); lightTL = (tlB + lB + tB + dirB) / 4.0F * depth + lightTL * (1 - depth); lightTR = (tB + dirB + trB + rB) / 4.0F * depth + lightTR * (1 - depth); lightBR = (dirB + bB + rB + brB) / 4.0F * depth + lightBR * (1 - depth); @@ -365,9 +365,9 @@ public class StaticBlockModelMojang implements StaticBlockModel { final int dirY2; final int dirZ2; if (!isFullCube) { - dirX2 = 0; - dirY2 = 0; - dirZ2 = 0; + dirX2 = cenX; + dirY2 = cenY; + dirZ2 = cenZ; } else { dirX2 = dirX; dirY2 = dirY; diff --git a/game/client/src/main/java/org/useless/dragonfly/models/entity/mojang/StaticEntityModelMojang.java b/game/client/src/main/java/org/useless/dragonfly/models/entity/mojang/StaticEntityModelMojang.java index 59187d286..7eb1f21c3 100644 --- a/game/client/src/main/java/org/useless/dragonfly/models/entity/mojang/StaticEntityModelMojang.java +++ b/game/client/src/main/java/org/useless/dragonfly/models/entity/mojang/StaticEntityModelMojang.java @@ -22,6 +22,7 @@ import org.joml.primitives.AABBdc; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL41; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.useless.dragonfly.data.entity.mojang.Bone; import org.useless.dragonfly.data.entity.mojang.Cube; import org.useless.dragonfly.data.entity.mojang.EntityGeometryMojangData; @@ -33,6 +34,7 @@ import java.nio.ByteBuffer; import java.util.Map; public class StaticEntityModelMojang implements StaticEntityModel { + private static final Logger LOGGER = LoggerFactory.getLogger(StaticEntityModelMojang.class.getSimpleName()); public static final int MAX_BONES = 128; private static final BoneTransform DUMMY_TRANSFORM = new BoneTransform(); private static final TessellatorEntity entityTessellator = new TessellatorEntity(16384); @@ -47,9 +49,16 @@ public class StaticEntityModelMojang implements StaticEntityModel { public StaticEntityModelMojang(final @NotNull EntityGeometryMojangData data, final double inflation) { this.data = data; - this.transforms = new BoneTransform[this.data.bones.size()]; - this.bones = new BoneEntry[this.data.bones.size()]; + final int boneCount = Math.min(MAX_BONES, this.data.bones.size()); + this.transforms = new BoneTransform[boneCount]; + this.bones = new BoneEntry[boneCount]; this.inflation = inflation; + if (this.data.bones.size() > MAX_BONES) LOGGER.error( + "Entity model '{}' had {} bone(s), but only a maximum of {} bones are supported! Excess bones will not be rendered", + data.modelId(), + this.data.bones.size(), + MAX_BONES + ); int i = 0; for (final Map.Entry entry : this.data.bones.entrySet()) { @@ -57,7 +66,7 @@ public class StaticEntityModelMojang implements StaticEntityModel { this.transformMap.put(entry.getKey(), transform); this.transforms[i] = transform; this.bones[i] = new BoneEntry(entry.getValue(), i); - i++; + if (++i >= MAX_BONES) break; } this.visBounds = new AABBd( @@ -70,8 +79,10 @@ public class StaticEntityModelMojang implements StaticEntityModel { ); entityTessellator.startDrawingQuads(); - for (BoneEntry bone : this.bones) { + i = 0; + for (final BoneEntry bone : this.bones) { renderBone(entityTessellator, bone); + if (++i >= MAX_BONES) break; } this.renderBuffer = entityTessellator.record(GL41.glGenVertexArrays(), GL41.glGenBuffers()); } @@ -122,7 +133,7 @@ public class StaticEntityModelMojang implements StaticEntityModel { } else { UniformBlockManager.BLOCK_ENTITY_BONES.adapter.bufferData(mat, entry.index() * 16 * 4, UniformBlockManager.BLOCK_ENTITY_BONES.buffer); } - i++; + if (++i >= MAX_BONES) break; } GL41.glBufferSubData(GL41.GL_UNIFORM_BUFFER, 0, UniformBlockManager.BLOCK_ENTITY_BONES.buffer.limit(i * 16 * 4)); GL41.glBindBuffer(GL41.GL_UNIFORM_BUFFER, 0); @@ -147,7 +158,8 @@ public class StaticEntityModelMojang implements StaticEntityModel { if (parent != null) { hidden |= boneTransform(parent, dest); } - final BoneTransform transform = this.transformMap.get(bone.name); + final BoneTransform transform = this.transformMap.getOrDefault(bone.name, DUMMY_TRANSFORM); + hidden |= !transform.visible; dest.translate((float) bone.pivot[0], (float) bone.pivot[1], (float) bone.pivot[2]); dest.translate((float) transform.posX, (float) transform.posY, (float) transform.posZ); diff --git a/game/client/src/main/resources/assets/minecraft/models/entity/pig/pig.animation.json b/game/client/src/main/resources/assets/minecraft/models/entity/pig/pig.animation.json index 40f84bd3c..ac8363675 100644 --- a/game/client/src/main/resources/assets/minecraft/models/entity/pig/pig.animation.json +++ b/game/client/src/main/resources/assets/minecraft/models/entity/pig/pig.animation.json @@ -18,8 +18,14 @@ "leg1": { "rotation": [-90, -15, 0], "position": [1, -4, 0] + }, + "leg2": { + "position": [0.125, 0, 0] + }, + "leg3": { + "position": [-0.125, 0, 0] } } } } -} +} \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/entity/wolf/wolf.geo.json b/game/client/src/main/resources/assets/minecraft/models/entity/wolf/wolf.geo.json index f5def56af..48e098005 100644 --- a/game/client/src/main/resources/assets/minecraft/models/entity/wolf/wolf.geo.json +++ b/game/client/src/main/resources/assets/minecraft/models/entity/wolf/wolf.geo.json @@ -23,8 +23,14 @@ { "name": "mouthItem", "parent": "head", - "pivot": [-1, 8.5, -9.5], - "rotation": [-90, 40, 2.5] + "pivot": [-1, 8.5, -10], + "rotation": [-90, -40, 0] + }, + { + "name": "mouthBlock", + "parent": "head", + "pivot": [-1, 4.5, -12.5], + "rotation": [180, 0, 0] }, { "name": "body", diff --git a/game/client/src/main/resources/assets/minecraft/models/entity/zombie/zombie.geo.json b/game/client/src/main/resources/assets/minecraft/models/entity/zombie/zombie.geo.json index a1b96edc5..24b47a50b 100644 --- a/game/client/src/main/resources/assets/minecraft/models/entity/zombie/zombie.geo.json +++ b/game/client/src/main/resources/assets/minecraft/models/entity/zombie/zombie.geo.json @@ -24,16 +24,6 @@ {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]} ] }, - { - "name": "bodyArmor", - "parent": "body", - "pivot": [0, 24, 0] - }, - { - "name": "belt", - "parent": "body", - "pivot": [0, 24, 0] - }, { "name": "rightArm", "parent": "torso", @@ -48,157 +38,12 @@ "pivot": [-6, 12, -2], "rotation": [90, 0, 0] }, - { - "name": "rightArmArmor", - "parent": "rightArm", - "pivot": [-5, 22, 0] - }, - { - "name": "leftArm", - "parent": "torso", - "pivot": [5, 22, 0], - "mirror": true, - "cubes": [ - {"origin": [4, 12, -2], "size": [4, 12, 4], "uv": [40, 16]} - ] - }, { "name": "leftItem", "parent": "leftArm", "pivot": [6, 12, -2], "rotation": [-90, 180, 0] }, - { - "name": "leftArmArmor", - "parent": "leftArm", - "pivot": [5, 22, 0], - "mirror": true - }, - { - "name": "head", - "parent": "waist", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [0, 0]} - ] - }, - { - "name": "hat", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [32, 0], "inflate": 0.5} - ] - }, - { - "name": "rightLeg", - "parent": "waist", - "pivot": [-1.9, 12, 0], - "cubes": [ - {"origin": [-3.9, 0, -2], "size": [4, 12, 4], "uv": [0, 16]} - ] - }, - { - "name": "rightLegging", - "parent": "rightLeg", - "pivot": [-1.9, 12, 0] - }, - { - "name": "rightBoot", - "parent": "rightLeg", - "pivot": [-1.9, 12, 0] - }, - { - "name": "rightSock", - "parent": "rightLeg", - "pivot": [-1.9, 12, 0] - }, - { - "name": "leftLeg", - "parent": "waist", - "pivot": [1.9, 12, 0], - "mirror": true, - "cubes": [ - {"origin": [-0.1, 0, -2], "size": [4, 12, 4], "uv": [0, 16]} - ] - }, - { - "name": "leftLegging", - "parent": "leftLeg", - "pivot": [1.9, 12, 0], - "mirror": true - }, - { - "name": "leftBoot", - "parent": "leftLeg", - "pivot": [1.9, 12, 0], - "mirror": true - }, - { - "name": "leftSock", - "parent": "leftLeg", - "pivot": [1.9, 12, 0], - "mirror": true - }, - { - "name": "helmet", - "parent": "waist", - "pivot": [0, 24, 0] - } - ] - }, - "geometry.humanoid": { - "texturewidth": 64, - "textureheight": 32, - "visible_bounds_width": 2, - "visible_bounds_height": 3, - "visible_bounds_offset": [0, 1.5, 0], - "bones": [ - { - "name": "waist", - "pivot": [0, 12, 0] - }, - { - "name": "torso", - "parent": "waist", - "pivot": [0, 24, 0] - }, - { - "name": "body", - "parent": "torso", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]} - ] - }, - { - "name": "bodyArmor", - "parent": "body", - "pivot": [0, 24, 0] - }, - { - "name": "belt", - "parent": "body", - "pivot": [0, 24, 0] - }, - { - "name": "rightArm", - "parent": "torso", - "pivot": [-5, 22, 0], - "cubes": [ - {"origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 16]} - ] - }, - { - "name": "rightItem", - "parent": "rightArm", - "pivot": [-6, 15, 1] - }, - { - "name": "rightArmArmor", - "parent": "rightArm", - "pivot": [-5, 22, 0] - }, { "name": "leftArm", "parent": "torso", @@ -208,12 +53,6 @@ {"origin": [4, 12, -2], "size": [4, 12, 4], "uv": [40, 16]} ] }, - { - "name": "leftArmArmor", - "parent": "leftArm", - "pivot": [5, 22, 0], - "mirror": true - }, { "name": "head", "parent": "waist", @@ -231,21 +70,6 @@ {"origin": [-3.9, 0, -2], "size": [4, 12, 4], "uv": [0, 16]} ] }, - { - "name": "rightLegging", - "parent": "rightLeg", - "pivot": [-1.9, 12, 0] - }, - { - "name": "rightBoot", - "parent": "rightLeg", - "pivot": [-1.9, 12, 0] - }, - { - "name": "rightSock", - "parent": "rightLeg", - "pivot": [-1.9, 12, 0] - }, { "name": "leftLeg", "parent": "waist", @@ -254,29 +78,6 @@ "cubes": [ {"origin": [-0.1, 0, -2], "size": [4, 12, 4], "uv": [0, 16]} ] - }, - { - "name": "leftLegging", - "parent": "leftLeg", - "pivot": [1.9, 12, 0], - "mirror": true - }, - { - "name": "leftBoot", - "parent": "leftLeg", - "pivot": [1.9, 12, 0], - "mirror": true - }, - { - "name": "leftSock", - "parent": "leftLeg", - "pivot": [1.9, 12, 0], - "mirror": true - }, - { - "name": "helmet", - "parent": "waist", - "pivot": [0, 24, 0] } ] } diff --git a/game/client/src/main/resources/shaders/entity.fsh b/game/client/src/main/resources/shaders/entity.fsh index fdaca5df0..51f95db8d 100644 --- a/game/client/src/main/resources/shaders/entity.fsh +++ b/game/client/src/main/resources/shaders/entity.fsh @@ -8,6 +8,7 @@ in vec3 Light; uniform float uLightMapStrength; uniform float uAlphaTest; uniform vec4 uColor; +uniform vec4 uOverlayColor; uniform vec2 uLightmap; uniform vec2 uViewPortSize; @@ -70,7 +71,7 @@ void main() { vec4 lightColor = mix(vec4(1, 1, 1, 1), texture(lighttex, uLightmap), uLightMapStrength); vec4 texColor = texture(colortex, TexCoord); - vec4 oColor = texColor * lightColor * uColor; + vec4 oColor = vec4(mix(texColor.rgb, uOverlayColor.rgb, uOverlayColor.a), texColor.a) * lightColor * uColor; vec4 litColor = vec4(oColor.rgb * clamp(Light, 0, 1), oColor.a); vec4 fColor = computeFog(litColor); diff --git a/game/core/src/main/java/net/minecraft/core/Global.java b/game/core/src/main/java/net/minecraft/core/Global.java index b31db96e5..e51099e3d 100644 --- a/game/core/src/main/java/net/minecraft/core/Global.java +++ b/game/core/src/main/java/net/minecraft/core/Global.java @@ -1,9 +1,11 @@ package net.minecraft.core; +import net.minecraft.core.enums.EnumOS; import org.jetbrains.annotations.NotNull; public class Global { + public static final @NotNull EnumOS OS; public static final int TICKS_PER_SECOND = 20; public static final int DAY_LENGTH_TICKS = 24000; public static final @NotNull String VERSION = Version.BUILD_CHANNEL.modifyVersionString(Version.VERSION); @@ -23,6 +25,19 @@ public class Global //noinspection AssertWithSideEffects assert assertions = true; ASSERTIONS_ENABLED = assertions; + + String s = System.getProperty("os.name").toLowerCase(); + if (s.contains("win")) { + OS = EnumOS.windows; + } else if (s.contains("mac")) { + OS = EnumOS.macos; + } else if (s.contains("solaris") || s.contains("sunos")) { + OS = EnumOS.solaris; + } else if (s.contains("linux") || s.contains("unix")) { + OS = EnumOS.linux; + } else { + OS = EnumOS.unknown; + } } public static MinecraftAccessor accessor; diff --git a/game/core/src/main/java/net/minecraft/core/Timer.java b/game/core/src/main/java/net/minecraft/core/Timer.java index aee9d0eb6..4d19a1890 100644 --- a/game/core/src/main/java/net/minecraft/core/Timer.java +++ b/game/core/src/main/java/net/minecraft/core/Timer.java @@ -1,76 +1,205 @@ package net.minecraft.core; -public class Timer +import java.util.concurrent.locks.LockSupport; + +public final class Timer { - public float ticksPerSecond; - private double lastTime; - public int frames; + private long theTime = System.nanoTime(); + private double accTime = 0; + private double nsPerTick; + private int frames; + private double fps; + private long sleepEnd; + + private long lastFpsUpdate = System.nanoTime(); + private double minFpsCtr = Long.MAX_VALUE; + private double maxFpsCtr = Long.MIN_VALUE; + private double minFps; + private double maxFps; + + private long targetNanosPerFrame; + private float ticksPerSecond; public float partialTicks; - public float fps; - public float ticks; - private long currentTime; - private long msPerTick; - private long passedTime; - private double averageFrameTime; - - public Timer(float ticksPerSecond) - { - fps = 1.0F; - ticks = 0.0F; - averageFrameTime = 1.0D; - this.ticksPerSecond = ticksPerSecond; - currentTime = System.currentTimeMillis(); - msPerTick = System.nanoTime() / 1000000L; + + private static final long FPS_SAMPLE_DELAY_NS = 1_000_000_000; + + /** + * Supposed park resolution based on OS. + */ + private static final long PARK_RESOLUTION_NS = getOSPrecisionNanos(); + /** + * The threshold at which the thread is allowed to sleep for {@link Timer#PARK_RESOLUTION_NS} to avoid + * oversleeping.
+ * + * BigSir notes: After some testing it appears that this 1:2 ratio is not enough on Linux (on my machine) + * and sometimes we end up constantly oversleeping. The oversleep amount was usually + * in the tens of thousands of microseconds range so nothing too concerning, but I could see this + * being a bigger issue on Windows. + */ + private static final long PARK_THRESHOLD_NS = 2 * getOSPrecisionNanos(); + + public Timer(float ticksPerSecond) { + this.setTps(ticksPerSecond); + } + + public void setTargetFps(final double fps) { + this.targetNanosPerFrame = fps <= 0 ? 0 : (long) (1_000_000_000.0 / fps); + } + + public void setTps(final float tps) { + this.ticksPerSecond = tps; + this.nsPerTick = 1_000_000_000.0 / tps; + } + + public double getFps() { + return this.fps; } - public void advanceTime() - { - long currentTime = System.currentTimeMillis(); - long timeDelta = currentTime - this.currentTime; - long nanoTime = System.nanoTime() / 1000000L; - double d = (double)nanoTime / 1000D; - if(timeDelta > 1000L) - { - lastTime = d; + public double getFpsMin() { + return this.minFps; + } + + public double getFpsMax() { + return this.maxFps; + } + + public float getTps() { + return this.ticksPerSecond; + } + + public int getGameSteps(final int maxSteps) { + return Math.min(this.frames, maxSteps); + } + + /** + * Sleeps the calling thread based on the value provided by {@link Timer#setTargetFps(double)}. + * This method only works properly when called immediately after an {@link Timer#advanceTime()} call, + * which is expected to be called in a loop continuously. + * The elapsed time between two {@link Timer#advanceTime()} calls is taken into account to avoid oversleeping. + * @see Timer#sleepPrecise(long, long) + */ + public void sleep(final Precision precision) { + final long theTime = System.nanoTime(); + final long deltaTime = theTime - this.sleepEnd; + + if (deltaTime < this.targetNanosPerFrame) { + final long sleepNanos = this.targetNanosPerFrame - deltaTime; + final long spinNanos = precision == Precision.AUTO ? 0 : (long) (precision.spinPercentage * sleepNanos); + + // Force oversleep on power saving + final long parkThreshold = precision == Precision.POWER_SAVING ? 0 : PARK_THRESHOLD_NS; + final long parkResolution = precision == Precision.POWER_SAVING ? 0 : PARK_RESOLUTION_NS; + + sleepPrecise(sleepNanos, spinNanos, parkResolution, parkThreshold); } - else if(timeDelta < 0L) - { - lastTime = d; + + this.sleepEnd = System.nanoTime(); + } + + /** + * Precise sleep implemented based on Kirisame's work in + * + * #1762 + * .
+ * Calling this method will sleep the calling thread for at least {@code nanos} nanoseconds. The precision + * of the sleep timing can be improved by providing a positive {@code spinMargin} value in nanoseconds, which will + * make the calling thread spin for the remaining {@code spinMargin} time. If {@code spinMargin >= nanos}, then + * the calling thread will simply spin until the timeout elapses. When {@code spinMargin} is zero the calling + * thread will at most spend {@link Timer#PARK_RESOLUTION_NS} nanos spinning. + * @param nanos the total time to sleep for in nanoseconds + * @param spinMargin the time to spend spin waiting in nanoseconds + * @param parkResolution the expected resolution of the system timer in nanoseconds + * @param parkThreshold the threshold over which a parkNanos call is made in nanoseconds + */ + public static void sleepPrecise(final long nanos, final long spinMargin, final long parkResolution, final long parkThreshold) { + if (nanos <= 0) return; + + final long theTime = System.nanoTime(); + final long toParkNanos = Math.max(0, nanos - Math.max(spinMargin, 0)); + + final long parkEnd = theTime + toParkNanos; + final long sleepEnd = theTime + nanos; + + // More testing of PARK_THRESHOLD and PARK_RESOLUTION needed!!! + // Getting these values right is probably impossible, but feel free to change + // them if you find something better + long remParkNanos; + while ((remParkNanos = parkEnd - System.nanoTime()) > parkThreshold) { + LockSupport.parkNanos(remParkNanos - parkResolution); } - else - { - passedTime += timeDelta; - if(passedTime > 1000L) - { - long l3 = nanoTime - msPerTick; - double d2 = (double) passedTime / (double)l3; - averageFrameTime += (d2 - averageFrameTime) * 0.2D; - msPerTick = nanoTime; - passedTime = 0L; - } - if(passedTime < 0L) - { - msPerTick = nanoTime; - } + + // Spin for at most max(spinMargin, PARK_THRESHOLD_NS) nanos, or less if we overslept + final long toSpinNanos = sleepEnd - System.nanoTime(); + long timeKeeper = System.nanoTime(); + + while (System.nanoTime() - timeKeeper < toSpinNanos) { + Thread.onSpinWait(); } - this.currentTime = currentTime; - double d1 = (d - lastTime) * averageFrameTime; - lastTime = d; - if(d1 < 0.0D) - { - d1 = 0.0D; + } + + /** + * Calls {@link Timer#sleepPrecise(long, long, long, long)} with {@link Timer#PARK_RESOLUTION_NS} and + * {@link Timer#PARK_THRESHOLD_NS}. + */ + @SuppressWarnings("unused") + public static void sleepPrecise(final long nanos, final long spinMargin) { + sleepPrecise(nanos, spinMargin, PARK_RESOLUTION_NS, PARK_THRESHOLD_NS); + } + + public static long getOSPrecisionNanos() { + return switch (Global.OS) { + case windows -> 1_600_000; // 1.6 ms allegedly + case macos -> 500_000; // 0.5 ms allegedly + case linux -> 50_000; // 50 us (default from https://www.man7.org/linux/man-pages/man2/PR_SET_TIMERSLACK.2const.html) + default -> 50_000; + }; + } + + private void sampleFps(final long nanoTime, final long deltaTime) { + this.fps = 1.0 / (deltaTime / 1_000_000_000.0); + this.minFpsCtr = Math.min(this.fps, this.minFpsCtr); + this.maxFpsCtr = Math.max(this.fps, this.maxFpsCtr); + + // Update samples every second + if (nanoTime - this.lastFpsUpdate >= FPS_SAMPLE_DELAY_NS) { + this.maxFps = this.maxFpsCtr; + this.minFps = this.minFpsCtr; + this.minFpsCtr = Long.MAX_VALUE; + this.maxFpsCtr = Long.MIN_VALUE; + this.lastFpsUpdate = nanoTime; } - if(d1 > 1.0D) - { - d1 = 1.0D; + } + + public void advanceTime() { + final long lastTime = this.theTime; + final long theTime = System.nanoTime(); + final long deltaTime = theTime - lastTime; + this.sampleFps(theTime, deltaTime); + this.theTime = theTime; + this.frames = 0; + + this.accTime += deltaTime; + if (this.accTime >= this.nsPerTick) { + this.frames = Math.min(10, (int) (this.accTime / this.nsPerTick)); + this.accTime %= this.nsPerTick; } - ticks += d1 * (double) fps * (double)ticksPerSecond; - frames = (int) ticks; - ticks -= frames; - if(frames > 10) - { - frames = 10; + + this.partialTicks = (float) (this.accTime / this.nsPerTick); + } + + public enum Precision { + AUTO(0.0), + POWER_SAVING(0.0), + LOW_PRECISION(0.25), + BALANCED(0.5), + HIGH_PRECISION(0.75), + MAX_PRECISION(1.0), + ; + + public final double spinPercentage; + + Precision(final double precision) { + this.spinPercentage = precision; } - partialTicks = ticks; } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBoulderMagmatic.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBoulderMagmatic.java index 72ba7bf14..a57004ecb 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBoulderMagmatic.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBoulderMagmatic.java @@ -2,9 +2,10 @@ package net.minecraft.core.block; import net.minecraft.core.block.entity.TileEntity; import net.minecraft.core.entity.Entity; +import net.minecraft.core.entity.EntityItem; import net.minecraft.core.enums.EnumDropCause; -import net.minecraft.core.item.Items; import net.minecraft.core.item.ItemStack; +import net.minecraft.core.item.Items; import net.minecraft.core.world.World; import net.minecraft.core.world.pos.TilePos; import net.minecraft.core.world.pos.TilePosc; @@ -17,11 +18,21 @@ public class BlockLogicBoulderMagmatic extends BlockLogicFlower { this.setBlockBounds(0.1F, 0.0F, 0.1F, 0.9F, 0.8F, 0.9F); } + public @NotNull Block getFireBlock() { + return Blocks.FIRE; + } + + public @NotNull ItemStack getMainDrop() { + return new ItemStack(Items.NETHERCOAL); + } + @Override public void onEntityCollision(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Entity entity) { - entity.maxFireTicks = 100; - entity.remainingFireTicks = 100; - entity.activeFireBlock = Blocks.FIRE; + if (!entity.isFireImmune() && !(entity instanceof EntityItem)) { + entity.maxFireTicks = 100; + entity.remainingFireTicks = 100; + entity.activeFireBlock = this.getFireBlock(); + } } @Override @@ -41,7 +52,7 @@ public class BlockLogicBoulderMagmatic extends BlockLogicFlower { default -> { final int pebbles = 1 + world.rand.nextInt(2); if (world.rand.nextInt(4) == 0) { - yield new ItemStack[]{new ItemStack(Items.AMMO_PEBBLE, pebbles), new ItemStack(Items.NETHERCOAL)}; + yield new ItemStack[]{new ItemStack(Items.AMMO_PEBBLE, pebbles), this.getMainDrop()}; } yield new ItemStack[]{new ItemStack(Items.AMMO_PEBBLE, pebbles)}; } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBoulderSulfuric.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBoulderSulfuric.java index 6791d070b..346324be5 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBoulderSulfuric.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBoulderSulfuric.java @@ -1,15 +1,10 @@ package net.minecraft.core.block; -import net.minecraft.core.block.entity.TileEntity; -import net.minecraft.core.entity.Entity; -import net.minecraft.core.enums.EnumDropCause; -import net.minecraft.core.item.Items; import net.minecraft.core.item.ItemStack; -import net.minecraft.core.world.World; -import net.minecraft.core.world.pos.TilePosc; +import net.minecraft.core.item.Items; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +// TODO this should probably be metadata based in 8.1? public class BlockLogicBoulderSulfuric extends BlockLogicBoulderMagmatic { public BlockLogicBoulderSulfuric(@NotNull Block block) { super(block); @@ -17,23 +12,12 @@ public class BlockLogicBoulderSulfuric extends BlockLogicBoulderMagmatic { } @Override - public @NotNull ItemStack @Nullable [] getBreakResult(@NotNull World world, @NotNull EnumDropCause dropCause, int meta, @Nullable TileEntity tileEntity) { - return switch (dropCause) { - case SILK_TOUCH, PICK_BLOCK -> new ItemStack[]{new ItemStack(this)}; - default -> { - final int pebbles = 1 + world.rand.nextInt(2); - if (world.rand.nextInt(4) == 0) { - yield new ItemStack[]{new ItemStack(Items.AMMO_PEBBLE, pebbles), new ItemStack(Items.SULFUR)}; - } - yield new ItemStack[]{new ItemStack(Items.AMMO_PEBBLE, pebbles)}; - } - }; + public @NotNull Block getFireBlock() { + return Blocks.FIRE_SULFURIC; } @Override - public void onEntityCollision(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Entity entity) { - entity.maxFireTicks = 100; - entity.remainingFireTicks = 100; - entity.activeFireBlock = Blocks.FIRE_SULFURIC; + public @NotNull ItemStack getMainDrop() { + return new ItemStack(Items.SULFUR); } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicButtonPainted.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicButtonPainted.java index a2b9673f5..809c4837a 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicButtonPainted.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicButtonPainted.java @@ -48,7 +48,7 @@ public class BlockLogicButtonPainted @Override public void setColor(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull DyeColor color) { final int meta = world.getBlockData(tilePos); - world.setBlockDataNotify(tilePos, meta | color.blockMeta << 4); + world.setBlockDataNotify(tilePos, meta & ~MASK_COLOR | color.blockMeta << 4); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java index faacd85aa..b3d57f053 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java @@ -64,11 +64,14 @@ public class BlockLogicDispenser extends BlockLogicVeryRotatable { if (itemStack.getItem() instanceof final @NotNull IDispensable dispensable) { dispensable.onDispensed(itemStack, world, random, direction, pos.x(), pos.y(), pos.z()); world.playBlockEvent(tilePos, LevelListener.EVENT_DISPENSER_PROJECTILE, 0); - } else if (itemStack.itemID == Items.AMMO_ARROW.id || itemStack.itemID == Items.AMMO_ARROW_GOLD.id) { + } else if (itemStack.itemID == Items.AMMO_ARROW.id || itemStack.itemID == Items.AMMO_ARROW_GOLD.id || itemStack.itemID == Items.AMMO_ARROW_FLAMING.id) { + // FIXME bad! if (itemStack.consumeItem(null)) { final @NotNull ProjectileArrow arrow; if (itemStack.itemID == Items.AMMO_ARROW.id) { arrow = new ProjectileArrow(world, pos.x(), pos.y(), pos.z(), 0); + } else if (itemStack.itemID == Items.AMMO_ARROW_FLAMING.id) { + arrow = new ProjectileArrowFlaming(world, pos.x(), pos.y(), pos.z()); } else { arrow = new ProjectileArrowGolden(world, pos.x(), pos.y(), pos.z()); } diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityBasket.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityBasket.java index cd3774ccb..c310ec6ab 100644 --- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityBasket.java +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityBasket.java @@ -19,6 +19,7 @@ import net.minecraft.core.util.collection.NamespaceID; import net.minecraft.core.world.ICarriable; import net.minecraft.core.world.ICarrySource; import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; @@ -60,7 +61,7 @@ public class TileEntityBasket extends TileEntity implements ICarrySource { } - private void dropItemStack(final Random rand, final ItemStack itemstack) { + private void dropItemStack(@NotNull final TilePosc pos, @NotNull final Random rand, @NotNull final ItemStack itemstack) { final float f = rand.nextFloat() * 0.8F + 0.1F; final float f1 = rand.nextFloat() * 0.8F + 0.1F; final float f2 = rand.nextFloat() * 0.8F + 0.1F; @@ -74,7 +75,7 @@ public class TileEntityBasket extends TileEntity implements ICarrySource { return; } - final EntityItem item = new EntityItem(workingWorld, this.tilePos.x + f, this.tilePos.y + f1, this.tilePos.z + f2, itemstack); + final EntityItem item = new EntityItem(workingWorld, pos.x() + f, pos.y() + f1, pos.z() + f2, itemstack); final float f3 = 0.05F; item.xd = (float) rand.nextGaussian() * f3; item.yd = (float) rand.nextGaussian() * f3 + 0.25F; @@ -222,7 +223,7 @@ public class TileEntityBasket extends TileEntity implements ICarrySource { final int remainingItems = numItems - maxStackSize; if (remainingItems < 0) stackSize = numItems; numItems -= stackSize; - dropItemStack(rand, new ItemStack(be.id, stackSize, be.metadata, be.tag)); + dropItemStack(new TilePos(x, y, z), rand, new ItemStack(be.id, stackSize, be.metadata, be.tag)); } } diff --git a/game/core/src/main/java/net/minecraft/core/data/registry/Registry.java b/game/core/src/main/java/net/minecraft/core/data/registry/Registry.java index 1903e6bf6..1dfd62d79 100644 --- a/game/core/src/main/java/net/minecraft/core/data/registry/Registry.java +++ b/game/core/src/main/java/net/minecraft/core/data/registry/Registry.java @@ -12,6 +12,7 @@ import java.util.*; /** * Stores an association between an object and a string key. + * The key has to be unique. * @param The type of item to store. */ public class Registry @@ -33,6 +34,10 @@ public class Registry Objects.requireNonNull(key); Objects.requireNonNull(item); + if(keyItemMap.containsKey(key)){ + throw new IllegalArgumentException("Duplicate key '" + key + "'!"); + } + items.add(item); keyItemMap.put(key, item); itemKeyMap.put(item, key); 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 cf52c9be9..26685f8cf 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 @@ -191,6 +191,10 @@ public abstract class Entity return this.entityData; } + public boolean isFireImmune() { + return this.fireImmune; + } + @Override public boolean equals(@Nullable Object that) { if (that instanceof Entity) { diff --git a/game/core/src/main/java/net/minecraft/core/entity/EntityItem.java b/game/core/src/main/java/net/minecraft/core/entity/EntityItem.java index 06c2c4f2f..4e36a1883 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/EntityItem.java +++ b/game/core/src/main/java/net/minecraft/core/entity/EntityItem.java @@ -46,7 +46,7 @@ public class EntityItem extends Entity private static final int BASE_DESPAWN_TICKS = 10 * 60 * 20; private static final int BASE_FADE_TICKS = 2 * 60 * 20; public static final float DESPAWN_ALPHA_THRESHOLD = 0.01f; - private static final int DESPAWN_FORCE_REMOVE_BUFFER = 20; + public static final int DESPAWN_FORCE_REMOVE_BUFFER = 20; public static int getDespawnFadeTicks(final int lifetime) { if (lifetime <= 0) { 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 725fdf11f..e1a497171 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 @@ -506,7 +506,6 @@ public abstract class Mob extends Entity { if (getHealth() <= 0) { return false; } - this.walkAnimSpeed = 1.5F; boolean flag = true; if ((float) this.heartsFlashTime > (float) this.heartsHalvesLife / 2.0F) { if (damage <= this.lastDamage) { @@ -525,6 +524,7 @@ public abstract class Mob extends Entity { this.hurtTime = this.maxHurtTime = 10; } } + this.walkAnimSpeed = 1.5F; this.attackedAtYaw = 0.0F; if (flag) { markHurt(); diff --git a/game/core/src/main/java/net/minecraft/core/entity/monster/MobGhast.java b/game/core/src/main/java/net/minecraft/core/entity/monster/MobGhast.java index 37c4b8f6c..9ee83a770 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/monster/MobGhast.java +++ b/game/core/src/main/java/net/minecraft/core/entity/monster/MobGhast.java @@ -97,24 +97,29 @@ public class MobGhast extends MobFlying implements Enemy { } tryToDespawn(); - double d = this.waypointX - this.x; - double d1 = this.waypointY - this.y; - double d2 = this.waypointZ - this.z; - double d3 = d * d + d1 * d1 + d2 * d2; + double distX = this.waypointX - this.x; + double distY = this.waypointY - this.y; + double distZ = this.waypointZ - this.z; + double sqrDist = distX * distX + distY * distY + distZ * distZ; - if (d3 < 1.0D || d3 > 3600.0D) { + if (sqrDist < 1.0D || sqrDist > 3600.0D) { this.waypointX = this.x + (double)((this.random.nextFloat() * 2.0F - 1.0F) * 16.0F); this.waypointY = this.y + (double)((this.random.nextFloat() * 2.0F - 1.0F) * 16.0F); this.waypointZ = this.z + (double)((this.random.nextFloat() * 2.0F - 1.0F) * 16.0F); + + distX = this.waypointX - this.x; + distY = this.waypointY - this.y; + distZ = this.waypointZ - this.z; + sqrDist = distX * distX + distY * distY + distZ * distZ; } if (this.courseChangeCooldown-- <= 0) { this.courseChangeCooldown += this.random.nextInt(5) + 2; - d3 = MathHelper.sqrt(d3); - if (this.isCourseTraversable(this.waypointX, this.waypointY, this.waypointZ, d3)) { - this.xd += d / d3 * 0.1D; - this.yd += d1 / d3 * 0.1D; - this.zd += d2 / d3 * 0.1D; + sqrDist = MathHelper.sqrt(sqrDist); + if (this.isCourseTraversable(this.waypointX, this.waypointY, this.waypointZ, sqrDist)) { + this.xd += distX / sqrDist * 0.1D; + this.yd += distY / sqrDist * 0.1D; + this.zd += distZ / sqrDist * 0.1D; } else { this.waypointX = this.x; this.waypointY = this.y; diff --git a/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileArrow.java b/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileArrow.java index e5f377d52..6e2766cef 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileArrow.java +++ b/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileArrow.java @@ -3,6 +3,7 @@ package net.minecraft.core.entity.projectile; import com.mojang.nbt.tags.CompoundTag; import net.minecraft.core.achievement.Achievements; import net.minecraft.core.block.Blocks; +import net.minecraft.core.entity.EntityItem; import net.minecraft.core.entity.Mob; import net.minecraft.core.entity.player.Player; import net.minecraft.core.util.phys.HitResult; @@ -132,7 +133,10 @@ public class ProjectileArrow extends Projectile { } this.ticksInGround++; if (this.ticksInGround >= LIFETIME) { - remove(); + if (EntityItem.getDespawnFadeAlpha(this.ticksInGround, LIFETIME, 0f) <= EntityItem.DESPAWN_ALPHA_THRESHOLD + || this.ticksInGround >= LIFETIME + EntityItem.DESPAWN_FORCE_REMOVE_BUFFER) { + remove(); + } } return; } else if (this instanceof ProjectileArrowGolden) { diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemWandSpawner.java b/game/core/src/main/java/net/minecraft/core/item/ItemWandSpawner.java index 2e4a7e2cd..26169e273 100644 --- a/game/core/src/main/java/net/minecraft/core/item/ItemWandSpawner.java +++ b/game/core/src/main/java/net/minecraft/core/item/ItemWandSpawner.java @@ -36,6 +36,15 @@ public class ItemWandSpawner extends Item implements IDispensable return true; } + @Override + public boolean useOnEntity(@NotNull ItemStack selfStack, @NotNull Player player, @NotNull Mob mob) { + if (player.gamemode != Gamemodes.CREATIVE || player.isSneaking()) return false; + + final World world = mob.world; + if (!world.isClientSide) spawnEntity(selfStack, world, mob.x, mob.y, mob.z); + return true; + } + @Override public @Nullable ItemStack onUse(@NotNull ItemStack selfStack, @NotNull World world, @NotNull Player player) { if (player.gamemode != Gamemodes.CREATIVE){ diff --git a/game/core/src/main/java/net/minecraft/core/lang/Language.java b/game/core/src/main/java/net/minecraft/core/lang/Language.java index c3083c8fe..01893b4fd 100644 --- a/game/core/src/main/java/net/minecraft/core/lang/Language.java +++ b/game/core/src/main/java/net/minecraft/core/lang/Language.java @@ -120,6 +120,10 @@ public class Language { throw new RuntimeException(e); } } + + if(!"en_US".equals(id)){ + loadFromNamespaces(); + } } /** @@ -139,6 +143,33 @@ public class Language { if (directory != null) { loadFromDirectory(directory); } + + if(!"en_US".equals(id)){ + loadFromNamespaces(); + } + } + + private void loadFromNamespaces(){ + for (String namespace : Registries.NAMESPACES) { + String dirPath = "/assets/" + namespace + "/lang/" + this.id + "/"; + for (String path : I18n.getFilesInDirectory(dirPath)) { + if (!path.endsWith(".lang")) continue; + try (InputStream is = I18n.getResourceAsStream(path)) { + if (is == null) continue; + Properties props = new Properties(); + try (InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) { + props.load(reader); + } + for (String key : props.stringPropertyNames()) { + if (this.entries.getProperty(key) == null) { + this.entries.setProperty(key, props.getProperty(key)); + } + } + } catch (Exception e) { + LOGGER.error("Failed to load lang file '{}' from namespace '{}' for locale '{}'", path, namespace, this.id, e); + } + } + } } private void loadFromDirectory(File directory) { diff --git a/game/core/src/main/java/net/minecraft/core/net/command/util/CommandHelper.java b/game/core/src/main/java/net/minecraft/core/net/command/util/CommandHelper.java index 2592309e7..a1ef8916b 100644 --- a/game/core/src/main/java/net/minecraft/core/net/command/util/CommandHelper.java +++ b/game/core/src/main/java/net/minecraft/core/net/command/util/CommandHelper.java @@ -162,57 +162,57 @@ public class CommandHelper { // e.printStackTrace(); // } // TODO hopefully find a way to automatically accomplish this without having to manually add all features - registerWorldFeatureClass(WorldFeatureAlgae.class); - registerWorldFeatureClass(WorldFeatureCactus.class); - registerWorldFeatureClass(WorldFeatureClay.class); - registerWorldFeatureClass(WorldFeatureDeadBush.class); - registerWorldFeatureClass(WorldFeatureDungeon.class); - registerWorldFeatureClass(WorldFeatureFire.class); - registerWorldFeatureClass(WorldFeatureFlowers.class); - registerWorldFeatureClass(WorldFeatureGlowstone.class); - registerWorldFeatureClass(WorldFeatureGrassPatch.class); - registerWorldFeatureClass(WorldFeatureLabyrinth.class); - registerWorldFeatureClass(WorldFeatureLake.class); - registerWorldFeatureClass(WorldFeatureLiquid.class); - registerWorldFeatureClass(WorldFeatureMeadow.class); - registerWorldFeatureClass(WorldFeatureMudPatch.class); - registerWorldFeatureClass(WorldFeatureNetherSpring.class); - registerWorldFeatureClass(WorldFeatureOre.class); - registerWorldFeatureClass(WorldFeaturePermaice.class); - registerWorldFeatureClass(WorldFeaturePumice.class); - registerWorldFeatureClass(WorldFeaturePumpkin.class); - registerWorldFeatureClass(WorldFeatureRichScorchedDirt.class); - registerWorldFeatureClass(WorldFeatureSpinifexPatch.class); - registerWorldFeatureClass(WorldFeatureSponge.class); - registerWorldFeatureClass(WorldFeatureSugarCane.class); - registerWorldFeatureClass(WorldFeatureSugarCaneTall.class); - registerWorldFeatureClass(WorldFeatureTallGrass.class); - - registerWorldFeatureClass(WorldFeatureCherryTreeFancy.class); - registerWorldFeatureClass(WorldFeatureTree.class); - registerWorldFeatureClass(WorldFeatureTreeCaatinga.class); - registerWorldFeatureClass(WorldFeatureTreeCherry.class); - registerWorldFeatureClass(WorldFeatureTreeEucalyptus.class); - registerWorldFeatureClass(WorldFeatureTreeFancy.class); - registerWorldFeatureClass(WorldFeatureTreeFancyRainforest.class); - registerWorldFeatureClass(WorldFeatureTreePalm.class); - registerWorldFeatureClass(WorldFeatureTreeShapeSwamp.class); - registerWorldFeatureClass(WorldFeatureTreeShrub.class); - registerWorldFeatureClass(WorldFeatureTreeTaigaBushy.class); - registerWorldFeatureClass(WorldFeatureTreeTaigaTall.class); - registerWorldFeatureClass(WorldFeatureTreeTall.class); - registerWorldFeatureClass(WorldFeatureTreeThorn.class); - - registerWorldFeatureClass(WorldFeatureSpoonerTree.class); - registerWorldFeatureClass(WorldFeatureSpoonerTreeBamboo.class); - registerWorldFeatureClass(WorldFeatureSpoonerTreeCone.class); - registerWorldFeatureClass(WorldFeatureSpoonerTreeMangrove.class); - registerWorldFeatureClass(WorldFeatureSpoonerTreeNormal.class); - registerWorldFeatureClass(WorldFeatureSpoonerTreePalm.class); - registerWorldFeatureClass(WorldFeatureSpoonerTreeProcedural.class); - registerWorldFeatureClass(WorldFeatureSpoonerTreeRainforest.class); - registerWorldFeatureClass(WorldFeatureSpoonerTreeRound.class); - registerWorldFeatureClass(WorldFeatureSpoonerTreeStick.class); + registerWorldFeatureClass(WorldFeatureAlgae.class, "Algae"); + registerWorldFeatureClass(WorldFeatureCactus.class, "Cactus"); + registerWorldFeatureClass(WorldFeatureClay.class, "Clay"); + registerWorldFeatureClass(WorldFeatureDeadBush.class, "DeadBush"); + registerWorldFeatureClass(WorldFeatureDungeon.class, "Dungeon"); + registerWorldFeatureClass(WorldFeatureFire.class, "Fire"); + registerWorldFeatureClass(WorldFeatureFlowers.class, "Flowers"); + registerWorldFeatureClass(WorldFeatureGlowstone.class, "Glowstone"); + registerWorldFeatureClass(WorldFeatureGrassPatch.class, "GrassPatch"); + registerWorldFeatureClass(WorldFeatureLabyrinth.class, "Labyrinth"); + registerWorldFeatureClass(WorldFeatureLake.class, "Lake"); + registerWorldFeatureClass(WorldFeatureLiquid.class, "Liquid"); + registerWorldFeatureClass(WorldFeatureMeadow.class, "Meadow"); + registerWorldFeatureClass(WorldFeatureMudPatch.class, "MudPatch"); + registerWorldFeatureClass(WorldFeatureNetherSpring.class, "NetherSpring"); + registerWorldFeatureClass(WorldFeatureOre.class, "Ore"); + registerWorldFeatureClass(WorldFeaturePermaice.class, "Permaice"); + registerWorldFeatureClass(WorldFeaturePumice.class, "Pumice"); + registerWorldFeatureClass(WorldFeaturePumpkin.class, "Pumpkin"); + registerWorldFeatureClass(WorldFeatureRichScorchedDirt.class, "RichScorchedDirt"); + registerWorldFeatureClass(WorldFeatureSpinifexPatch.class, "SpinifexPatch"); + registerWorldFeatureClass(WorldFeatureSponge.class, "Sponge"); + registerWorldFeatureClass(WorldFeatureSugarCane.class, "SugarCane"); + registerWorldFeatureClass(WorldFeatureSugarCaneTall.class, "SugarCaneTall"); + registerWorldFeatureClass(WorldFeatureTallGrass.class, "TallGrass"); + + registerWorldFeatureClass(WorldFeatureCherryTreeFancy.class, "CherryTreeFancy"); + registerWorldFeatureClass(WorldFeatureTree.class, "Tree"); + registerWorldFeatureClass(WorldFeatureTreeCaatinga.class, "TreeCaatinga"); + registerWorldFeatureClass(WorldFeatureTreeCherry.class, "TreeCherry"); + registerWorldFeatureClass(WorldFeatureTreeEucalyptus.class, "TreeEucalyptus"); + registerWorldFeatureClass(WorldFeatureTreeFancy.class, "TreeFancy"); + registerWorldFeatureClass(WorldFeatureTreeFancyRainforest.class, "TreeFancyRainforest"); + registerWorldFeatureClass(WorldFeatureTreePalm.class, "TreePalm"); + registerWorldFeatureClass(WorldFeatureTreeShapeSwamp.class, "TreeShapeSwamp"); + registerWorldFeatureClass(WorldFeatureTreeShrub.class, "TreeShrub"); + registerWorldFeatureClass(WorldFeatureTreeTaigaBushy.class, "TreeTaigaBushy"); + registerWorldFeatureClass(WorldFeatureTreeTaigaTall.class, "TreeTaigaTall"); + registerWorldFeatureClass(WorldFeatureTreeTall.class, "TreeTall"); + registerWorldFeatureClass(WorldFeatureTreeThorn.class, "TreeThorn"); + + registerWorldFeatureClass(WorldFeatureSpoonerTree.class, "SpoonerTree"); + registerWorldFeatureClass(WorldFeatureSpoonerTreeBamboo.class, "SpoonerTreeBamboo"); + registerWorldFeatureClass(WorldFeatureSpoonerTreeCone.class, "SponerTreeCone"); + registerWorldFeatureClass(WorldFeatureSpoonerTreeMangrove.class, "SpoonerTreeMangrove"); + registerWorldFeatureClass(WorldFeatureSpoonerTreeNormal.class, "SpoonerTreeNormal"); + registerWorldFeatureClass(WorldFeatureSpoonerTreePalm.class, "SpoonerTreePalm"); + registerWorldFeatureClass(WorldFeatureSpoonerTreeProcedural.class, "SpoonerTreeProcedural"); + registerWorldFeatureClass(WorldFeatureSpoonerTreeRainforest.class, "SpoonerTreeRainforest"); + registerWorldFeatureClass(WorldFeatureSpoonerTreeRound.class, "SpoonerTreeRound"); + registerWorldFeatureClass(WorldFeatureSpoonerTreeStick.class, "SpoonerTreeStick"); registerWorldFeatureClass(WorldFeatureHangingDungeon.Gloomstone.class, "HangingDungeonGloomstone"); registerWorldFeatureClass(WorldFeatureHangingDungeon.Basalt.class, "HangingDungeonBasalt"); @@ -220,8 +220,19 @@ public class CommandHelper { registerWorldFeatureClass(WorldFeatureHangingDungeon.Slate.class, "HangingDungeonSlate"); } + /** + * @deprecated Use {@link CommandHelper#registerWorldFeatureClass(Class, String)} + */ + @Deprecated(since = "8.0.2") public static void registerWorldFeatureClass(@NotNull final Class tClass) { - registerWorldFeatureClass(tClass, tClass.getSimpleName().substring(12)); + final String prefix = "WorldFeature"; + final int prefixLen = prefix.length(); + + final String name = tClass.getSimpleName(); + final int prefixIdx = name.indexOf(prefix); + final boolean useSimpleName = prefixIdx == -1 || name.length() <= prefixIdx + prefixLen; + + registerWorldFeatureClass(tClass, useSimpleName ? name : name.substring(prefixIdx + prefixLen)); } public static void registerWorldFeatureClass(@NotNull final Class tClass, @NotNull final String name) { diff --git a/game/core/src/main/java/net/minecraft/core/player/inventory/slot/SlotResult.java b/game/core/src/main/java/net/minecraft/core/player/inventory/slot/SlotResult.java index f35fc8862..0e89a68af 100644 --- a/game/core/src/main/java/net/minecraft/core/player/inventory/slot/SlotResult.java +++ b/game/core/src/main/java/net/minecraft/core/player/inventory/slot/SlotResult.java @@ -41,7 +41,7 @@ public class SlotResult extends Slot if(item.id == Blocks.FURNACE_STONE_IDLE.id()) thePlayer.addStat(Achievements.BUILD_FURNACE, 1); if(item.id == Blocks.FURNACE_BLAST_IDLE.id()) thePlayer.addStat(Achievements.GET_STEEL_BLAST_FURNACE, 1); if(item.id == Items.FOOD_CAKE.id) thePlayer.addStat(Achievements.BAKE_CAKE, 1); - if(item instanceof ItemBucket && ItemBucket.getState(itemStack) == ItemBucket.STATE_ICECREAM) thePlayer.addStat(Achievements.CRAFT_ICECREAM, 1); + if(item instanceof ItemBucket && ItemBucket.STATE_ICECREAM.equals(ItemBucket.getState(itemStack))) thePlayer.addStat(Achievements.CRAFT_ICECREAM, 1); if(item.id == Items.FOOD_PUMPKIN_PIE.id) thePlayer.addStat(Achievements.CRAFT_PUMPKIN_PIE, 1); if(item.id == Items.HANDCANNON_UNLOADED.id) thePlayer.addStat(Achievements.CRAFT_HANDCANNON, 1); if(item instanceof ItemToolHoe) thePlayer.addStat(Achievements.BUILD_HOE, 1); diff --git a/game/core/src/main/java/net/minecraft/core/util/helper/Color.java b/game/core/src/main/java/net/minecraft/core/util/helper/Color.java index 6329e1012..239808682 100644 --- a/game/core/src/main/java/net/minecraft/core/util/helper/Color.java +++ b/game/core/src/main/java/net/minecraft/core/util/helper/Color.java @@ -3,6 +3,7 @@ package net.minecraft.core.util.helper; import com.b100.utils.InvalidCharacterException; import com.b100.utils.StringReader; +@SuppressWarnings("unused") public class Color { public static final int SHIFT_ALPHA = 24; public static final int SHIFT_RED = 16; @@ -69,6 +70,27 @@ public class Color { throw new RuntimeException("Invalid Color String: \""+colorString+"\"", e); } } + + public static int mixARGB(final int argb1, final int argb2, final float f) { + final float ff = 1.0F - f; + final int a = (int) ((argb1 >>> 24) * ff + (argb2 >>> 24) * f); + final int r = (int) ((argb1 >>> 16 & 0xFF) * ff + (argb2 >>> 16 & 0xFF) * f); + final int g = (int) ((argb1 >>> 8 & 0xFF) * ff + (argb2 >>> 8 & 0xFF) * f); + final int b = (int) ((argb1 & 0xFF) * ff + (argb2 & 0xFF) * f); + return a << 24 | r << 16 | g << 8 | b; + } + + public static int blendARGB(final int argb1, final int argb2) { + final int a1 = argb1 >>> 24; + final int a2 = argb2 >>> 24; + final int aSum = a1 + a2; + final float f1 = a1 / (float) aSum; + final float f2 = a2 / (float) aSum; + final int r = (int) ((argb1 >>> 16 & 0xFF) * f1 + (argb2 >>> 16 & 0xFF) * f2); + final int g = (int) ((argb1 >>> 8 & 0xFF) * f1 + (argb2 >>> 8 & 0xFF) * f2); + final int b = (int) ((argb1 & 0xFF) * f1 + (argb2 & 0xFF) * f2); + return Math.min(aSum, 255) << 24 | r << 16 | g << 8 | b; + } public int getARGB() { return value; diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderB173.java b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderB173.java index 201b7c338..c9afcda2a 100644 --- a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderB173.java +++ b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderB173.java @@ -17,22 +17,29 @@ public class BiomeProviderB173 private static final double DOWNFALL_SCALE = 0.05; private static final double NOISE_SCALE = 0.25; - private final @NotNull FractalNoise2D temperatureMap; - private final @NotNull FractalNoise2D downfallMap; - private final @NotNull FractalNoise2D noiseMap; + private final ThreadLocal maps; + private final record Maps( + @NotNull FractalNoise2D temperatureMap, + @NotNull FractalNoise2D downfallMap, + @NotNull FractalNoise2D noiseMap + ) {} public BiomeProviderB173(final @NotNull World world) { super(world); final long seed = world.getRandomSeed(); - this.temperatureMap = new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 9871, 4)); - this.downfallMap = new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 39811, 4)); - this.noiseMap = new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 543321, 4)); + this.maps = ThreadLocal.withInitial(() -> new Maps( + new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 9871L, 4)), + new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 39811L, 4)), + new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 543321L, 4)) + )); } @Override public Biome[] getBiomes(Biome[] biomes, double[] temperatures, double[] humidities, double[] varieties, final int x, final int y, final int z, final int xSize, final int ySize, final int zSize) { + final var maps = this.maps.get(); + if (biomes == null || biomes.length < xSize * ySize * zSize) { biomes = new Biome[xSize * ySize * zSize]; } @@ -40,19 +47,19 @@ public class BiomeProviderB173 if (temperatures == null || temperatures.length < xSize * zSize) { temperatures = new double[xSize * zSize]; } - this.temperatureMap.setLacunarity(0.25).getRegion(temperatures, x, z, xSize, xSize, TEMP_SCALE, TEMP_SCALE); + maps.temperatureMap.setLacunarity(0.25).getRegion(temperatures, x, z, xSize, xSize, TEMP_SCALE, TEMP_SCALE); if (humidities == null || humidities.length < xSize * zSize) { humidities = new double[xSize * zSize]; } - this.downfallMap.setLacunarity(1.0 / 3.0).getRegion(humidities, x, z, xSize, xSize, DOWNFALL_SCALE, DOWNFALL_SCALE); + maps.downfallMap.setLacunarity(1.0 / 3.0).getRegion(humidities, x, z, xSize, xSize, DOWNFALL_SCALE, DOWNFALL_SCALE); if (varieties == null || varieties.length < xSize * zSize) { varieties = new double[xSize * zSize]; } Arrays.fill(varieties, 0.0); - final double @NotNull [] noises = this.noiseMap.setLacunarity(10.0 / 17.0).getRegion(null, x, z, xSize, xSize, NOISE_SCALE, NOISE_SCALE); + final double @NotNull [] noises = maps.noiseMap.setLacunarity(10.0 / 17.0).getRegion(null, x, z, xSize, xSize, NOISE_SCALE, NOISE_SCALE); for (int xx = 0; xx < xSize; xx++) { for (int zz = 0; zz < zSize; zz++) { @@ -95,12 +102,14 @@ public class BiomeProviderB173 @Override public double[] getTemperatures(double[] temperatures, final int x, final int z, final int xSize, final int zSize) { + final var maps = this.maps.get(); + if (temperatures == null || temperatures.length < xSize * zSize) { temperatures = new double[xSize * zSize]; } - this.temperatureMap.setLacunarity(0.25).getRegion(temperatures, x, z, xSize, xSize, TEMP_SCALE, TEMP_SCALE); + maps.temperatureMap.setLacunarity(0.25).getRegion(temperatures, x, z, xSize, xSize, TEMP_SCALE, TEMP_SCALE); - final double @NotNull [] noises = this.noiseMap.setLacunarity(10.0 / 17.0).getRegion(null, x, z, xSize, zSize, NOISE_SCALE, NOISE_SCALE); + final double @NotNull [] noises = maps.noiseMap.setLacunarity(10.0 / 17.0).getRegion(null, x, z, xSize, zSize, NOISE_SCALE, NOISE_SCALE); int i = 0; for (int xx = 0; xx < xSize; xx++) { @@ -130,7 +139,7 @@ public class BiomeProviderB173 if (humidities == null || humidities.length < xSize * zSize) { humidities = new double[xSize * zSize]; } - return this.downfallMap.setLacunarity(0.5).getRegion(humidities, x, z, xSize, zSize, DOWNFALL_SCALE, DOWNFALL_SCALE); + return this.maps.get().downfallMap.setLacunarity(0.5).getRegion(humidities, x, z, xSize, zSize, DOWNFALL_SCALE, DOWNFALL_SCALE); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderNether.java b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderNether.java index 3f5b4bce2..56a39d6d8 100644 --- a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderNether.java +++ b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderNether.java @@ -24,9 +24,12 @@ public final class BiomeProviderNether extends BiomeProvider { private static final double DOWNFALL_SCALE = 0.05 / BIOME_STRETCH_FACTOR; private static final double NOISE_SCALE = 0.25F / BIOME_STRETCH_FACTOR; - private final FractalNoise2D temperatureNoise; - private final FractalNoise2D downfallNoise; - private final FractalNoise2D fuzzinessNoise; + private final ThreadLocal maps; + private final record Maps( + @NotNull FractalNoise2D temperatureNoise, + @NotNull FractalNoise2D downfallNoise, + @NotNull FractalNoise2D fuzzinessNoise + ) {} static { init(); @@ -34,13 +37,17 @@ public final class BiomeProviderNether extends BiomeProvider { public BiomeProviderNether(@NotNull World world) { super(world); - long seed = world.getRandomSeed(); - this.temperatureNoise = new FractalNoise3D<>(SimplexNoise.genOctaves(seed * 9871L, 4)); - this.downfallNoise = new FractalNoise3D<>(SimplexNoise.genOctaves(seed * 39811L, 4)); - this.fuzzinessNoise = new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 543321L, 4)); + final long seed = world.getRandomSeed(); + this.maps = ThreadLocal.withInitial(() -> new Maps( + new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 9871L, 4)), + new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 39811L, 4)), + new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 543321L, 4)) + )); } public Biome[] getBiomes(Biome[] biomes, double[] temperatures, double[] humidities, double[] varieties, int x, int y, int z, int xSize, int ySize, int zSize) { + final var maps = this.maps.get(); + if (biomes == null || biomes.length < xSize * ySize * zSize) { biomes = new Biome[xSize * ySize * zSize]; } @@ -48,19 +55,19 @@ public final class BiomeProviderNether extends BiomeProvider { if (temperatures == null || temperatures.length < xSize * zSize) { temperatures = new double[xSize * zSize]; } - this.temperatureNoise.setLacunarity(0.25).getRegion(temperatures, x, z, xSize, xSize, TEMP_SCALE, TEMP_SCALE); + maps.temperatureNoise.setLacunarity(0.25).getRegion(temperatures, x, z, xSize, xSize, TEMP_SCALE, TEMP_SCALE); if (humidities == null || humidities.length < xSize * zSize) { humidities = new double[xSize * zSize]; } - this.downfallNoise.setLacunarity(1.0 / 3.0).getRegion(humidities, x, z, xSize, xSize, DOWNFALL_SCALE, DOWNFALL_SCALE); + maps.downfallNoise.setLacunarity(1.0 / 3.0).getRegion(humidities, x, z, xSize, xSize, DOWNFALL_SCALE, DOWNFALL_SCALE); if (varieties == null || varieties.length < xSize * zSize) { varieties = new double[xSize * zSize]; } Arrays.fill(varieties, 0.0); - final double @NotNull [] noises = this.fuzzinessNoise.setLacunarity(10.0 / 17.0).getRegion(null, x, z, xSize, xSize, NOISE_SCALE, NOISE_SCALE); + final double @NotNull [] noises = maps.fuzzinessNoise.setLacunarity(10.0 / 17.0).getRegion(null, x, z, xSize, xSize, NOISE_SCALE, NOISE_SCALE); for (int xx = 0; xx < xSize; xx++) { for (int zz = 0; zz < zSize; zz++) { @@ -106,12 +113,14 @@ public final class BiomeProviderNether extends BiomeProvider { } public double[] getTemperatures(double[] temperatures, int x, int z, int xSize, int zSize) { + final var maps = this.maps.get(); + if (temperatures == null || temperatures.length < xSize * zSize) { temperatures = new double[xSize * zSize]; } - this.temperatureNoise.setLacunarity(0.25F).getRegion(temperatures, x, z, xSize, xSize, TEMP_SCALE, TEMP_SCALE); - double[] noises = this.fuzzinessNoise.setLacunarity(0.5882352941176471).getRegion(null, x, z, xSize, zSize, NOISE_SCALE, NOISE_SCALE); + maps.temperatureNoise.setLacunarity(0.25F).getRegion(temperatures, x, z, xSize, xSize, TEMP_SCALE, TEMP_SCALE); + double[] noises = maps.fuzzinessNoise.setLacunarity(0.5882352941176471).getRegion(null, x, z, xSize, zSize, NOISE_SCALE, NOISE_SCALE); int i = 0; for (int xx = 0; xx < xSize; ++xx) { @@ -131,7 +140,7 @@ public final class BiomeProviderNether extends BiomeProvider { if (humidities == null || humidities.length < xSize * zSize) { humidities = new double[xSize * zSize]; } - return this.downfallNoise.setLacunarity(0.5F).getRegion(humidities, x, z, xSize, zSize, DOWNFALL_SCALE, DOWNFALL_SCALE); + return this.maps.get().downfallNoise.setLacunarity(0.5F).getRegion(humidities, x, z, xSize, zSize, DOWNFALL_SCALE, DOWNFALL_SCALE); } public double[] getVarieties(double[] varieties, int x, int z, int xSize, int zSize) { diff --git a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderOverworld.java b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderOverworld.java index 1f0a50ced..14771abbb 100644 --- a/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderOverworld.java +++ b/game/core/src/main/java/net/minecraft/core/world/biome/provider/BiomeProviderOverworld.java @@ -19,10 +19,13 @@ public final class BiomeProviderOverworld private static final BiomeRangeMap brm = new BiomeRangeMap(); private static Biome[] biomes; - private final FractalNoise2D temperatureMap; - private final FractalNoise2D humidityMap; - private final FractalNoise2D varietyMap; - private final FractalNoise2D noiseMap; + private final ThreadLocal maps; + private final record Maps( + @NotNull FractalNoise2D temperatureMap, + @NotNull FractalNoise2D humidityMap, + @NotNull FractalNoise2D varietyMap, + @NotNull FractalNoise2D noiseMap + ) {} private double temperatureXScale = 0.0125; private double temperatureZScale = 0.0125; @@ -48,10 +51,12 @@ public final class BiomeProviderOverworld super(world); final long seed = world.getRandomSeed(); - this.temperatureMap = new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 9871, 4)); - this.humidityMap = new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 39811, 4)); - this.varietyMap = new FractalNoise2D<>(SimplexNoise.genOctaves(seed, 4)); - this.noiseMap = new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 543321, 2)); + this.maps = ThreadLocal.withInitial(() -> new Maps( + new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 9871, 4)), + new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 39811, 4)), + new FractalNoise2D<>(SimplexNoise.genOctaves(seed, 4)), + new FractalNoise2D<>(SimplexNoise.genOctaves(seed * 543321, 2)) + )); } public BiomeProviderOverworld withTemperatureScales(double xScale, double zScale, double lacunarity, double noise) @@ -128,13 +133,15 @@ public final class BiomeProviderOverworld @Override public double[] getTemperatures(double[] temperatures, int x, int z, int xSize, int zSize) { + final var maps = this.maps.get(); + if (temperatures == null || temperatures.length < xSize * zSize) { temperatures = new double[xSize * zSize]; } - double[] tnResult = temperatureMap.setLacunarity(this.temperatureLacunarity).getRegion(null, x, z, xSize, zSize, temperatureXScale, temperatureZScale); - double[] fnResult = noiseMap.setLacunarity(this.noiseLacunarity).getRegion(null, x, z, xSize, zSize, noiseXScale, noiseZScale); + double[] tnResult = maps.temperatureMap.setLacunarity(this.temperatureLacunarity).getRegion(null, x, z, xSize, zSize, temperatureXScale, temperatureZScale); + double[] fnResult = maps.noiseMap.setLacunarity(this.noiseLacunarity).getRegion(null, x, z, xSize, zSize, noiseXScale, noiseZScale); for (int dx = 0; dx < xSize; dx++) { @@ -165,13 +172,15 @@ public final class BiomeProviderOverworld @Override public double[] getHumidities(double[] humidities, int x, int z, int xSize, int zSize) { + final var maps = this.maps.get(); + if (humidities == null || humidities.length < xSize * zSize) { humidities = new double[xSize * zSize]; } - double[] hnResult = humidityMap.setLacunarity(this.humidityLacunarity).getRegion(null, x, z, xSize, zSize, humidityXScale, humidityZScale); - double[] fnResult = noiseMap.setLacunarity(this.noiseLacunarity).getRegion(null, x, z, xSize, zSize, noiseXScale, noiseZScale); + double[] hnResult = maps.humidityMap.setLacunarity(this.humidityLacunarity).getRegion(null, x, z, xSize, zSize, humidityXScale, humidityZScale); + double[] fnResult = maps.noiseMap.setLacunarity(this.noiseLacunarity).getRegion(null, x, z, xSize, zSize, noiseXScale, noiseZScale); for (int dx = 0; dx < xSize; dx++) { @@ -201,13 +210,15 @@ public final class BiomeProviderOverworld @Override public double[] getVarieties(double[] varieties, int x, int z, int xSize, int zSize) { + final var maps = this.maps.get(); + if (varieties == null || varieties.length < xSize * zSize) { varieties = new double[xSize * zSize]; } - double[] vnResult = varietyMap.setLacunarity(this.varietyLacunarity).getRegion(null, x, z, xSize, zSize, varietyXScale, varietyZScale); - double[] fnResult = noiseMap.setLacunarity(this.noiseLacunarity).getRegion(null, x, z, xSize, zSize, noiseXScale, noiseZScale); + double[] vnResult = maps.varietyMap.setLacunarity(this.varietyLacunarity).getRegion(null, x, z, xSize, zSize, varietyXScale, varietyZScale); + double[] fnResult = maps.noiseMap.setLacunarity(this.noiseLacunarity).getRegion(null, x, z, xSize, zSize, noiseXScale, noiseZScale); for (int dx = 0; dx < xSize; dx++) { 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 9b704aecc..4d1a3dd74 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 @@ -302,8 +302,7 @@ public abstract class WorldType time = 0.75f + ((cycleTick - dayTicks / 2f - nightTicks / 2f - nightTicks / 2f) / (dayTicks / 2f)) * 0.25f; } - while (time < 0.0f) time += 1.0f; - while (time >= 1.0f) time -= 1.0f; + if ((time %= 1) < 0) ++time; return time; } diff --git a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherManager.java b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherManager.java index a6f2a4100..5c74f5bd9 100644 --- a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherManager.java +++ b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherManager.java @@ -7,6 +7,7 @@ import net.minecraft.core.world.Dimension; import net.minecraft.core.world.World; import net.minecraft.core.world.save.DimensionData; import net.minecraft.core.world.season.Season; +import net.minecraft.core.world.type.WorldTypes; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -161,6 +162,15 @@ public class WeatherManager { this.weatherDuration = getRandomWeatherDuration(); } + // FIXME awful temporary hack, clean this up for 8.1 + if (this.world.getWorldType() == WorldTypes.OVERWORLD_WINTER) { + this.currentWeather = Weathers.OVERWORLD_WINTER_SNOW; + this.nextWeather = null; + this.weatherIntensity = 1.0F; + this.weatherDuration = 1; + this.weatherPower = 1.0F; + } + final @NotNull DimensionData dimensionData = this.world.getDimensionData(); dimensionData.setCurrentWeather(this.currentWeather); dimensionData.setNextWeather(this.nextWeather); diff --git a/game/core/src/main/resources/assets/minecraft/lang/en_US/options.lang b/game/core/src/main/resources/assets/minecraft/lang/en_US/options.lang index 6e960fba6..3174f951a 100644 --- a/game/core/src/main/resources/assets/minecraft/lang/en_US/options.lang +++ b/game/core/src/main/resources/assets/minecraft/lang/en_US/options.lang @@ -355,6 +355,14 @@ options.verticalSubtitleTextAlignment.top=Top options.verticalSubtitleTextAlignment.center=Center options.verticalSubtitleTextAlignment.bottom=Bottom +options.timerPrecision=Frame Timer Precision +options.timerPrecision.auto=Auto +options.timerPrecision.power_saving=Power Saving +options.timerPrecision.low_precision=Low Precision +options.timerPrecision.balanced=Balanced +options.timerPrecision.high_precision=High Precision +options.timerPrecision.max_precision=Max Precision + key.attack=Attack key.interact=Interact key.pickBlock=Pick Block diff --git a/game/core/src/main/resources/assets/minecraft/sounds/sounds.json b/game/core/src/main/resources/assets/minecraft/sounds/sounds.json index 8e9115c42..5c65211a3 100644 --- a/game/core/src/main/resources/assets/minecraft/sounds/sounds.json +++ b/game/core/src/main/resources/assets/minecraft/sounds/sounds.json @@ -894,7 +894,7 @@ ] }, "step.crystal": { - "subtitle": "subtitles.step.crystal", + "subtitle": "subtitles.tile.crystal", "sounds": [ "step/crystal_1.ogg", "step/crystal_2.ogg", 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 971a45f1e..1ef8e522f 100644 --- a/game/server/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/game/server/src/main/java/net/minecraft/server/MinecraftServer.java @@ -252,12 +252,15 @@ public class MinecraftServer EntityItem.enableItemClumping = propertyManager.getBooleanProperty("enable-item-clumping", true); UUIDHelper.urlUUID = propertyManager.getStringProperty("uuid-service", "https://api.minecraftservices.com/minecraft/profile/lookup/name/%s"); + // Assigning defaultGamemode before the registry access makes sure that the registry is actually + // populated by Gamemodes before trying to access its items + this.defaultGamemode = Gamemodes.SURVIVAL; String gamemodeProperty = propertyManager.getStringProperty("default-gamemode", "minecraft:gamemode/survival"); final @Nullable Gamemode gamemodeFromProperty = Registries.GAMEMODES.getItem(gamemodeProperty); if (gamemodeFromProperty == null) { LOGGER.warn("Unrecognised gamemode \"" + gamemodeProperty + "\"! Gamemodes must be in namespace ID format, e.g. \"minecraft:gamemode/survival\"."); } - this.defaultGamemode = Objects.requireNonNullElse(gamemodeFromProperty, Gamemodes.SURVIVAL); + if (gamemodeFromProperty != null) this.defaultGamemode = gamemodeFromProperty; if (defaultWorldType == null) { diff --git a/util/datagen/src/main/java/net/minecraft/datagen/SmeltingGenerator.java b/util/datagen/src/main/java/net/minecraft/datagen/SmeltingGenerator.java index 853bf1272..c309fd612 100644 --- a/util/datagen/src/main/java/net/minecraft/datagen/SmeltingGenerator.java +++ b/util/datagen/src/main/java/net/minecraft/datagen/SmeltingGenerator.java @@ -75,7 +75,7 @@ public class SmeltingGenerator { final Block toChild = Blocks.getBlock(variantMap.get(toParentId)); blastRecipe( - String.format("%s_to_%s", oreGroup, toChild.getKey()), + String.format("%s_to_%s", oreGroup.split(":")[1], toChild.namespaceId().value().split("/")[1]), toParent.getDefaultStack(), oreGroup, toChild.getDefaultStack() ); }