diff --git a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/sounds.json b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/sounds.json index 606273548..a667a01cd 100644 --- a/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/sounds.json +++ b/game/client/devPacks/inTestingSoundsPack/assets/minecraft/sounds/sounds.json @@ -166,7 +166,7 @@ }, { "name": "btamusic/underground/untitled.ogg", - "title": "Untitled Cave Song", + "title": "Karst", "author": "ShignBright", "stream": true } 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 26ab5ec5b..81f67a35c 100644 --- a/game/client/src/main/java/net/minecraft/client/Minecraft.java +++ b/game/client/src/main/java/net/minecraft/client/Minecraft.java @@ -2322,7 +2322,7 @@ public class Minecraft if (spawnCoordinates != null) { bedSpawnCoordinates = Player.getValidBedSpawnCoordinates(this.currentWorld, spawnCoordinates); if (bedSpawnCoordinates == null) { - this.thePlayer.sendTranslatedChatMessage("bed.notValid"); + this.thePlayer.sendTranslatedChatMessage("messages.bed.notValid"); } } } 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 4e3382389..bc100ff7b 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 @@ -45,6 +45,7 @@ import paulscode.sound.SoundSystem; import java.io.File; import java.io.IOException; import java.util.Collections; +import java.util.List; public abstract class OptionsPages { @@ -398,7 +399,7 @@ public abstract class OptionsPages { .withComponent(new ShortcutComponent("gui.options.page.debug.button.open.biome_finder", () -> { new Thread(() -> { try { - JavaProcess.exec(SeedViewerMain.class, Collections.emptyList()); + JavaProcess.exec(SeedViewerMain.class, List.of("-main", "false")); } catch (final IOException | InterruptedException e) { LogUtils.getLogger().error("", e); } diff --git a/game/client/src/main/java/net/minecraft/client/player/controller/PlayerController.java b/game/client/src/main/java/net/minecraft/client/player/controller/PlayerController.java index f3594f92a..0b94d52bb 100644 --- a/game/client/src/main/java/net/minecraft/client/player/controller/PlayerController.java +++ b/game/client/src/main/java/net/minecraft/client/player/controller/PlayerController.java @@ -102,6 +102,8 @@ public abstract class PlayerController { } final Block mineBlock = world.getBlockType(tilePos); + if (!mineBlock.canCollideCheck(world.getBlockData(tilePos), false)) return; + this.syncCurrentPlayItem(); final float mineStrength = mineBlock.getStrength(world, tilePos, side, player); diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java index 005acdcb5..e184b6351 100644 --- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java +++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java @@ -346,10 +346,10 @@ public final class BlockModelDispatcher addDispatch(new BlockModelGeneric<>(Blocks.ORE_DIAMOND_PERMAFROST, loadDataModel("minecraft:block/ore/diamond/permafrost"))); addDispatch(new BlockModelGeneric<>(Blocks.RUBYGLASS_COLUMN, loadDataModel("minecraft:block/rubyglass/column"))); - addDispatch(new BlockModelGeneric<>(Blocks.RUBYGLASS_NODE, loadDataModel("minecraft:block/rubyglass/node")).forceCullSelf(true)); + addDispatch(new BlockModelGeneric<>(Blocks.RUBYGLASS_NODE, loadDataModel("minecraft:block/rubyglass/node"))); addDispatch(new BlockModelGeneric<>(Blocks.BRICK_RUBYGLASS, loadDataModel("minecraft:block/rubyglass/brick"))); - addDispatch(new BlockModelGeneric<>(Blocks.BLOCK_RUBYGLASS, loadDataModel("minecraft:block/rubyglass/block")).forceCullSelf(true)); - addDispatch(new BlockModelConduit<>(Blocks.CONDUIT).forceCullSelf(true)); + addDispatch(new BlockModelGeneric<>(Blocks.BLOCK_RUBYGLASS, loadDataModel("minecraft:block/rubyglass/block"))); + addDispatch(new BlockModelConduit<>(Blocks.CONDUIT)); addDispatch(new BlockModelGenericRubyglassCrystal<>(Blocks.RUBYGLASS_CRYSTAL, loadDataModel("minecraft:block/rubyglass/crystal/0")).forceCullSelf(true)); addDispatch(new BlockModelGenericRubyglassGrowth<>(Blocks.RUBYGLASS_GROWTH)); diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericFurnace.java b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericFurnace.java index 56031bde0..07a71fb6b 100644 --- a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericFurnace.java +++ b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericFurnace.java @@ -6,6 +6,7 @@ import net.minecraft.client.render.texture.stitcher.IconCoordinate; import net.minecraft.core.block.Block; import net.minecraft.core.block.BlockLogic; import net.minecraft.core.block.BlockLogicRotatable; +import net.minecraft.core.block.entity.TileEntityFurnace; import net.minecraft.core.block.entity.TileEntityFurnaceBlast; import net.minecraft.core.player.inventory.container.Container; import net.minecraft.core.util.helper.Direction; @@ -54,9 +55,9 @@ public class BlockModelGenericFurnace extends BlockModelGe if (source.getTileEntity(tilePosc) instanceof Container container) { boolean hasOutput; if (container instanceof TileEntityFurnaceBlast) { - hasOutput = container.getItem(3) != null; + hasOutput = container.getItem(TileEntityFurnaceBlast.SLOT_RESULT) != null; } else { - hasOutput = container.getItem(2) != null; + hasOutput = container.getItem(TileEntityFurnace.SLOT_RESULT) != null; } if (hasOutput) { return this.filled; diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericRubyglassCrystal.java b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericRubyglassCrystal.java index 0a5e7a394..efe02e10b 100644 --- a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericRubyglassCrystal.java +++ b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericRubyglassCrystal.java @@ -3,12 +3,13 @@ package net.minecraft.client.render.block.model.generic; import net.minecraft.client.render.block.model.BlockModelDispatcher; import net.minecraft.core.block.Block; import net.minecraft.core.block.BlockLogic; +import net.minecraft.core.block.BlockLogicRubyglassCrystal; import org.jetbrains.annotations.NotNull; import org.useless.dragonfly.data.block.BlockModelData; import org.useless.dragonfly.models.block.StaticBlockModel; public class BlockModelGenericRubyglassCrystal extends BlockModelGeneric { - public final StaticBlockModel[] models = new StaticBlockModel[4]; + public final StaticBlockModel[] models = new StaticBlockModel[BlockLogicRubyglassCrystal.BREAK_STAGES + 1]; public BlockModelGenericRubyglassCrystal(@NotNull Block block, @NotNull StaticBlockModel staticModel) { super(block, staticModel); diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererSheep.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererSheep.java index 67054d433..b44444a7a 100644 --- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererSheep.java +++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererSheep.java @@ -95,8 +95,8 @@ public class MobRendererSheep extends MobRenderer { else { // normal head rotations - head.rotX = headPitch * MathHelper.DEG_TO_RAD; - head.rotY = headYaw * MathHelper.DEG_TO_RAD; + head.rotX = headPitch; + head.rotY = headYaw; } return model; diff --git a/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererJarButterfly.java b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererJarButterfly.java index 0b5f21272..789078fc5 100644 --- a/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererJarButterfly.java +++ b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererJarButterfly.java @@ -11,8 +11,15 @@ public class TileEntityRendererJarButterfly extends TileEntityRenderer bBlock = world.getBlockType(thatPos); + /** + * Metadata compared by the matcher. Override to ignore orientation while keeping visual state (e.g. powered). + */ + protected int getMatcherEquivalenceData(final int data) { + return data; + } + + /** + * Whether another block counts as the same type for matcher comparison (e.g. on/off variants). + */ + protected boolean isSameBlockForMatcher(final @NotNull Block other) { + return this.block == other; + } + + public record MatcherSnapshot(@NotNull Block block, int meta, @NotNull BlockLogic logic) {} - final int thisMeta = world.getBlockData(thisPos); - final int otherMeta = world.getBlockData(thatPos); + /** + * Resolves the block/meta/logic at this position for matcher comparison. + *

+ * The default implementation returns the block actually stored in the world. Blocks + * that visually stand in for another block (e.g. the moving piston, which carries + * its real contents in the tile entity) should override this to delegate to that block. + */ + public @NotNull MatcherSnapshot resolveForMatcher(final @NotNull World world, final @NotNull TilePosc tilePos) { + final @NotNull Block block = world.getBlockType(tilePos); + return new MatcherSnapshot(block, world.getBlockData(tilePos), block.getLogic()); + } - return this.block == bBlock && thisMeta == otherMeta; + public static @NotNull MatcherSnapshot resolveMatcherBlock(final @NotNull World world, final @NotNull TilePosc tilePos) { + return world.getBlockType(tilePos).getLogic().resolveForMatcher(world, tilePos); + } + + public static boolean areBlocksEquivalentForMatcher( + final @NotNull World world, + final @NotNull TilePosc posA, + final @NotNull TilePosc posB + ) { + final @NotNull MatcherSnapshot a = resolveMatcherBlock(world, posA); + final @NotNull MatcherSnapshot b = resolveMatcherBlock(world, posB); + if (!a.logic().isSameBlockForMatcher(b.block()) || !b.logic().isSameBlockForMatcher(a.block())) { + return false; + } + return a.logic().getMatcherEquivalenceData(a.meta()) == b.logic().getMatcherEquivalenceData(b.meta()); + } + + @Override + public boolean isEquivalent(final @NotNull World world, final @NotNull TilePosc thisPos, final @NotNull TilePosc thatPos) { + return areBlocksEquivalentForMatcher(world, thisPos, thatPos); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicActivator.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicActivator.java index 6f3aead64..226d3e3a2 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicActivator.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicActivator.java @@ -27,6 +27,11 @@ public class BlockLogicActivator extends BlockLogicVeryRotatable { public static final int MASK_POWERED = 0b0000_1000; + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & MASK_POWERED; + } + public BlockLogicActivator(final @NotNull Block block) { super(block, Materials.NETHERRACK); block.withEntity(TileEntityActivator::new); diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicAxisAligned.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicAxisAligned.java index 1f78a5629..6c4214482 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicAxisAligned.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicAxisAligned.java @@ -17,6 +17,11 @@ public class BlockLogicAxisAligned super(block, material); } + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & ~MASK_DIRECTION; + } + @Override public void onPlacedByMob(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side, final @NotNull Mob mob, final double xHit, final double yHit) { final @NotNull Axis axis = mob.getPlacementDirection(side, PlacementMode.SIDE).axis(); diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBed.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBed.java index 90017d1ce..d29c1ef19 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBed.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBed.java @@ -32,6 +32,11 @@ public class BlockLogicBed this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.5625F, 1.0F); } + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & ~DIRECTION.mask; + } + @Override public boolean onInteracted(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Player player, final @Nullable Side side, final double xHit, final double yHit) { if (world.isClientSide) { diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicButton.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicButton.java index b8add79b1..63d149c3f 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicButton.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicButton.java @@ -41,6 +41,11 @@ public class BlockLogicButton block.setTicking(true); } + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & MASK_POWERED; + } + @Override public @Nullable AABBdc getCollisionAABB(final @NotNull WorldSource source, final @NotNull TilePosc tilePos) { return null; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicChest.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicChest.java index 9fadd0ef0..f5c36f7a2 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicChest.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicChest.java @@ -25,6 +25,11 @@ public class BlockLogicChest block.withEntity(TileEntityChest::new); } + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & typeBits; + } + @Override public void onPlacedByMob(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side, final @NotNull Mob mob, final double xHit, final double yHit) { @NotNull Direction direction = mob.getHorizontalPlacementDirection(side).opposite(); diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicConduit.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicConduit.java index 38fa673b5..0909fb927 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicConduit.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicConduit.java @@ -77,12 +77,12 @@ public class BlockLogicConduit extends BlockLogic { @Override public boolean isSolidRender() { - return false; + return true; // Setting to true. False allows redstone towering, true makes it handle culling properly. It is a full solid block so ideally is set to true, really redstone shouldn't depend on these at all though -Useless } @Override public boolean isCubeShaped() { - return false; + return false; // False makes it not able to be hard powered } @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..55e368fea 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 @@ -27,6 +27,11 @@ import org.joml.Vector3dc; public class BlockLogicDispenser extends BlockLogicVeryRotatable { public static final int MASK_POWERED = 0b0000_1000; + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & MASK_POWERED; + } + public BlockLogicDispenser(final @NotNull Block block) { super(block, Materials.STONE); block.withEntity(TileEntityDispenser::new); diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDoor.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDoor.java index 86a67a49d..e07c01202 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDoor.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDoor.java @@ -52,6 +52,19 @@ public class BlockLogicDoor } } + @Override + protected boolean isSameBlockForMatcher(final @NotNull Block other) { + if (!(other.getLogic() instanceof BlockLogicDoor otherDoor)) { + return false; + } + return otherDoor.isTop == this.isTop; + } + + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & ~(MASK_ROTATION); + } + @Override public void onPlacedOnSide(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side, final double xHit, final double yHit) { final int meta = world.getBlockData(tilePos); diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceGate.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceGate.java index b803851d5..6a6f1d6de 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceGate.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceGate.java @@ -32,6 +32,11 @@ public class BlockLogicFenceGate super(block, Materials.WOOD); } + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & ~MASK_DIRECTION; + } + @Override public @Nullable AABBdc getCollisionAABB(final @NotNull WorldSource source, final @NotNull TilePosc tilePos) { final int metadata = source.getBlockData(tilePos); diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFullyRotatable.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFullyRotatable.java index 2313016d4..b80fefd85 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFullyRotatable.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFullyRotatable.java @@ -14,6 +14,11 @@ public class BlockLogicFullyRotatable extends BlockLogic { super(block, material); } + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & ~MASK_DIRECTION; + } + @Override public void onPlacedByMob(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Side side, @NotNull Mob mob, double xHit, double yHit) { final Direction direction = mob.getPlacementDirection(side).opposite(); diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLadder.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLadder.java index 3d43989b9..fb83841cb 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLadder.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLadder.java @@ -22,6 +22,11 @@ public class BlockLogicLadder extends BlockLogic implements ISupportable { super(block, Materials.WOOD); } + @Override + protected int getMatcherEquivalenceData(final int data) { + return 0; + } + @Override public boolean isSolidRender() { return false; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLamp.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLamp.java index 73b63fd20..a0286ec70 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLamp.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLamp.java @@ -173,13 +173,12 @@ public class BlockLogicLamp extends BlockLogic implements IPainted { } @Override - public boolean isEquivalent(final @NotNull World world, final @NotNull TilePosc thisPos, final @NotNull TilePosc tilePos) { - Block block = world.getBlockType(tilePos); - - if (block.getLogic() instanceof BlockLogicLamp logicOfLamp) { - return this.isActive == logicOfLamp.isActive; - } + protected boolean isSameBlockForMatcher(final @NotNull Block other) { + return other.getLogic() instanceof BlockLogicLamp; + } - return false; + @Override + protected int getMatcherEquivalenceData(final int data) { + return (this.isActive ? 1 : 0) | (data & 0x0F); } } \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLever.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLever.java index b14ad73dd..e029e54be 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLever.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLever.java @@ -39,6 +39,11 @@ public class BlockLogicLever extends BlockLogic implements ISupportable { super(block, Materials.DECORATION); } + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & MASK_POWERED; + } + @Override public @Nullable AABBdc getCollisionAABB(@NotNull WorldSource source, @NotNull TilePosc tilePos) { return null; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMatcher.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMatcher.java index 389110c9a..8c0b4510f 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMatcher.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMatcher.java @@ -4,6 +4,7 @@ import net.minecraft.core.block.entity.TileEntity; import net.minecraft.core.block.material.Materials; import net.minecraft.core.block.piston.IMovingBlock; import net.minecraft.core.block.piston.MovingLine; +import net.minecraft.core.block.piston.TileEntityMovingPistonBlock; import net.minecraft.core.entity.Mob; import net.minecraft.core.enums.EnumDropCause; import net.minecraft.core.enums.PlacementMode; @@ -32,6 +33,16 @@ public class BlockLogicMatcher extends BlockLogicAxisAligned { this.isActive = isActive; } + @Override + protected boolean isSameBlockForMatcher(final @NotNull Block other) { + return other.getLogic() instanceof BlockLogicMatcher; + } + + @Override + protected int getMatcherEquivalenceData(final int data) { + return this.isActive ? 1 : 0; + } + @Override public int tickDelay() { return 4; @@ -65,12 +76,40 @@ public class BlockLogicMatcher extends BlockLogicAxisAligned { @Override public void onNeighborChanged(@NotNull World world, @NotNull TilePosc tilePos, final @NotNull Block block) { + this.scheduleUpdate(world, tilePos); + } + + private void scheduleUpdate(@NotNull World world, @NotNull TilePosc tilePos) { world.scheduleBlockUpdate(tilePos, this.block, tickDelay()); + if (this.hasMovingPistonNeighbor(world, tilePos)) { + world.scheduleBlockUpdate(tilePos, this.block, TileEntityMovingPistonBlock.TICKS_TO_EXTEND + tickDelay()); + } + } + + private boolean hasMovingPistonNeighbor(@NotNull World world, @NotNull TilePosc tilePos) { + final Axis axis = BlockLogicAxisAligned.metaToAxis(world.getBlockData(tilePos) & BlockLogicAxisAligned.MASK_DIRECTION); + final TilePos front = new TilePos(tilePos); + final TilePos back = new TilePos(tilePos); + switch (axis) { + case X -> { + front.x += 1; + back.x -= 1; + } + case Y -> { + front.y += 1; + back.y -= 1; + } + default -> { + front.z += 1; + back.z -= 1; + } + } + return world.getBlockType(front) == Blocks.PISTON_MOVING || world.getBlockType(back) == Blocks.PISTON_MOVING; } @Override public void onMoved(@NotNull World world, @NotNull TilePosc sourcePos, @NotNull TilePosc targetPos, @NotNull IMovingBlock block, int indexInLine, @NotNull MovingLine line) { - world.scheduleBlockUpdate(targetPos, this.block, tickDelay()); + this.scheduleUpdate(world, targetPos); } public void updateState(@NotNull World world, @NotNull TilePosc tilePos) { @@ -95,9 +134,8 @@ public class BlockLogicMatcher extends BlockLogicAxisAligned { } - boolean backMatchesFront; - Block fBlock = world.getBlockType(front); - backMatchesFront = fBlock.isEquivalent(world, front, back); + final @Nullable Block frontBlock = world.getBlockType(front); + final boolean backMatchesFront = frontBlock.isEquivalent(world, front, back); if (!this.isActive && backMatchesFront) { world.setBlockTypeDataNotify(tilePos, Blocks.MATCHER_ACTIVE, world.getBlockData(tilePos)); diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicNote.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicNote.java index d889de532..44aa5147c 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicNote.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicNote.java @@ -25,6 +25,11 @@ public class BlockLogicNote extends BlockLogic { public static final int MASK_NOTE = 0b0011_1111; public static final int MASK_POWERED = 0b1000_0000; + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & MASK_POWERED; + } + public static final byte MAX_NOTE = 24; public BlockLogicNote(@NotNull Block block) { diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPortal.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPortal.java index de4c866ce..c4e030e52 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPortal.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPortal.java @@ -40,6 +40,11 @@ public class BlockLogicPortal extends BlockLogicTransparent implements IPainted public final @NotNull Block portalFrame; public final @NotNull Block portalTrigger; + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & ~MASK_ROTATION; + } + public BlockLogicPortal(@NotNull Block block, @NotNull Dimension targetDimension, @NotNull Block portalMaterial, @NotNull Block portalTrigger) { super(block, Materials.PORTAL); this.targetDimension = targetDimension; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPressurePlate.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPressurePlate.java index e0725cb98..ddf3577e6 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPressurePlate.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPressurePlate.java @@ -24,6 +24,11 @@ import java.util.Random; public class BlockLogicPressurePlate extends BlockLogic implements IPaintable, ISupportable { public static final int MASK_POWERED = 0b0000_0001; + + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & MASK_POWERED; + } public static final int MASK_SIDE = 0b0000_1110; private final @NotNull Class triggerMobClass; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRail.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRail.java index 09d99f924..cca4f6fe7 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRail.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRail.java @@ -38,6 +38,14 @@ public class BlockLogicRail extends BlockLogic implements ISupportable { setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F); } + @Override + protected int getMatcherEquivalenceData(final int data) { + if (this.isPowered) { + return data & MASK_POWERED; + } + return data; + } + public @NotNull RailDirection getRailDirection(@NotNull WorldSource world, @NotNull TilePosc tilePos) { int meta = world.getBlockData(tilePos); if (this.isPowered) { diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRepeater.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRepeater.java index 1f8b0e775..caf9c3020 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRepeater.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRepeater.java @@ -45,6 +45,16 @@ public class BlockLogicRepeater extends BlockLogic implements ISupportable { setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F); } + @Override + protected boolean isSameBlockForMatcher(final @NotNull Block other) { + return other.getLogic() instanceof BlockLogicRepeater; + } + + @Override + protected int getMatcherEquivalenceData(final int data) { + return (this.isRepeaterPowered ? 0x10 : 0) | (data & MASK_TICK_DELAY); + } + @Override public boolean isCubeShaped() { return false; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRotatable.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRotatable.java index df176e776..8e8075dc0 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRotatable.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRotatable.java @@ -16,6 +16,11 @@ public abstract class BlockLogicRotatable extends BlockLogic { super(block, material); } + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & ~MASK_DIRECTION; + } + public static @NotNull Direction getDirectionFromMeta(int meta) { return Direction.fromId(meta & MASK_DIRECTION); } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassCrystal.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassCrystal.java index 514fced4c..4ce22dac6 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassCrystal.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassCrystal.java @@ -21,6 +21,7 @@ import org.joml.primitives.AABBdc; import java.util.Random; public class BlockLogicRubyglassCrystal extends BlockLogicTransparent { + public static final int BREAK_STAGES = 3; private final @NotNull AABBd checkAABB = new AABBd(); public BlockLogicRubyglassCrystal(@NotNull Block block) { super(block, Materials.ICE); @@ -73,7 +74,7 @@ public class BlockLogicRubyglassCrystal extends BlockLogicTransparent { int data = world.getBlockData(tilePos); if (!standing.isEmpty()) { int nextData = data + 1; - if (nextData >= 3) { + if (nextData > BREAK_STAGES) { world.playBlockEvent(null, tilePos, LevelListener.EVENT_BLOCK_BREAK, block.id()); world.setBlockTypeNotify(tilePos, Blocks.AIR); } else { diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSign.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSign.java index dc87952e5..6b4afe098 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSign.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSign.java @@ -40,6 +40,19 @@ public class BlockLogicSign extends BlockLogic implements IPaintable { block.withEntity(TileEntitySign::new); } + @Override + protected boolean isSameBlockForMatcher(final @NotNull Block other) { + if (!(other.getLogic() instanceof BlockLogicSign otherSign)) { + return false; + } + return otherSign.isFreeStanding == this.isFreeStanding; + } + + @Override + protected int getMatcherEquivalenceData(final int data) { + return 0; + } + @Override public @Nullable AABBdc getCollisionAABB(@NotNull WorldSource source, @NotNull TilePosc tilePos) { return null; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSpikes.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSpikes.java index 10f062f76..f9b83120b 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSpikes.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSpikes.java @@ -38,6 +38,11 @@ public class BlockLogicSpikes extends BlockLogic this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, thickness, 1.0F); } + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & MASK_POWERED; + } + @Override public void onPlacedByMob(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side sidePlacedOnto, final @NotNull Mob mob, final double xHit, final double yHit) { if (world.isClientSide) { diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStairs.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStairs.java index e0294b7a3..9d86f24b0 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStairs.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStairs.java @@ -27,6 +27,11 @@ import org.joml.primitives.AABBd; import org.joml.primitives.AABBdc; public class BlockLogicStairs extends BlockLogic { + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & ~MASK_ROTATION_HORIZONTAL; + } + // private static final Map selectionVolumes = new HashMap<>(); // // static diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicThermalVent.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicThermalVent.java index c04ab6df9..eb4e1250f 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicThermalVent.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicThermalVent.java @@ -57,6 +57,11 @@ public class BlockLogicThermalVent extends BlockLogic { return Block.hasLogicClass(world.getBlockType(tilePos.down(new TilePos())), BlockLogicThermalVent.class); } + @Override + public boolean isEquivalent(final @NotNull World world, final @NotNull TilePosc thisPos, final @NotNull TilePosc thatPos) { + return Block.hasLogicClass(world.getBlockType(thatPos), BlockLogicThermalVent.class); + } + @Override public void onNeighborChanged(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Block block) { if (!hasVentBelow(world, tilePos) && getVentState(world.getBlockData(tilePos)) != DORMANT_STATE) { diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTimer.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTimer.java index 21648dc61..068ddbb61 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTimer.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTimer.java @@ -49,6 +49,11 @@ public class BlockLogicTimer extends BlockLogic implements ISupportable { public static final int MASK_TICK_DELAY = 0b0000_1100; + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & (MASK_TICK_DELAY | ~MASK_DIRECTION); + } + public BlockLogicTimer(@NotNull Block block) { super(block, Materials.DECORATION); setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F); diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorch.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorch.java index 41b10f73c..2b7a5f1b5 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorch.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorch.java @@ -34,6 +34,11 @@ public class BlockLogicTorch extends BlockLogic implements ISupportable { block.setTicking(true); } + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & ~MASK_DIRECTION; + } + @Override public @Nullable AABBdc getCollisionAABB(@NotNull WorldSource source, @NotNull TilePosc tilePos) { return null; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorchRedstone.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorchRedstone.java index 895b17f39..9c14af673 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorchRedstone.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorchRedstone.java @@ -19,7 +19,16 @@ public class BlockLogicTorchRedstone extends BlockLogicTorch { public BlockLogicTorchRedstone(@NotNull Block block, boolean isActive) { super(block); this.torchActive = isActive; - block.setTicking(true); + } + + @Override + protected boolean isSameBlockForMatcher(final @NotNull Block other) { + return other.getLogic() instanceof BlockLogicTorchRedstone; + } + + @Override + protected int getMatcherEquivalenceData(final int data) { + return this.torchActive ? 1 : 0; } @Override @@ -32,6 +41,7 @@ public class BlockLogicTorchRedstone extends BlockLogicTorch { if (world.getBlockData(tilePos) == SIDE_NONE) { super.onPlacedByWorld(world, tilePos); } + world.scheduleBlockUpdate(tilePos, this.block, tickDelay()); world.notifyShellBlocksInRadiusOfNeighborChange(2, tilePos, this.block); } @@ -70,8 +80,6 @@ public class BlockLogicTorchRedstone extends BlockLogicTorch { @Override public void updateTick(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Random rand, boolean isRandomTick) { - if (isRandomTick) return; - boolean isPowered = hasNeighborSignal(world, tilePos); if (this.torchActive) { if (isPowered) { diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoor.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoor.java index 0855f0212..eb0b6a71b 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoor.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoor.java @@ -43,6 +43,11 @@ public class BlockLogicTrapDoor extends BlockLogic implements IPaintable { setBlockBounds(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, f1, 0.5F + f); } + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & ~(MASK_DIRECTION | MASK_UPPER_HALF); + } + @Override public void onPlacedOnSide(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Side side, double xHit, double yHit) { int meta = world.getBlockData(tilePos); diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicVeryRotatable.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicVeryRotatable.java index ef39e7d8e..0bfd57ee8 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicVeryRotatable.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicVeryRotatable.java @@ -16,6 +16,11 @@ public abstract class BlockLogicVeryRotatable super(block, material); } + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & ~MASK_DIRECTION; + } + @Override public void onPlacedByMob(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side, final @NotNull Mob mob, final double xHit, final double yHit) { final @NotNull Direction direction = mob.getPlacementDirection(side).opposite(); diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnace.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnace.java index 006d87b58..d000affae 100644 --- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnace.java +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnace.java @@ -370,10 +370,10 @@ public class TileEntityFurnace extends TileEntity @Override public Packet getDescriptionPacket() { - if (furnaceItemStacks[SLOT_RESULT] != null) { +// if (furnaceItemStacks[SLOT_RESULT] != null) { // Making this always send, furnaces aren't super big and this fixes the filled status not being synched in mp -Useless return new PacketTileEntityData(this); - } - return null; +// } +// return null; } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnaceBlast.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnaceBlast.java index 61cfb1c7b..87b75ad4a 100644 --- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnaceBlast.java +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnaceBlast.java @@ -328,10 +328,10 @@ public class TileEntityFurnaceBlast extends TileEntity @Override public Packet getDescriptionPacket() { - if (this.inventory[SLOT_RESULT] != null) { +// if (this.inventory[SLOT_RESULT] != null) { // Making this always send, blast furnaces aren't super big and this fixes the filled status not being synched in mp -Useless return new PacketTileEntityData(this); - } - return null; +// } +// return null; } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java index 0b818cb64..931f38e8d 100644 --- a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java +++ b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java @@ -63,6 +63,16 @@ public class BlockLogicPistonBase extends BlockLogic { this.flingStrength = flingStrength; } + @Override + protected boolean isSameBlockForMatcher(final @NotNull Block other) { + return other.getLogic() instanceof BlockLogicPistonBase otherBase && otherBase.typeId == this.typeId; + } + + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & ~DIRECTION.mask; + } + // Piston updates: // ================= @@ -414,7 +424,7 @@ public class BlockLogicPistonBase extends BlockLogic { } private void retract(@NotNull World world, @NotNull TilePosc basePos, int data, int lineInfo) { - data = validateBaseData(data, this); + final int rData = IS_EXTENDED.set(validateBaseData(data, this), 0); final var dir = Direction.fromId(DIRECTION.get(data)); final TilePos query1 = new TilePos(), query2 = new TilePos(); @@ -429,10 +439,9 @@ public class BlockLogicPistonBase extends BlockLogic { } world.setBlockTypeRaw(headPos, Blocks.AIR); world.removeTileEntity(headPos); - final var moving = new TileEntityMovingPistonBlock( MovingType.RETRACTING_PISTON, - this.block, dir.id, null, dir); + this.block, rData, null, dir); world.setBlockTypeRaw(basePos, Blocks.AIR); world.setBlockTypeDataEntity(basePos, Blocks.PISTON_MOVING, data, moving); @@ -588,10 +597,10 @@ public class BlockLogicPistonBase extends BlockLogic { static final ItemStack[] buf = new ItemStack[1]; } - data = validateBaseData(data, this); - data = DIRECTION.set(data, 0) & IS_EXTENDED.set(data, 0); +// data = validateBaseData(data, this); +// data = DIRECTION.set(data, 0) & IS_EXTENDED.set(data, 0); - ctx.buf[0] = new ItemStack(this.block, 1, data); + ctx.buf[0] = new ItemStack(this.block, 1, /*data*/0); // Setting the item to just have metadata 0, the item doesn't really need to know the blocks metadata to work and it just complicates recipe logic when the metadata is there -Useless return ctx.buf; } diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java index cb836acbe..e16017c0c 100644 --- a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java +++ b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java @@ -46,6 +46,11 @@ public class BlockLogicPistonHead extends BlockLogic implements ICarrySource { this.shaftThickness = shaftThickness; } + @Override + protected int getMatcherEquivalenceData(final int data) { + return data & ~DIRECTION.mask; + } + @Override public boolean isSolidRender() { return false; diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonMoving.java b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonMoving.java index e8f2f9aba..63372dce4 100644 --- a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonMoving.java +++ b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonMoving.java @@ -133,6 +133,15 @@ public class BlockLogicPistonMoving extends BlockLogic { : super.getBoundsFromState(source, tilePos); } + @Override + public @NotNull MatcherSnapshot resolveForMatcher(@NotNull World world, @NotNull TilePosc tilePos) { + if (world.getTileEntity(tilePos) instanceof TileEntityMovingPistonBlock moving) { + final Block block = moving.movingBlock(); + return new MatcherSnapshot(block, moving.movingBlockData(), block.getLogic()); + } + return super.resolveForMatcher(world, tilePos); + } + @Override public int getPistonPushReaction(@NotNull World world, @NotNull TilePosc tilePos) { return Material.PISTON_CANT_PUSH; diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/MovingLine.java b/game/core/src/main/java/net/minecraft/core/block/piston/MovingLine.java index fdb808614..d97eda610 100644 --- a/game/core/src/main/java/net/minecraft/core/block/piston/MovingLine.java +++ b/game/core/src/main/java/net/minecraft/core/block/piston/MovingLine.java @@ -119,8 +119,17 @@ public final class MovingLine { if (!this.isExtending) world.markBlockDirty(query); for (int i = 0; i < len; i++, query.add(this.direction)) { - world.setBlockTypeDataEntity(query, Blocks.PISTON_MOVING, this.data[i], this.createMoving(i)); + world.setBlockTypeDataEntity(query, Blocks.PISTON_MOVING, Byte.toUnsignedInt(this.data[i]), this.createMoving(i)); } + + if (!this.isExtending) this.notifyLineEndNeighbors(query); + } + + private void notifyLineEndNeighbors(@NotNull TilePos query) { + world.notifyBlocksOfNeighborChange(this.origin, null); + query.set(this.origin); + this.direction.offsetScaled(query, this.len); + world.notifyBlocksOfNeighborChange(query, null); } void notify(@NotNull TilePos query1, @NotNull TilePos query2) { @@ -170,7 +179,7 @@ public final class MovingLine { if (world.hasDirectSignal(queryPos.set(tilePos).add(d2), d2.side())) return true; } if (block == Blocks.PUMPKIN_REDSTONE) { - final var pumpkinDir = Direction.fromId(this.data[index]); + final var pumpkinDir = Direction.fromId(Byte.toUnsignedInt(this.data[index])); if (pumpkinDir != d1 && world.hasDirectSignal(queryPos.set(tilePos).add(d1), d1.side())) return true; if (pumpkinDir != d2 && world.hasDirectSignal(queryPos.set(tilePos).add(d2), d2.side())) return true; } @@ -281,6 +290,6 @@ public final class MovingLine { assert index >= 0 && index < this.len; return this.movingBlocks[index] = new TileEntityMovingPistonBlock( (this.isExtending) ? MovingType.EXTENDING : MovingType.RETRACTING, - this.blocks[index], this.data[index], this.entities[index], this.direction); + this.blocks[index], Byte.toUnsignedInt(this.data[index]), this.entities[index], this.direction); } } 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 3e1a09e98..41355d1ae 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 @@ -151,6 +151,10 @@ public class EntityItem extends Entity } } + @Override + public void waterHurt() { + } + @Override public boolean hurt(Entity entity, int i, DamageType type) { diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemBoat.java b/game/core/src/main/java/net/minecraft/core/item/ItemBoat.java index 0d0fcfcc6..05821f209 100644 --- a/game/core/src/main/java/net/minecraft/core/item/ItemBoat.java +++ b/game/core/src/main/java/net/minecraft/core/item/ItemBoat.java @@ -5,7 +5,7 @@ import net.minecraft.core.entity.vehicle.EntityBoat; import net.minecraft.core.entity.player.Player; import net.minecraft.core.block.Blocks; import net.minecraft.core.util.helper.Direction; -import net.minecraft.core.util.phys.HitResult; +import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.World; import net.minecraft.core.world.pos.TilePos; import net.minecraft.core.world.pos.TilePosc; @@ -22,24 +22,25 @@ public class ItemBoat extends Item { } @Override - public @Nullable ItemStack onUse(@NotNull ItemStack selfStack, @NotNull World world, @NotNull Player player) { - HitResult rayCast = player.rayCast(player.getGamemode().getBlockReachDistance(), 1f, true, false, false); - if (rayCast == null) { - return selfStack; - } - if (rayCast instanceof HitResult.Tile hitTile) { - TilePos pos = new TilePos(hitTile.tilePos); - if (!world.isClientSide) { - if (world.getBlockType(pos) == Blocks.LAYER_SNOW) { - pos.y--; - } - EntityBoat boat = new EntityBoat(world, pos.x + 0.5F, pos.y + 1.0F, pos.z + 0.5F); + public boolean interactsWithFluid(@NotNull ItemStack selfStack) { + return true; + } + + @Override + public boolean onUseOnBlock(@NotNull ItemStack selfStack, @NotNull World world, @Nullable Player player, @NotNull TilePosc blockPos, @NotNull Side side, double xHit, double yHit) { + TilePos pos = new TilePos(blockPos); + if (!world.isClientSide) { + if (world.getBlockType(pos) == Blocks.LAYER_SNOW) { + pos.y--; + } + EntityBoat boat = new EntityBoat(world, pos.x + 0.5F, pos.y + 1.0F, pos.z + 0.5F); + if (player != null) { boat.setRot(player.yRot - 90, 0); - world.entityJoinedWorld(boat); } - selfStack.consumeItem(player); + world.entityJoinedWorld(boat); } - return selfStack; + selfStack.consumeItem(player); + return true; } @Override diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java b/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java index 3dbc3b892..5ed5c8f78 100644 --- a/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java +++ b/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java @@ -17,12 +17,11 @@ import net.minecraft.core.util.HardIllegalArgumentException; import net.minecraft.core.util.collection.NamespaceID; import net.minecraft.core.util.helper.Direction; import net.minecraft.core.util.helper.Side; -import net.minecraft.core.util.phys.HitResult; import net.minecraft.core.world.LevelListener; import net.minecraft.core.world.World; -import net.minecraft.core.world.type.tag.WorldTypeTags; import net.minecraft.core.world.pos.TilePos; import net.minecraft.core.world.pos.TilePosc; +import net.minecraft.core.world.type.tag.WorldTypeTags; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.primitives.AABBd; @@ -275,10 +274,13 @@ public abstract class ItemBucket extends ItemFood implements IItemContainer { if (currentState.isEdible() && !currentState.canPlace()) return false; - final int oldSize = selfStack.stackSize; - @Nullable ItemStack newStack; + final @NotNull UseResult result; + + interface ctx { @NotNull UseResult result = new UseResult(); } + interact: synchronized(ctx.result) { + ctx.result.used = false; + ctx.result.itemStack = null; - interact: { if (world.getBlockData(tilePos) == 0) { final NamespaceID targetStateId = getFluidStateAt(world, tilePos); @@ -287,7 +289,7 @@ public abstract class ItemBucket extends ItemFood implements IItemContainer { currentStateId.equals(targetStateId) && getCharges(selfStack) < this.maxCharges; if (targetStateId != null && (isEmptyScoop || isRefillScoop)) { - newStack = tryPickupFluid(selfStack, world, player, tilePos, targetStateId); + result = tryPickupFluid(selfStack, world, player, tilePos, targetStateId, ctx.result); break interact; } } @@ -295,20 +297,20 @@ public abstract class ItemBucket extends ItemFood implements IItemContainer { if (currentState.canPlace()) { final NamespaceID aimedFluid = getFluidStateAt(world, tilePos); if (currentStateId.equals(aimedFluid) && getCharges(selfStack) < this.maxCharges) { - newStack = selfStack; + result = ctx.result; break interact; } - newStack = tryPlaceFluid(selfStack, world, player, tilePos, side); + result = tryPlaceFluid(selfStack, world, player, tilePos, side, ctx.result); break interact; } return false; } - final boolean isDifferent = oldSize != newStack.stackSize || newStack != selfStack; - if (isDifferent) player.inventory.setItem(player.inventory.getCurrentSlot(), newStack); - - return isDifferent; + if (result.used && result.itemStack != null) { + player.inventory.setItem(player.inventory.getCurrentSlot(), result.itemStack); + } + return result.used; } @Override @@ -316,47 +318,59 @@ public abstract class ItemBucket extends ItemFood implements IItemContainer { return handleAirClick(itemStack, world, player); } - protected ItemStack tryPickupFluid(ItemStack itemStack, World world, Player player, TilePosc tilePos, NamespaceID targetState) { - if (!world.canMineBlock(player, tilePos)) return itemStack; + protected static class UseResult { + public boolean used = false; + public @Nullable ItemStack itemStack = null; + } + + protected @NotNull UseResult tryPickupFluid( + @NotNull ItemStack itemStack, @NotNull World world, @NotNull Player player, @NotNull TilePosc tilePos, @NotNull NamespaceID targetState, + @NotNull UseResult result + ) { + if (!world.canMineBlock(player, tilePos)) return result; world.setBlockTypeNotify(tilePos, Blocks.AIR); - player.swingItem(); world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, tilePos.x() + 0.5F, tilePos.y() + 0.5F, tilePos.z() + 0.5F, "item.pickup", 2.2f, 0.5f); + result.used = true; if (itemStack.stackSize > 1) { - return splitBucket(itemStack, player, targetState, world); + result.itemStack = splitBucket(itemStack, player, targetState, world); + return result; + } + final NamespaceID currentState = getState(itemStack); + if (STATE_EMPTY.equals(currentState)) { + setState(itemStack, targetState); + setCharges(itemStack, 1); } else { - NamespaceID currentState = getState(itemStack); - if (STATE_EMPTY.equals(currentState)) { - setState(itemStack, targetState); - setCharges(itemStack, 1); - } else { - setCharges(itemStack, getCharges(itemStack) + 1); - } - return itemStack; + setCharges(itemStack, getCharges(itemStack) + 1); } + result.itemStack = itemStack; + return result; } - protected ItemStack tryPlaceFluid(@NotNull ItemStack itemStack, @NotNull World world, @NotNull Player player, @NotNull TilePosc tilePos, @NotNull Side side) { - if (!world.canMineBlock(player, tilePos)) return itemStack; + protected @NotNull UseResult tryPlaceFluid( + @NotNull ItemStack itemStack, @NotNull World world, @NotNull Player player, @NotNull TilePosc tilePos, @NotNull Side side, + @NotNull UseResult result + ) { + if (!world.canMineBlock(player, tilePos)) return result; final NamespaceID stateId = getState(itemStack); final BucketState bucketState = getBucketState(stateId); - if (bucketState.fluidBlock() == null) return itemStack; + if (bucketState.fluidBlock() == null) return result; final var blockAtPos = world.getBlockType(tilePos); if (!blockAtPos.hasTag(BlockTags.PLACE_OVERWRITES) && !blockAtPos.hasTag(BlockTags.BROKEN_BY_FLUIDS)) { tilePos = tilePos.add(side, new TilePos()); } - if (!world.canBlockIdBePlacedAt(bucketState.fluidBlock().id(), tilePos, true, side)) return itemStack; + if (!world.canBlockIdBePlacedAt(bucketState.fluidBlock().id(), tilePos, true, side)) return result; if (bucketState.placementAction() != null) bucketState.placementAction().accept(world, tilePos); final Block replacedBlock = world.getBlockType(tilePos); final int replacedData = world.getBlockData(tilePos); - if (!world.setBlockTypeNotify(tilePos, bucketState.fluidBlock())) return itemStack; + if (!world.setBlockTypeNotify(tilePos, bucketState.fluidBlock())) return result; replacedBlock.dropWithCause(world, EnumDropCause.WORLD, tilePos, replacedData, null, null); @@ -369,7 +383,9 @@ public abstract class ItemBucket extends ItemFood implements IItemContainer { world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, tilePos.x() + 0.5F, tilePos.y() + 0.5F, tilePos.z() + 0.5F, bucketState.soundPath(), 1f, 1f); } - return itemStack; + result.used = true; + result.itemStack = itemStack; + return result; } protected ItemStack handleAirClick(ItemStack itemStack, World world, Player player) { diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemPlaceablePair.java b/game/core/src/main/java/net/minecraft/core/item/ItemPlaceablePair.java index 3827f3647..0b2c38152 100644 --- a/game/core/src/main/java/net/minecraft/core/item/ItemPlaceablePair.java +++ b/game/core/src/main/java/net/minecraft/core/item/ItemPlaceablePair.java @@ -116,12 +116,16 @@ public abstract class ItemPlaceablePair extends Item implements IPlaceable { isAIdentical = prevBlockA == this.blockA && prevDataA == dataA; isBIdentical = prevBlockB == this.blockB && prevDataB == dataB; - + + if (isAIdentical && isBIdentical) return false; + if (!isAIdentical) world.setBlockTypeDataRaw(posA, this.blockA, dataA); if (!isBIdentical) world.setBlockTypeDataRaw(posB, this.blockB, dataB); if (!isAIdentical) world.markBlockNeedsUpdate(posA); if (!isBIdentical) world.markBlockNeedsUpdate(posB); + selfStack.consumeItem(player); + if (!isAIdentical) prevBlockA.onRemoved(world, posA, prevDataA); if (!isBIdentical) prevBlockB.onRemoved(world, posB, prevDataB); if (player == null) { 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 b37151054..2e4a7e2cd 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 @@ -4,7 +4,7 @@ import net.minecraft.core.block.entity.TileEntityActivator; import net.minecraft.core.entity.Mob; import net.minecraft.core.player.gamemode.Gamemodes; import net.minecraft.core.util.helper.Direction; -import net.minecraft.core.util.phys.HitResult; +import net.minecraft.core.util.helper.Side; import net.minecraft.core.entity.Entity; import net.minecraft.core.entity.EntityDispatcher; import net.minecraft.core.entity.player.Player; @@ -20,6 +20,22 @@ public class ItemWandSpawner extends Item implements IDispensable public ItemWandSpawner(@NotNull String name, @NotNull String namespaceId, int id) { super(name, namespaceId, id); } + + @Override + public boolean onUseOnBlock(@NotNull ItemStack selfStack, @NotNull World world, @Nullable Player player, @NotNull TilePosc blockPos, @NotNull Side side, double xHit, double yHit) { + if (player == null) return false; + if (player.gamemode != Gamemodes.CREATIVE) return false; + if (player.isSneaking()) return false; + + if (!world.isClientSide) { + final double x = blockPos.x() + 0.5 + side.offsetX() * 0.5; + final double y = blockPos.y() + 0.5 + side.offsetY() * 0.5; + final double z = blockPos.z() + 0.5 + side.offsetZ() * 0.5; + spawnEntity(selfStack, world, x, y, z); + } + return true; + } + @Override public @Nullable ItemStack onUse(@NotNull ItemStack selfStack, @NotNull World world, @NotNull Player player) { if (player.gamemode != Gamemodes.CREATIVE){ @@ -27,18 +43,6 @@ public class ItemWandSpawner extends Item implements IDispensable return selfStack; } - if (!player.isSneaking()){ - double reachDistance = player.getGamemode().getBlockReachDistance(); - HitResult rayTraceResult = player.rayCast(reachDistance, 1f, false, false, false); - - if (rayTraceResult != null){ - if (!world.isClientSide){ - spawnEntity(selfStack, world, rayTraceResult.location.x(), rayTraceResult.location.y(), rayTraceResult.location.z()); - } - return selfStack; - } - } - player.displayWandMobPickerScreen(selfStack); return selfStack; } diff --git a/game/core/src/main/java/net/minecraft/core/world/World.java b/game/core/src/main/java/net/minecraft/core/world/World.java index 5546e3925..d69e43401 100644 --- a/game/core/src/main/java/net/minecraft/core/world/World.java +++ b/game/core/src/main/java/net/minecraft/core/world/World.java @@ -159,7 +159,7 @@ public abstract class World implements MutableWorldSource { private final @NotNull ConduitHandler conduitHandler = new ConduitHandler(this); private final @NotNull LightingEngine lightingEngine = new LightingEngineLegacy(this); - private World( + protected World( final @NotNull Dimension dimension, final @NotNull LevelStorage levelStorage, final @Nullable WorldConfiguration worldConfiguration, diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java index 06ac14c92..83d211e27 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java @@ -591,7 +591,7 @@ public class ChunkDecoratorOverworld int j16 = x + rand.nextInt(16) + 8; int j21 = z + rand.nextInt(16) + 8; int i22 = this.world.getHeightValue(j16, j21); - (new WorldFeatureSponge()).place(this.world, rand, j16, i22, j21); + (new WorldFeatureSponge()).place(this.world, rand, new TilePos(j16, i22, j21)); } int k16 = 0; diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureSponge.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureSponge.java index 5ab9f583f..46b87fe4a 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureSponge.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureSponge.java @@ -2,29 +2,34 @@ package net.minecraft.core.world.generate.feature; import net.minecraft.core.block.Blocks; import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; import java.util.Random; -public class WorldFeatureSponge extends WorldFeature +public class WorldFeatureSponge implements WorldFeatureInterface { - @Override - public boolean place(World world, Random random, int x, int y, int z) - { - if (world.getBlockId(x, y - 1, z) != Blocks.FLUID_WATER_STILL.id()) + public boolean place(@NotNull World world, @NotNull Random random, @NotNull TilePosc tilePos) { + int x = tilePos.x(); + int y = tilePos.y(); + int z = tilePos.z(); + TilePos queryPos = new TilePos(tilePos); + if (world.getBlockType(queryPos.set(x, y - 1, z)) != Blocks.FLUID_WATER_STILL) return false; for(int l = 0; l < 16; l++) { - int i1 = (x + random.nextInt(8)) - random.nextInt(8); - int k1 = (z + random.nextInt(8)) - random.nextInt(8); + int rx = (x + random.nextInt(8)) - random.nextInt(8); + int rz = (z + random.nextInt(8)) - random.nextInt(8); - for (; world.getBlockId(i1, y - 1, k1) == Blocks.FLUID_WATER_STILL.id(); y--); + for (; world.getBlockType(queryPos.set(rx, y - 1, rz)) == Blocks.FLUID_WATER_STILL; y--); - if(world.getBlockId(i1, y-1, k1) != Blocks.SAND.id() && world.getBlockId(i1, y-1, k1) != Blocks.DIRT.id()) + if(world.getBlockType(queryPos.set(rx, y-1, rz)) != Blocks.SAND && world.getBlockType(queryPos.set(rx, y-1, rz)) != Blocks.DIRT) continue; - if(world.getBlockId(i1, y+1, k1) == 0) + if(world.isAirBlock(queryPos.set(rx, y+1, rz))) continue; - world.setBlockRaw(i1, y, k1, Blocks.SPONGE_WET.id()); + world.setBlockTypeNotify(queryPos.set(rx, y, rz), Blocks.SPONGE_WET); } return true; } 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 10b3a8b1a..b15e45ff1 100644 --- a/game/core/src/main/resources/assets/minecraft/sounds/sounds.json +++ b/game/core/src/main/resources/assets/minecraft/sounds/sounds.json @@ -1270,7 +1270,7 @@ }, { "name": "btamusic/underground/untitled.ogg", - "title": "Untitled Cave Song", + "title": "Karst", "author": "ShignBright", "stream": true } diff --git a/util/seed-viewer/build.gradle.kts b/util/seed-viewer/build.gradle.kts index 0d1f2e98f..17d9b0c1e 100644 --- a/util/seed-viewer/build.gradle.kts +++ b/util/seed-viewer/build.gradle.kts @@ -7,7 +7,7 @@ plugins { } group = "org.useless" -version = "1.1.2" +version = "1.2.0" val include: Configuration by configurations.creating diff --git a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTAChunkProvider.java b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTAChunkProvider.java index 610a57353..6cbe26ba8 100644 --- a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTAChunkProvider.java +++ b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTAChunkProvider.java @@ -11,8 +11,16 @@ import net.minecraft.core.world.biome.Biomes; import net.minecraft.core.world.biome.provider.BiomeProvider; import net.minecraft.core.world.biome.provider.BiomeProviderOverworld; import net.minecraft.core.world.pos.ChunkPos; +import net.minecraft.core.world.save.ISaveFormat; import net.minecraft.core.world.save.LevelData; +import net.minecraft.core.world.save.LevelStorage; +import net.minecraft.core.world.save.LevelStorageDummy; +import net.minecraft.core.world.save.SaveFormatBase; +import net.minecraft.core.world.save.SaveFormats; +import net.minecraft.core.world.settings.WorldConfiguration; +import net.minecraft.core.world.type.WorldType; import net.minecraft.core.world.type.WorldTypes; +import org.jetbrains.annotations.NotNull; import org.useless.seedviewer.bta.worldloader.ChunkLoader; import org.useless.seedviewer.data.ViewerChunk; import org.useless.seedviewer.gui.ChunkProvider; @@ -21,6 +29,8 @@ import org.slf4j.Logger; import java.io.File; import java.io.IOException; +import static net.minecraft.core.Global.CURRENT_SAVE_VERSION; + public class BTAChunkProvider implements ChunkProvider { private static final Logger LOGGER = LogUtils.getLogger(); static { @@ -41,14 +51,20 @@ public class BTAChunkProvider implements ChunkProvider { private final BiomeProvider biomeProvider; - public BTAChunkProvider(long seed) { - this.biomeProvider = WorldTypes.NETHER_DEFAULT.createBiomeProvider(new DummyWorld(Dimension.NETHER)); + public BTAChunkProvider(@NotNull WorldType worldType, @NotNull Dimension dimension, long seed) { + LevelStorage storage = new LevelStorageDummy(); + WorldConfiguration config = new WorldConfiguration(); config.setNumericSeed(seed); + this.biomeProvider = worldType.createBiomeProvider(new DummyWorld(dimension, storage, config, null, null)); } - public BTAChunkProvider(File worldFolder, LevelData data) { -// this.biomeProvider = new BiomeProviderOverworld(data.getRandomSeed(), WorldTypes.OVERWORLD_EXTENDED); - this.chunkLoader = new ChunkLoader(worldFolder, Dimension.OVERWORLD); - throw new IllegalArgumentException("This is currently broken!"); + public BTAChunkProvider(@NotNull File worldFolder, @NotNull Dimension dimension, @NotNull LevelData data) { + ISaveFormat activeFormat = SaveFormats.createSaveFormat(CURRENT_SAVE_VERSION, new File(worldFolder.getParent())); + if (!(activeFormat instanceof SaveFormatBase saveFormat)) { + throw new IllegalStateException("No save format registered for current save version " + CURRENT_SAVE_VERSION); + } + LevelStorage saveHandler = saveFormat.getLevelStorage(worldFolder.getName(), false); + this.biomeProvider = new DummyWorld(dimension, saveHandler, null, data, saveHandler.getDimensionDataOrDefault(dimension)).getBiomeProvider(); + this.chunkLoader = new ChunkLoader(worldFolder, dimension, data.getRandomSeed()); } @Override public ViewerChunk getChunk(ChunkPos location) { diff --git a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTAWorld.java b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTAWorld.java index 97e631027..57193de34 100644 --- a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTAWorld.java +++ b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTAWorld.java @@ -1,5 +1,6 @@ package org.useless.seedviewer.bta; +import net.minecraft.core.world.Dimension; import net.minecraft.core.world.World; import net.minecraft.core.world.save.LevelData; import org.jetbrains.annotations.NotNull; @@ -11,10 +12,12 @@ import java.io.File; import java.util.Objects; public class BTAWorld implements ViewerWorld { - private final @NotNull File worldFolder; + public final @NotNull File worldFolder; + private final @NotNull Dimension dimension; private final LevelData data; - public BTAWorld(@NotNull File worldFolder) { + public BTAWorld(@NotNull File worldFolder, @NotNull Dimension dimension) { this.worldFolder = worldFolder; + this.dimension = dimension; this.data = Objects.requireNonNull(LevelDataLoader.getLevelData(worldFolder), "Failed to get level data from world '" + worldFolder + "'"); } @Override @@ -39,6 +42,6 @@ public class BTAWorld implements ViewerWorld { @Override public ChunkProvider getChunkProvider() { - return new BTAChunkProvider(this.worldFolder, this.data); + return new BTAChunkProvider(this.worldFolder, this.dimension, this.data); } } diff --git a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/DummyWorld.java b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/DummyWorld.java index 53e7c5216..c79f74f61 100644 --- a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/DummyWorld.java +++ b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/DummyWorld.java @@ -2,7 +2,10 @@ package org.useless.seedviewer.bta; import net.minecraft.core.world.Dimension; import net.minecraft.core.world.World; +import net.minecraft.core.world.biome.Biome; import net.minecraft.core.world.chunk.provider.ChunkProvider; +import net.minecraft.core.world.save.DimensionData; +import net.minecraft.core.world.save.LevelData; import net.minecraft.core.world.save.LevelStorage; import net.minecraft.core.world.save.LevelStorageDummy; import net.minecraft.core.world.settings.WorldConfiguration; @@ -16,8 +19,14 @@ import java.util.Objects; public class DummyWorld extends World { public static @Nullable ChunkLoader CHUNK_LOADER = null; - public DummyWorld(final @NotNull Dimension dimension) { - super(new LevelStorageDummy(), new WorldConfiguration(), dimension); + public DummyWorld( + final @NotNull Dimension dimension, + final @NotNull LevelStorage levelStorage, + final @Nullable WorldConfiguration worldConfiguration, + final @Nullable LevelData levelData, + final @Nullable DimensionData dimensionData + ) { + super(dimension, levelStorage, worldConfiguration, levelData, dimensionData); } @Override @@ -25,6 +34,11 @@ public class DummyWorld extends World { // Do nothing } + @Override + protected void getInitialSpawnLocation(@Nullable Biome startingBiome) { + + } + @Override protected @NotNull ChunkProvider createChunkProvider(final @NotNull LevelStorage levelStorage) { return Objects.requireNonNullElseGet(CHUNK_LOADER, () -> new ChunkLoaderEmpty(this)); diff --git a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/worldloader/ChunkLoader.java b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/worldloader/ChunkLoader.java index e20cfe7ad..c10967a29 100644 --- a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/worldloader/ChunkLoader.java +++ b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/worldloader/ChunkLoader.java @@ -15,7 +15,9 @@ import net.minecraft.core.world.chunk.provider.ChunkProvider; import net.minecraft.core.world.chunk.reader.*; import net.minecraft.core.world.pos.ChunkPos; import net.minecraft.core.world.pos.ChunkPosc; +import net.minecraft.core.world.save.LevelStorageDummy; import net.minecraft.core.world.save.mcregion.RegionFileCache; +import net.minecraft.core.world.settings.WorldConfiguration; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -33,10 +35,11 @@ public class ChunkLoader implements ChunkProvider { private final File dimensionDir; - public ChunkLoader(File worldFolder, Dimension dimension) { + public ChunkLoader(File worldFolder, Dimension dimension, long seed) { this.dimensionDir = new File(worldFolder, "dimensions/" + dimension.id); DummyWorld.CHUNK_LOADER = this; - this.dummyWorld = new DummyWorld(dimension); + WorldConfiguration configuration = new WorldConfiguration(); configuration.setNumericSeed(seed); + this.dummyWorld = new DummyWorld(dimension, new LevelStorageDummy(), configuration, null, null); this.empty = new EmptyChunk(this.dummyWorld, 0, 0); } diff --git a/util/seed-viewer/src/main/java/org/useless/seedviewer/gui/ChunkView.java b/util/seed-viewer/src/main/java/org/useless/seedviewer/gui/ChunkView.java index 9d7ab22b3..40e57a7dc 100644 --- a/util/seed-viewer/src/main/java/org/useless/seedviewer/gui/ChunkView.java +++ b/util/seed-viewer/src/main/java/org/useless/seedviewer/gui/ChunkView.java @@ -16,8 +16,8 @@ import java.util.concurrent.Future; public class ChunkView { private static final Logger LOGGER = LogUtils.getLogger(); - private static final ExecutorService InitializerService = Executors.newFixedThreadPool(10); - private static final ExecutorService PostProcessorService = Executors.newFixedThreadPool(10); + public static final ExecutorService InitializerService = Executors.newFixedThreadPool(10); + public static final ExecutorService PostProcessorService = Executors.newFixedThreadPool(10); private final BufferedImage biomeMapImage = new BufferedImage(ViewerChunk.CHUNK_SIZE_X, ViewerChunk.CHUNK_SIZE_Z, BufferedImage.TYPE_INT_ARGB); private final BufferedImage terrainMapImage = new BufferedImage(ViewerChunk.CHUNK_SIZE_X, ViewerChunk.CHUNK_SIZE_Z, BufferedImage.TYPE_INT_ARGB); diff --git a/util/seed-viewer/src/main/java/org/useless/seedviewer/gui/SeedViewer.java b/util/seed-viewer/src/main/java/org/useless/seedviewer/gui/SeedViewer.java index 075973989..d050b4260 100644 --- a/util/seed-viewer/src/main/java/org/useless/seedviewer/gui/SeedViewer.java +++ b/util/seed-viewer/src/main/java/org/useless/seedviewer/gui/SeedViewer.java @@ -14,6 +14,9 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.awt.event.WindowStateListener; import java.util.ArrayList; import java.util.List; import java.util.Properties; @@ -25,6 +28,8 @@ public class SeedViewer extends JFrame { public static final int TICKS_PER_SECOND = 10; public static final int BEZEL = 15; + private volatile boolean running = true; + // Storage public final Properties launchProperties; private volatile boolean needsResize = true; @@ -52,7 +57,7 @@ public class SeedViewer extends JFrame { Thread mainThread = new Thread( () -> { long tickCount = 0; - while (true) { + while (this.running) { try { tick(); tickCount++; @@ -72,7 +77,7 @@ public class SeedViewer extends JFrame { } } ); - mainThread.setName("Main"); + mainThread.setName("SeedViewer Main"); mainThread.setPriority(6); mainThread.start(); } @@ -80,7 +85,46 @@ public class SeedViewer extends JFrame { public void initFrame() { // Creating instance of JFrame LOGGER.info("Initializing Frame"); - this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + boolean main = Boolean.parseBoolean(launchProperties.getProperty("main", "true")); + this.setDefaultCloseOperation(main ? EXIT_ON_CLOSE : DISPOSE_ON_CLOSE); + this.addWindowListener(new WindowListener() { + @Override + public void windowOpened(WindowEvent e) { + + } + + @Override + public void windowClosing(WindowEvent e) { + + } + + @Override + public void windowClosed(WindowEvent e) { + SeedViewer.this.running = false; + ChunkView.InitializerService.shutdown(); + ChunkView.PostProcessorService.shutdown(); + } + + @Override + public void windowIconified(WindowEvent e) { + + } + + @Override + public void windowDeiconified(WindowEvent e) { + + } + + @Override + public void windowActivated(WindowEvent e) { + + } + + @Override + public void windowDeactivated(WindowEvent e) { + + } + }); this.setTitle("BTA Seed Viewer! Version: " + SeedViewerMain.VERSION); this.setSize(960, 720); this.setMinimumSize(new Dimension(480, 360)); diff --git a/util/seed-viewer/src/main/java/org/useless/seedviewer/gui/components/InputPanel.java b/util/seed-viewer/src/main/java/org/useless/seedviewer/gui/components/InputPanel.java index ad0befb86..c31f91562 100644 --- a/util/seed-viewer/src/main/java/org/useless/seedviewer/gui/components/InputPanel.java +++ b/util/seed-viewer/src/main/java/org/useless/seedviewer/gui/components/InputPanel.java @@ -2,6 +2,12 @@ package org.useless.seedviewer.gui.components; import com.mojang.logging.LogUtils; import net.minecraft.core.Global; +import net.minecraft.core.data.registry.Registries; +import net.minecraft.core.lang.I18n; +import net.minecraft.core.world.Dimension; +import net.minecraft.core.world.type.WorldType; +import net.minecraft.core.world.type.WorldTypes; +import org.useless.seedviewer.collections.ObjectWrapper; import org.useless.seedviewer.gui.SeedViewer; import org.slf4j.Logger; @@ -32,7 +38,12 @@ public class InputPanel extends JPanel { public JCheckBox showBiomesBox; public JCheckBox showTerrainBox; public JCheckBox showCrosshairBox; + public JLabel seedInputLabel; public JTextField seedInputBox; + public JLabel worldTypeLabel; + public JComboBox worldTypeBox; + public JLabel dimensionLabel; + public JComboBox dimensionBox; public JButton screenshot; public JButton openWorld; public JButton closeWorld; @@ -91,6 +102,10 @@ public class InputPanel extends JPanel { addManaged(this.showTerrainBox); addManaged(this.showCrosshairBox); + this.seedInputLabel = new JLabel("Seed:"); + this.seedInputLabel.setSize(0, textFieldHeight); + addManaged(this.seedInputLabel); + this.seedInputBox = new JTextField(this.seedViewer.viewport.seed.toString()); this.seedInputBox.setSize(0, textFieldHeight); this.seedInputBox.addActionListener(new AbstractAction() { @@ -109,6 +124,59 @@ public class InputPanel extends JPanel { }); addManaged(this.seedInputBox); + this.worldTypeLabel = new JLabel("World Type:"); + this.worldTypeLabel.setSize(0, textFieldHeight); + addManaged(this.worldTypeLabel); + + this.worldTypeBox = new JComboBox<>(Registries.WORLD_TYPES.values().toArray(new WorldType[0])); + this.worldTypeBox.setSelectedItem(this.seedViewer.viewport.worldType.get()); + this.worldTypeBox.setSize(0, textFieldHeight); + this.worldTypeBox.setRenderer(new DefaultListCellRenderer() { + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + var comp = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (value instanceof WorldType worldType) { + setText(I18n.getInstance().translateKey(worldType.getLanguageKey() + ".name")); + } + return comp; + } + }); + this.worldTypeBox.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + seedViewer.viewport.setWorldType((WorldType) worldTypeBox.getSelectedItem()); + } + }); + seedViewer.viewport.worldType.addChangeListener(newValue -> worldTypeBox.setSelectedItem(newValue)); + addManaged(this.worldTypeBox); + + this.dimensionLabel = new JLabel("Dimension:"); + this.dimensionLabel.setSize(0, textFieldHeight); + addManaged(this.dimensionLabel); + + this.dimensionBox = new JComboBox<>(Dimension.getDimensionList().values().toArray(new Dimension[0])); + this.dimensionBox.setSelectedItem(this.seedViewer.viewport.dimension.get()); + this.dimensionBox.setSize(0, textFieldHeight); + this.dimensionBox.setRenderer(new DefaultListCellRenderer() { + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + var comp = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (value instanceof Dimension dimension) { + setText(I18n.getInstance().translateKey("dimension." + dimension.languageKey + ".name")); + } + return comp; + } + }); + this.dimensionBox.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + seedViewer.viewport.setDimension((Dimension) dimensionBox.getSelectedItem()); + } + }); + seedViewer.viewport.dimension.addChangeListener(newValue -> dimensionBox.setSelectedItem(newValue)); + addManaged(this.dimensionBox); + + this.screenshot = new JButton("Save Screenshot"); this.screenshot.setSize(0, button); this.screenshot.addActionListener(new AbstractAction() { @@ -173,10 +241,10 @@ public class InputPanel extends JPanel { if (result == JFileChooser.APPROVE_OPTION) { File selectedFile = worldSelector.getSelectedFile(); LOGGER.info("Selected file: {}", selectedFile.getAbsolutePath()); - InputPanel.this.seedViewer.viewport.setWorld(selectedFile); + InputPanel.this.seedViewer.viewport.setWorld(selectedFile, Dimension.OVERWORLD); } else { - InputPanel.this.seedViewer.viewport.setWorld(null); + InputPanel.this.seedViewer.viewport.setWorld(null, Dimension.OVERWORLD); } } }); @@ -196,7 +264,7 @@ public class InputPanel extends JPanel { this.closeWorld.addActionListener(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { - InputPanel.this.seedViewer.viewport.setWorld(null); + InputPanel.this.seedViewer.viewport.setWorld(null, Dimension.OVERWORLD); } }); addManaged(this.closeWorld); @@ -209,23 +277,43 @@ public class InputPanel extends JPanel { } public void onWorldOpen() { + this.seedInputLabel.setEnabled(false); + this.seedInputLabel.setVisible(false); this.seedInputBox.setEnabled(false); this.seedInputBox.setVisible(false); + this.worldTypeLabel.setEnabled(false); + this.worldTypeLabel.setVisible(false); + this.worldTypeBox.setEnabled(false); + this.worldTypeBox.setVisible(false); this.closeWorld.setEnabled(true); this.closeWorld.setVisible(true); this.showTerrainBox.setEnabled(true); this.showTerrainBox.setVisible(true); + this.dimensionLabel.setEnabled(true); + this.dimensionLabel.setVisible(true); + this.dimensionBox.setEnabled(true); + this.dimensionBox.setVisible(true); } public void onWorldClose() { + this.seedInputLabel.setEnabled(true); + this.seedInputLabel.setVisible(true); this.seedInputBox.setEnabled(true); this.seedInputBox.setVisible(true); + this.worldTypeLabel.setEnabled(true); + this.worldTypeLabel.setVisible(true); + this.worldTypeBox.setEnabled(true); + this.worldTypeBox.setVisible(true); this.closeWorld.setEnabled(false); this.closeWorld.setVisible(false); this.showTerrainBox.setEnabled(false); this.showTerrainBox.setVisible(false); + this.dimensionLabel.setEnabled(false); + this.dimensionLabel.setVisible(false); + this.dimensionBox.setEnabled(false); + this.dimensionBox.setVisible(false); } public void addManaged(Component c) { diff --git a/util/seed-viewer/src/main/java/org/useless/seedviewer/gui/components/Viewport.java b/util/seed-viewer/src/main/java/org/useless/seedviewer/gui/components/Viewport.java index 9805540c4..3d3d56a5d 100644 --- a/util/seed-viewer/src/main/java/org/useless/seedviewer/gui/components/Viewport.java +++ b/util/seed-viewer/src/main/java/org/useless/seedviewer/gui/components/Viewport.java @@ -1,8 +1,12 @@ package org.useless.seedviewer.gui.components; import com.mojang.logging.LogUtils; +import net.minecraft.core.world.Dimension; +import net.minecraft.core.world.World; import net.minecraft.core.world.pos.ChunkPos; import net.minecraft.core.world.pos.ChunkTilePos; +import net.minecraft.core.world.type.WorldType; +import net.minecraft.core.world.type.WorldTypes; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.useless.seedviewer.bta.BTAWorld; @@ -54,6 +58,8 @@ public class Viewport extends JLabel { public ChunkProvider chunkProvider = new TestChunkProvider(); public final ObjectWrapper<@NotNull Long> seed = new ObjectWrapper<>(100L); public final ObjectWrapper<@Nullable ViewerWorld> world = new ObjectWrapper<>(null); + public final ObjectWrapper<@NotNull Dimension> dimension = new ObjectWrapper<>(Dimension.OVERWORLD); + public final ObjectWrapper<@NotNull WorldType> worldType = new ObjectWrapper<>(WorldTypes.OVERWORLD_EXTENDED); public final ObjectWrapper<@NotNull Float> zoom = new ObjectWrapper<>(1F); public final ObjectWrapper<@NotNull Float> viewX = new ObjectWrapper<>(0F); @@ -205,23 +211,47 @@ public class Viewport extends JLabel { clearChunkViews(); this.viewX.set(0F); this.viewZ.set(0F); - this.chunkProvider = new BTAChunkProvider(this.seed.get()); + this.chunkProvider = new BTAChunkProvider(this.worldType.get(), this.dimension.get(), this.seed.get()); this.seedViewer.queueResize(); } - public synchronized void setWorld(@Nullable File file) { + public synchronized void setWorldType(@NotNull WorldType worldType) { + this.worldType.set(worldType); + clearChunkViews(); + this.viewX.set(0F); + this.viewZ.set(0F); + this.chunkProvider = new BTAChunkProvider(this.worldType.get(), this.dimension.get(), this.seed.get()); + this.seedViewer.queueResize(); + } + + public synchronized void setDimension(@NotNull Dimension dimension) { + this.dimension.set(dimension); + clearChunkViews(); + this.viewX.set(0F); + this.viewZ.set(0F); + if (this.world.get() instanceof BTAWorld btaWorld) { + setWorld(btaWorld.worldFolder, dimension); + } else { + this.chunkProvider = new BTAChunkProvider(this.worldType.get(), this.dimension.get(), this.seed.get()); + } + this.seedViewer.queueResize(); + } + + public synchronized void setWorld(@Nullable File file, @NotNull Dimension dimension) { + this.dimension.set(dimension); if (file != null) { try { - this.world.set(new BTAWorld(file)); + this.world.set(new BTAWorld(file, dimension)); this.chunkProvider = Objects.requireNonNull(this.world.get()).getChunkProvider(); } catch (Exception e) { LOGGER.error("", e); this.world.set(null); - this.chunkProvider = new BTAChunkProvider(this.seed.get()); + this.chunkProvider = new BTAChunkProvider(this.worldType.get(), dimension, this.seed.get()); } } else { this.world.set(null); - this.chunkProvider = new BTAChunkProvider(this.seed.get()); + this.worldType.set(WorldTypes.OVERWORLD_EXTENDED); + this.chunkProvider = new BTAChunkProvider(this.worldType.get(), dimension, this.seed.get()); } clearChunkViews();