diff --git a/game/client/src/main/java/net/betterthanadventure/utils/DataDumper.java b/game/client/src/main/java/net/betterthanadventure/utils/DataDumper.java index e989e6a4a..5e06c9c25 100644 --- a/game/client/src/main/java/net/betterthanadventure/utils/DataDumper.java +++ b/game/client/src/main/java/net/betterthanadventure/utils/DataDumper.java @@ -15,6 +15,7 @@ import net.minecraft.core.entity.SpawnListEntry; import net.minecraft.core.enums.MobCategory; import net.minecraft.core.item.ItemFood; import net.minecraft.core.item.Item; +import net.minecraft.core.item.ItemStack; import net.minecraft.core.item.Items; import net.minecraft.core.item.tag.ItemTags; import net.minecraft.core.item.tool.ItemToolPickaxe; @@ -117,7 +118,7 @@ public class DataDumper implements MinecraftAccessor { .append(item.id).append(",") .append(item.getKey()).append(",") .append(item.getMaxDamage()).append(",") - .append(item instanceof ItemFood ? ((ItemFood) item).getHealAmount() : "").append(",") + .append(item instanceof ItemFood ? ((ItemFood) item).getHealAmount(new ItemStack(item)) : "").append(",") .append(item.getItemStackLimit(null)).append(",") .append("\"").append(translator.translateKey(item.getKey() + ".name")).append("\"").append(",") .append("\"").append(translator.translateKey(item.getKey() + ".desc")).append("\"").append(","); diff --git a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenContainerAbstract.java b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenContainerAbstract.java index 224ca0a73..dcd58660a 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenContainerAbstract.java +++ b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenContainerAbstract.java @@ -432,7 +432,7 @@ public abstract class ScreenContainerAbstract extends Screen { break; } } - isFuel = LookupFuelFurnace.instance.getFuelYield(clickedItemId) > 0; + isFuel = LookupFuelFurnace.instance.getFuelYield(stackInSlot) > 0; if (isIngredient) { target = 1; // Into the ingredient slot @@ -453,7 +453,7 @@ public abstract class ScreenContainerAbstract extends Screen { break; } } - isFuel = LookupFuelFurnaceBlast.instance.getFuelYield(clickedItemId) > 0; + isFuel = LookupFuelFurnaceBlast.instance.getFuelYield(stackInSlot) > 0; if (isIngredient) { target = 1; // Into the ingredient slot @@ -462,7 +462,7 @@ public abstract class ScreenContainerAbstract extends Screen { } } if (this.inventorySlots instanceof MenuTrommel) { - if (LookupFuelFurnace.instance.getFuelYield(clickedItemId) > 0) { + if (LookupFuelFurnace.instance.getFuelYield(stackInSlot) > 0) { target = 2; // Into the fuel slot } else { target = 1; // Into the item slots diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHealthBar.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHealthBar.java index e35788124..a30230736 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHealthBar.java +++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHealthBar.java @@ -9,11 +9,10 @@ import net.minecraft.client.render.renderer.State; import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.core.block.Block; import net.minecraft.core.block.BlockLogicEdible; -import net.minecraft.core.item.Item; -import net.minecraft.core.item.ItemFood; -import net.minecraft.core.item.ItemStack; +import net.minecraft.core.item.*; import net.minecraft.core.player.gamemode.Gamemodes; import net.minecraft.core.util.phys.HitResult; +import org.lwjgl.opengl.GL11; import java.util.Random; @@ -70,106 +69,91 @@ public class HudComponentHealthBar extends HudComponentMovable { int x = this.getLayout().getComponentX(this, xSizeScreen); int y = this.getLayout().getComponentY(this, ySizeScreen); - // Setup rendering GLRenderer.setColor4f(1.0f, 1.0f, 1.0f, 1.0f); GLRenderer.enableState(State.BLEND); boolean heartsFlash = (mc.thePlayer.heartsFlashTime / 3) % 2 == 1; - if (mc.thePlayer.heartsFlashTime < 10) { + if (mc.thePlayer.heartsFlashTime < 10) + { heartsFlash = false; } int health = mc.thePlayer.getHealth(); int prevHealth = mc.thePlayer.prevHealth; - this.random.setSeed(hud.updateCounter * 0x4c627L); + random.setSeed(hud.updateCounter * 0x4c627L); boolean isHardcore = mc.thePlayer.getGamemode() == Gamemodes.HARDCORE; boolean isVertical = this.isVertical(); boolean isFlipped = this.isFlipped(); - + String styleFolder = isHardcore ? "hardcore/" : "survival/"; - - String halfSuffix = ""; - if (isVertical) { - halfSuffix = isFlipped ? "_vertical_flipped" : "_vertical"; - } else if (isFlipped) { - halfSuffix = "_flipped"; - } + String halfSuffix = isVertical ? (isFlipped ? "_vertical_flipped" : "_vertical") : (isFlipped ? "_flipped" : ""); for (int i = 0; i < 10; i++) { - int heartOffset = 0; - if (heartsFlash) { - heartOffset = 1; - } + int heartOffset = heartsFlash ? 1 : 0; + int xHeart = x; + int yHeart = y; - int xHeart; - int yHeart; - - // Coordinate logic applying both vertical and flipped states if (isVertical) { - xHeart = x; - yHeart = isFlipped ? (y + i * 8) : (y + (9 - i) * 8); - if (health <= 4) { - xHeart += this.random.nextInt(2); // Shake horizontally - } + yHeart = isFlipped ? (y + i * 8) : (y + (9 - i) * 8); + if (health <= 4) xHeart += this.random.nextInt(2); } else { - xHeart = isFlipped ? (x + (9 - i) * 8) : (x + i * 8); - yHeart = y; - if (health <= 4) { - yHeart += this.random.nextInt(2); // Shake vertically - } + xHeart = isFlipped ? (x + (9 - i) * 8) : (x + i * 8); + if (health <= 4) yHeart += random.nextInt(2); } - - hud.drawGuiIcon(xHeart, yHeart, 9, 9, heartOffset == 0 ? TextureRegistry.getTexture("minecraft:gui/hud/heart/container") : TextureRegistry.getTexture("minecraft:gui/hud/heart/container_blinking")); - // Flashing Damage/Heal Overlay + hud.drawGuiIcon(xHeart, yHeart, 9, 9, heartOffset == 0 ? + TextureRegistry.getTexture("minecraft:gui/hud/heart/container") : + TextureRegistry.getTexture("minecraft:gui/hud/heart/container_blinking")); + if (heartsFlash) { if (i * 2 + 1 < prevHealth) { hud.drawGuiIcon(xHeart, yHeart, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/heart/" + styleFolder + "full_blinking")); - } - if (i * 2 + 1 == prevHealth) { + } else if (i * 2 + 1 == prevHealth) { hud.drawGuiIcon(xHeart, yHeart, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/heart/" + styleFolder + "half_blinking" + halfSuffix)); } } - // Base Health if (i * 2 + 1 < health) { hud.drawGuiIcon(xHeart, yHeart, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/heart/" + styleFolder + "full")); - } - if (i * 2 + 1 == health) { + } else if (i * 2 + 1 == health) { hud.drawGuiIcon(xHeart, yHeart, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/heart/" + styleFolder + "half" + halfSuffix)); } - // Food Regen Overlay if (GameSettings.FOOD_HEALTH_REGEN_OVERLAY.value) { - int healing = 0; - ItemStack held = mc.thePlayer.getHeldItem(); - if (held != null) { - Item heldItem = held.getItem(); - if (heldItem instanceof ItemFood) { - healing = ((ItemFood) heldItem).getHealAmount(); - } - } - if (mc.objectMouseOver instanceof HitResult.Tile hitTile) { - Block b = mc.currentWorld.getBlockType(hitTile.tilePos); - if (Block.getLogicClass(b) instanceof BlockLogicEdible edible) { - healing = edible.getHealAmount(mc.currentWorld, hitTile.tilePos); + int healing = getPotentialHealing(); + if (healing > 0 && i * 2 + 1 >= health) { + if (i * 2 + 1 == health) { + hud.drawGuiIcon(xHeart, yHeart, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/heart/" + styleFolder + "preview/half_right" + halfSuffix)); + } else if (i * 2 + 1 < health + healing) { + hud.drawGuiIcon(xHeart, yHeart, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/heart/" + styleFolder + "preview/full")); + } else if (i * 2 + 1 == health + healing) { + hud.drawGuiIcon(xHeart, yHeart, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/heart/" + styleFolder + "preview/half" + halfSuffix)); } } + } + } + GLRenderer.disableState(State.BLEND); + } - if (healing > 0) { - if (i * 2 + 1 >= health) { - if (i * 2 + 1 == health) { - hud.drawGuiIcon(xHeart, yHeart, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/heart/" + styleFolder + "preview/half_right" + halfSuffix)); - } else if (i * 2 + 1 < health + healing) { - hud.drawGuiIcon(xHeart, yHeart, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/heart/" + styleFolder + "preview/full")); - } else if (i * 2 + 1 == health + healing) { - hud.drawGuiIcon(xHeart, yHeart, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/heart/" + styleFolder + "preview/half" + halfSuffix)); - } - } - } + private int getPotentialHealing() { + int healing = 0; + + ItemStack held = mc.thePlayer.getHeldItem(); + + if (held != null && held.getItem() instanceof ItemFood food) { + healing = food.getHealAmount(held); + } + + if (mc.objectMouseOver instanceof HitResult.Tile hitTile) { + Block block = mc.currentWorld.getBlockType(hitTile.tilePos); + + if (Block.getLogicClass(block) instanceof BlockLogicEdible edible) { + healing = edible.getHealAmount(mc.currentWorld, hitTile.tilePos); } } + + return healing; } @Override @@ -206,10 +190,10 @@ public class HudComponentHealthBar extends HudComponentMovable { yHeart = y; } - // Container + // Container gui.drawGuiIcon(xHeart, yHeart, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/heart/container")); - - if (i * 2 + 1 < health) { + if (i * 2 + 1 < health) + { gui.drawGuiIcon(xHeart, yHeart, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/heart/" + styleFolder + "full")); } if (i * 2 + 1 == health) { 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 0209477d9..e140ae371 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 @@ -31,7 +31,6 @@ import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.client.render.worldtype.WorldTypeFX; import net.minecraft.client.render.worldtype.WorldTypeFXDispatcher; import net.minecraft.client.world.WorldClient; -import net.minecraft.core.Global; import net.minecraft.core.block.Block; import net.minecraft.core.block.Blocks; import net.minecraft.core.block.entity.TileEntity; @@ -1945,9 +1944,59 @@ public class RenderGlobal case EVENT_PISTON_RETRACT: // Piston retract this.world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, (double) x + 0.5F, (double) y + 0.5F, (double) z + 0.5F, "tile.piston.in", 0.5F, this.world.rand.nextFloat() * 0.25F + 0.6F); break; - default: + case EVENT_CONDUIT_PORT_PARTICLES: // Conduit port open particles + Side s1 = unpackEventConduitSide(data); + int xO = s1.getOffsetX(); + int yO = s1.getOffsetY(); + int zO = s1.getOffsetZ(); + double xP = (double) x + (double) xO * 0.6D + 0.5D; + double yP = (double) y + (double) yO * 0.6D + 0.5D; + double zP = (double) z + (double) zO * 0.6D + 0.5D; + for (int i = 0; i < 2; i++) { + double rO = random.nextDouble() * 0.2D + 0.01D; + double fx = xP + (double) xO * 0.01D + (random.nextDouble() - 0.5D) * (double) zO * 0.5D; + double fy = yP + (double) yO * 0.01D + (random.nextDouble() - 0.5D) * (double) yO * 0.5D; + double fz = zP + (double) zO * 0.01D + (random.nextDouble() - 0.5D) * (double) xO * 0.5D; + double mx = (double) xO * rO; + double my = (double) yO * rO; + double mz = (double) zO * rO; + addParticle("reddust", fx, fy, fz, mx, my, mz, unpackEventConduitStrength(data), false); + } + break; + case EVENT_CONDUIT_SURFACE_PARTICLES: //conduit ambient particles + int surfaceStrength = unpackEventConduitStrength(data); + + if (surfaceStrength <= 0) { + break; + } + + double d = 0.0625; + + Direction dir = Direction.directions[random.nextInt(Direction.directions.length)]; + + double lx = (double) x + random.nextFloat(); + double ly = (double) y + random.nextFloat(); + double lz = (double) z + random.nextFloat(); + + if (!this.world.isBlockOpaqueCube(x + dir.getOffsetX(), y + dir.getOffsetY(), z + dir.getOffsetZ())) { + switch (dir) { + case UP -> ly = (y + 1) + d; + case DOWN -> ly = (y) - d; + case SOUTH -> lz = (z + 1) + d; + case NORTH -> lz = (z) - d; + case EAST -> lx = (x + 1) + d; + case WEST -> lx = (x) - d; + } + } + + if (lx < x || lx > (x + 1) || ly < 0.0D || ly > (y + 1) || lz < z || lz > (z + 1)) { + addParticle("reddust", lx, ly, lz, 0, 0, 0, surfaceStrength, false); + } + break; + default: + break; } } @@ -1959,4 +2008,13 @@ public class RenderGlobal public void entityRemoved(Entity entity) { } + public static Side unpackEventConduitSide(int packed) { + int sideId = (packed >> 4) & 0x07; + return Side.getSideById(sideId); + } + + public static int unpackEventConduitStrength(int packed) { + return packed & 0x0F; + } + } diff --git a/game/client/src/main/java/net/minecraft/client/render/TileEntityRenderDispatcher.java b/game/client/src/main/java/net/minecraft/client/render/TileEntityRenderDispatcher.java index 84a74fbc6..235f6d164 100644 --- a/game/client/src/main/java/net/minecraft/client/render/TileEntityRenderDispatcher.java +++ b/game/client/src/main/java/net/minecraft/client/render/TileEntityRenderDispatcher.java @@ -62,6 +62,7 @@ public final class TileEntityRenderDispatcher { } @SuppressWarnings("unchecked") // trust me this is safe, Notch did it first + // Instills me with much confidence :wolfblock: ^ public TileEntityRenderer getRenderer(final Class e) { TileEntityRenderer r = this.renderers.get(e); if (r == null && e != TileEntity.class) { diff --git a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorDispatcher.java b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorDispatcher.java index 14f8493b7..023ec10ad 100644 --- a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorDispatcher.java +++ b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorDispatcher.java @@ -48,6 +48,7 @@ public final class BlockColorDispatcher addDispatch(Blocks.WIRE_REDSTONE, new BlockColorWireRedstone()); addDispatch(Blocks.TALLGRASS, new BlockColorCustom(Colorizers.grass)); addDispatch(Blocks.TALLGRASS_FERN, new BlockColorCustom(Colorizers.grass)); + addDispatch(Blocks.RUBYGLASS_CONDUIT, new BlockColorRubyglassConduit()); } diff --git a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorRubyglassConduit.java b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorRubyglassConduit.java new file mode 100644 index 000000000..679cad0ca --- /dev/null +++ b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorRubyglassConduit.java @@ -0,0 +1,63 @@ +package net.minecraft.client.render.block.color; + +import com.mojang.logging.LogUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.core.block.BlockLogicRubyglassConduit; +import net.minecraft.core.world.WorldSource; +import net.minecraft.core.world.pos.TilePosc; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.InputStream; + +public class BlockColorRubyglassConduit extends BlockColor { + + private static final org.slf4j.Logger LOGGER = LogUtils.getLogger(); + private final int[] powerColors = new int[11]; + + public BlockColorRubyglassConduit() { + loadPalette(); + } + + private void loadPalette() { + boolean loadedSuccessfully = false; + String palettePath = "/assets/minecraft/textures/misc/colors_conduit.png"; + + try (InputStream stream = Minecraft.getMinecraft().texturePackList.getResourceAsStream(palettePath)) { + if (stream != null) { + BufferedImage image = ImageIO.read(stream); + + for (int i = 0; i < 11; i++) { + int x = Math.min(i, image.getWidth() - 1); + powerColors[i] = image.getRGB(x, 0) & 0xFFFFFF; + } + loadedSuccessfully = true; + } + } catch (Exception e) { + LOGGER.error("Failed to load conduit palette at {}", palettePath, e); + } + + if (!loadedSuccessfully) { + powerColors[0] = 0x330000; + int minRed = 80; + int maxRed = 255; + for (int strength = 1; strength <= 10; strength++) { + int redValue = minRed + (int)(((strength - 1) / 9.0f) * (maxRed - minRed)); + powerColors[strength] = (redValue << 16); + } + } + } + + @Override + public int getFallbackColor(int meta, int tintIndex) { + return powerColors[0]; + } + + @Override + public int getWorldColor(WorldSource world, TilePosc pos, int tintIndex) { + int data = world.getBlockData(pos); + int strength = data / BlockLogicRubyglassConduit.STATE_COUNT; + strength = Math.max(0, Math.min(10, strength)); + return powerColors[strength]; + } +} \ No newline at end of file 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 d451b9d60..af8a9e2a4 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 @@ -7,7 +7,6 @@ import net.minecraft.client.render.texture.stitcher.IconCoordinate; import net.minecraft.client.util.dispatch.Dispatcher; import net.minecraft.core.block.Block; import net.minecraft.core.block.Blocks; -import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.World; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; @@ -348,7 +347,7 @@ public final class BlockModelDispatcher addDispatch(new BlockModelGeneric<>(Blocks.RUBYGLASS_NODE, loadDataModel("minecraft:block/rubyglass/node"))); addDispatch(new BlockModelGeneric<>(Blocks.BLOCK_RUBYGLASS, loadDataModel("minecraft:block/rubyglass/block")).forceCullSelf(true)); addDispatch(new BlockModelCrystalBud<>(Blocks.RUBYGLASS_SPROUT, loadDataModel("minecraft:block/rubyglass/sprout")).render3D(false)); - addDispatch(new BlockModelGeneric<>(Blocks.RUBYGLASS_CIRCUIT, loadDataModel("minecraft:block/rubyglass/circuit"))); + addDispatch(new BlockModelRubyglassConduit<>(Blocks.RUBYGLASS_CONDUIT)); addDispatch(new BlockModelGeneric<>(Blocks.ORE_NETHERCOAL_NETHERRACK, loadDataModel("minecraft:block/ore/nethercoal/netherrack"))); addDispatch(new BlockModelGeneric<>(Blocks.ORE_NETHERCOAL_BASALT, loadDataModel("minecraft:block/ore/nethercoal/basalt"))); diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRubyglassConduit.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRubyglassConduit.java new file mode 100644 index 000000000..5faddc642 --- /dev/null +++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRubyglassConduit.java @@ -0,0 +1,101 @@ +package net.minecraft.client.render.block.model; + +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.Block; +import net.minecraft.core.block.BlockLogicRubyglassConduit; +import net.minecraft.core.world.WorldSource; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.useless.dragonfly.models.block.StaticBlockModel; + +public class BlockModelRubyglassConduit extends BlockModelGeneric { + + private record ModelState(StaticBlockModel model, int rotX, int rotY, int rotZ) { } + + private final ModelState[] stateMapOn = new ModelState[BlockLogicRubyglassConduit.STATE_COUNT]; + private final ModelState[] stateMapOff = new ModelState[BlockLogicRubyglassConduit.STATE_COUNT]; + + public BlockModelRubyglassConduit(Block block) { + super(block, BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass/conduit/conduit_core").asModel()); + + StaticBlockModel onCore = BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass/conduit/conduit_core").asModel(); + StaticBlockModel onCap = BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass/conduit/conduit_cap").asModel(); + StaticBlockModel onStraight = BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass/conduit/conduit_straight").asModel(); + StaticBlockModel onCorner = BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass/conduit/conduit_corner").asModel(); + + StaticBlockModel offCore = BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass/conduit/conduit_core_off").asModel(); + StaticBlockModel offCap = BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass/conduit/conduit_cap_off").asModel(); + StaticBlockModel offStraight = BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass/conduit/conduit_straight_off").asModel(); + StaticBlockModel offCorner = BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass/conduit/conduit_corner_off").asModel(); + + populateStateMap(stateMapOn, onCore, onCap, onStraight, onCorner); + populateStateMap(stateMapOff, offCore, offCap, offStraight, offCorner); + } + + private void populateStateMap(ModelState[] map, StaticBlockModel core, StaticBlockModel cap, StaticBlockModel straight, StaticBlockModel corner) { + // 0: Core + map[0] = new ModelState(core, 0, 0, 0); + + // 1-6: End Caps + map[1] = new ModelState(cap, 0, 0, 0); + map[2] = new ModelState(cap, 2, 0, 0); + map[3] = new ModelState(cap, 1, 0, 0); + map[4] = new ModelState(cap, 3, 0, 0); + map[5] = new ModelState(cap, 0, 0, 3); + map[6] = new ModelState(cap, 0, 0, 1); + + // 7-9: Straights + map[7] = new ModelState(straight, 0, 0, 0); + map[8] = new ModelState(straight, 1, 0, 0); + map[9] = new ModelState(straight, 0, 0, 1); + + // 10-13: Bottom Corners + map[10] = new ModelState(corner, 0, 0, 0); + map[11] = new ModelState(corner, 0, 2, 0); + map[12] = new ModelState(corner, 0, 1, 0); + map[13] = new ModelState(corner, 0, 3, 0); + + // 14-17: Top Corners + map[14] = new ModelState(corner, 2, 2, 0); + map[15] = new ModelState(corner, 2, 0, 0); + map[16] = new ModelState(corner, 2, 3, 0); + map[17] = new ModelState(corner, 2, 1, 0); + + // 18-21: Horizontal Corners + map[18] = new ModelState(corner, 0, 0, 3); + map[19] = new ModelState(corner, 0, 0, 1); + map[20] = new ModelState(corner, 0, 2, 3); + map[21] = new ModelState(corner, 0, 2, 1); + } + + @Override + public @NotNull StaticBlockModel getModelFromData(int data) { + int state = data % BlockLogicRubyglassConduit.STATE_COUNT; + int strength = data / BlockLogicRubyglassConduit.STATE_COUNT; + + if (strength == 0) { + return stateMapOff[state].model; + } else { + return stateMapOn[state].model; + } + } + + @Override + public boolean renderAttached(final @NotNull TessellatorGeneral tessellator, @NotNull final WorldSource worldSource, @NotNull TilePosc tilePos, boolean cullFaces, final @Nullable IconCoordinate overrideTexture) { + int data = worldSource.getBlockData(tilePos); + int state = data % BlockLogicRubyglassConduit.STATE_COUNT; + int strength = data / BlockLogicRubyglassConduit.STATE_COUNT; + + ModelState activeState; + if (strength == 0) { + activeState = stateMapOff[state]; + } else { + activeState = stateMapOn[state]; + } + + return activeState.model.renderAttached(this, tessellator, worldSource, tilePos, activeState.rotX, activeState.rotY, activeState.rotZ, 0, 0, 0, false, cullFaces, overrideTexture); + } +} \ No newline at end of file diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/RenderBlocks.java b/game/client/src/main/java/net/minecraft/client/render/block/model/RenderBlocks.java index f29dc48b6..81a98d504 100644 --- a/game/client/src/main/java/net/minecraft/client/render/block/model/RenderBlocks.java +++ b/game/client/src/main/java/net/minecraft/client/render/block/model/RenderBlocks.java @@ -21,7 +21,8 @@ import static net.minecraft.client.render.block.model.BlockModel.FULL_CUBE_THRES public final class RenderBlocks { public final @NotNull Minecraft mc; - public IconCoordinate overrideBlockTexture; + public @Nullable IconCoordinate overrideBlockTexture; + public @Nullable Integer overrideLightmap; public boolean flipTexture; public boolean renderAllFaces; public byte renderBitMask; @@ -57,6 +58,7 @@ public final class RenderBlocks { public RenderBlocks() { this.overrideBlockTexture = null; + this.overrideLightmap = null; this.flipTexture = false; this.renderAllFaces = false; this.useInventoryTint = true; @@ -77,6 +79,7 @@ public final class RenderBlocks { this.useInventoryTint = true; this.flipTexture = false; this.overrideBlockTexture = null; + this.overrideLightmap = null; this.uvRotateEast = 0; this.uvRotateWest = 0; this.uvRotateSouth = 0; @@ -248,54 +251,62 @@ public final class RenderBlocks { int dirX, int dirY, int dirZ, float depth, int topX, int topY, int topZ, float topP, float botP, int lefX, int lefY, int lefZ, float lefP, float rigP) { + this.colorRedTopLeft = this.colorRedBottomLeft = this.colorRedBottomRight = this.colorRedTopRight = r; + this.colorGreenTopLeft = this.colorGreenBottomLeft = this.colorGreenBottomRight = this.colorGreenTopRight = g; + this.colorBlueTopLeft = this.colorBlueBottomLeft = this.colorBlueBottomRight = this.colorBlueTopRight = b; + boolean ao = GameSettings.AMBIENT_OCCLUSION.value && block.emission == 0; boolean isFullCube = depth <= FULL_CUBE_THRESHOLD; - if (ao) { - int dirX2 = dirX; - int dirY2 = dirY; - int dirZ2 = dirZ; - - if (!isFullCube) { - dirX2 = 0; - dirY2 = 0; - dirZ2 = 0; - } - - boolean topT = this.cache.getOpacity(dirX2 + topX, dirY2 + topY, dirZ2 + topZ); - boolean botT = this.cache.getOpacity(dirX2 - topX, dirY2 - topY, dirZ2 - topZ); - boolean lefT = this.cache.getOpacity(dirX2 + lefX, dirY2 + lefY, dirZ2 + lefZ); - boolean rigT = this.cache.getOpacity(dirX2 - lefX, dirY2 - lefY, dirZ2 - lefZ); - - boolean topLefT = this.cache.getOpacity(dirX2 + topX + lefX, dirY2 + topY + lefY, dirZ2 + topZ + lefZ); - boolean topRigT = this.cache.getOpacity(dirX2 + topX - lefX, dirY2 + topY - lefY, dirZ2 + topZ - lefZ); - boolean botLefT = this.cache.getOpacity(dirX2 - topX + lefX, dirY2 - topY + lefY, dirZ2 - topZ + lefZ); - boolean botRigT = this.cache.getOpacity(dirX2 - topX - lefX, dirY2 - topY - lefY, dirZ2 - topZ - lefZ); - - byte lmcCen = this.cache.getLightIndex(dirX2, dirY2, dirZ2); - - byte lmcTop = topT ? lmcCen : this.cache.getLightIndex(dirX2 + topX, dirY2 + topY, dirZ2 + topZ); - byte lmcBot = botT ? lmcCen : this.cache.getLightIndex(dirX2 - topX, dirY2 - topY, dirZ2 - topZ); - byte lmcLef = lefT ? lmcCen : this.cache.getLightIndex(dirX2 + lefX, dirY2 + lefY, dirZ2 + lefZ); - byte lmcRig = rigT ? lmcCen : this.cache.getLightIndex(dirX2 - lefX, dirY2 - lefY, dirZ2 - lefZ); - - byte lmcTopLef = topT && lefT ? lmcLef : (topLefT ? lmcCen : this.cache.getLightIndex(dirX2 + topX + lefX, dirY2 + topY + lefY, dirZ2 + topZ + lefZ)); - byte lmcBotLef = botT && lefT ? lmcLef : (botLefT ? lmcCen : this.cache.getLightIndex(dirX2 - topX + lefX, dirY2 - topY + lefY, dirZ2 - topZ + lefZ)); - byte lmcTopRig = topT && rigT ? lmcRig : (topRigT ? lmcCen : this.cache.getLightIndex(dirX2 + topX - lefX, dirY2 + topY - lefY, dirZ2 + topZ - lefZ)); - byte lmcBotRig = botT && rigT ? lmcRig : (botRigT ? lmcCen : this.cache.getLightIndex(dirX2 - topX - lefX, dirY2 - topY - lefY, dirZ2 - topZ - lefZ)); - - this.lightIndexTopLeft = LightIndexHelper.avg(lmcCen, lmcLef, lmcTop, lmcTopLef); - this.lightIndexTopRight = LightIndexHelper.avg(lmcCen, lmcRig, lmcTop, lmcTopRig); - this.lightIndexBottomLeft = LightIndexHelper.avg(lmcCen, lmcLef, lmcBot, lmcBotLef); - this.lightIndexBottomRight = LightIndexHelper.avg(lmcCen, lmcRig, lmcBot, lmcBotRig); - } else { - int lmc; - if (!isFullCube) { - lmc = block.getLightIndex(worldSource, tilePos); + if (this.overrideLightmap == null) { + if (ao) { + int dirX2 = dirX; + int dirY2 = dirY; + int dirZ2 = dirZ; + + if (!isFullCube) { + dirX2 = 0; + dirY2 = 0; + dirZ2 = 0; + } + + boolean topT = this.cache.getOpacity(dirX2 + topX, dirY2 + topY, dirZ2 + topZ); + boolean botT = this.cache.getOpacity(dirX2 - topX, dirY2 - topY, dirZ2 - topZ); + boolean lefT = this.cache.getOpacity(dirX2 + lefX, dirY2 + lefY, dirZ2 + lefZ); + boolean rigT = this.cache.getOpacity(dirX2 - lefX, dirY2 - lefY, dirZ2 - lefZ); + + boolean topLefT = this.cache.getOpacity(dirX2 + topX + lefX, dirY2 + topY + lefY, dirZ2 + topZ + lefZ); + boolean topRigT = this.cache.getOpacity(dirX2 + topX - lefX, dirY2 + topY - lefY, dirZ2 + topZ - lefZ); + boolean botLefT = this.cache.getOpacity(dirX2 - topX + lefX, dirY2 - topY + lefY, dirZ2 - topZ + lefZ); + boolean botRigT = this.cache.getOpacity(dirX2 - topX - lefX, dirY2 - topY - lefY, dirZ2 - topZ - lefZ); + + byte lmcCen = this.cache.getLightIndex(dirX2, dirY2, dirZ2); + + byte lmcTop = topT ? lmcCen : this.cache.getLightIndex(dirX2 + topX, dirY2 + topY, dirZ2 + topZ); + byte lmcBot = botT ? lmcCen : this.cache.getLightIndex(dirX2 - topX, dirY2 - topY, dirZ2 - topZ); + byte lmcLef = lefT ? lmcCen : this.cache.getLightIndex(dirX2 + lefX, dirY2 + lefY, dirZ2 + lefZ); + byte lmcRig = rigT ? lmcCen : this.cache.getLightIndex(dirX2 - lefX, dirY2 - lefY, dirZ2 - lefZ); + + byte lmcTopLef = topT && lefT ? lmcLef : (topLefT ? lmcCen : this.cache.getLightIndex(dirX2 + topX + lefX, dirY2 + topY + lefY, dirZ2 + topZ + lefZ)); + byte lmcBotLef = botT && lefT ? lmcLef : (botLefT ? lmcCen : this.cache.getLightIndex(dirX2 - topX + lefX, dirY2 - topY + lefY, dirZ2 - topZ + lefZ)); + byte lmcTopRig = topT && rigT ? lmcRig : (topRigT ? lmcCen : this.cache.getLightIndex(dirX2 + topX - lefX, dirY2 + topY - lefY, dirZ2 + topZ - lefZ)); + byte lmcBotRig = botT && rigT ? lmcRig : (botRigT ? lmcCen : this.cache.getLightIndex(dirX2 - topX - lefX, dirY2 - topY - lefY, dirZ2 - topZ - lefZ)); + + this.lightIndexTopLeft = LightIndexHelper.avg(lmcCen, lmcLef, lmcTop, lmcTopLef); + this.lightIndexTopRight = LightIndexHelper.avg(lmcCen, lmcRig, lmcTop, lmcTopRig); + this.lightIndexBottomLeft = LightIndexHelper.avg(lmcCen, lmcLef, lmcBot, lmcBotLef); + this.lightIndexBottomRight = LightIndexHelper.avg(lmcCen, lmcRig, lmcBot, lmcBotRig); } else { - lmc = block.getLightIndex(worldSource, tilePos.add(dirX, dirY, dirZ, new TilePos())); + int lmc; + if (!isFullCube) { + lmc = block.getLightIndex(worldSource, tilePos); + } else { + lmc = block.getLightIndex(worldSource, tilePos.add(dirX, dirY, dirZ, new TilePos())); + } + this.lightIndexTopLeft = this.lightIndexBottomLeft = this.lightIndexBottomRight = this.lightIndexTopRight = lmc; } - this.lightIndexTopLeft = this.lightIndexBottomLeft = this.lightIndexBottomRight = this.lightIndexTopRight = lmc; + } else { + this.lightIndexTopLeft = this.lightIndexBottomLeft = this.lightIndexBottomRight = this.lightIndexTopRight = this.overrideLightmap; } float lightTR; @@ -357,9 +368,6 @@ public final class RenderBlocks { lightTL = lightBL = lightBR = lightTR = brightness; } - this.colorRedTopLeft = this.colorRedBottomLeft = this.colorRedBottomRight = this.colorRedTopRight = r; - this.colorGreenTopLeft = this.colorGreenBottomLeft = this.colorGreenBottomRight = this.colorGreenTopRight = g; - this.colorBlueTopLeft = this.colorBlueBottomLeft = this.colorBlueBottomRight = this.colorBlueTopRight = b; float tl = topP * lightTL + (1 - topP) * lightBL; float tr = topP * lightTR + (1 - topP) * lightBR; float bl = botP * lightTL + (1 - botP) * lightBL; diff --git a/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureCustom.java b/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureCustom.java index 1d87a4884..73a8af518 100644 --- a/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureCustom.java +++ b/game/client/src/main/java/net/minecraft/client/render/dynamictexture/DynamicTextureCustom.java @@ -15,20 +15,20 @@ public class DynamicTextureCustom extends DynamicTexture { private static final Logger LOGGER = LogUtils.getLogger(); private static final Random rand = new Random(); - private final int frameCount; - private final byte[][] frameData; + protected final int frameCount; + protected final byte[][] frameData; - private final AnimationProperties properties; + protected final AnimationProperties properties; - private int currentIndex = 0; - private final int indices; + protected int currentIndex = 0; + protected final int indices; - private int currentFrame = -1; - private int previousFrame = -1; - private int delayUntilNextFrame = 0; - private int frameLength = 0; + protected int currentFrame = -1; + protected int previousFrame = -1; + protected int delayUntilNextFrame = 0; + protected int frameLength = 0; - private final boolean tickWhenPaused; + protected final boolean tickWhenPaused; public DynamicTextureCustom(IconCoordinate texture, AnimationProperties animationProperties) { super(texture); diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelBucket.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelBucket.java new file mode 100644 index 000000000..a0a6d2f40 --- /dev/null +++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelBucket.java @@ -0,0 +1,69 @@ +package net.minecraft.client.render.item.model; + +import net.minecraft.client.render.texture.stitcher.IconCoordinate; +import net.minecraft.client.render.texture.stitcher.TextureRegistry; +import net.minecraft.core.entity.Entity; +import net.minecraft.core.item.Item; +import net.minecraft.core.item.ItemBucket; +import net.minecraft.core.item.ItemStack; +import net.minecraft.core.util.collection.NamespaceID; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public abstract class ItemModelBucket extends ItemModelStandard { + + protected final Map bucketIcons = new HashMap<>(); + + public ItemModelBucket(Item item, String namespace) { + super(item, namespace); + } + + protected void initializeIcons(String namespace, String prefix, int maxCharges, Set validStates) { + IconCoordinate[] emptyArray = new IconCoordinate[1]; + emptyArray[0] = TextureRegistry.getTexture(namespace + ":item/" + prefix + "/empty"); + this.bucketIcons.put(ItemBucket.STATE_EMPTY, emptyArray); + + for (NamespaceID stateId : validStates) { + if (ItemBucket.STATE_EMPTY.equals(stateId)) continue; + + String stateName = stateId.value(); + IconCoordinate[] chargesArray = new IconCoordinate[maxCharges + 1]; + + for (int c = 1; c <= maxCharges; c++) { + String path = namespace + ":item/" + prefix + "/" + stateName + "_" + c; + chargesArray[c] = TextureRegistry.getTexture(path); + } + this.bucketIcons.put(stateId, chargesArray); + } + } + + @Override + public @NotNull IconCoordinate getIcon(@Nullable Entity entity, ItemStack itemStack) { + NamespaceID state = ItemBucket.getState(itemStack); + int charges = ItemBucket.getCharges(itemStack); + + int maxForThisBucket = 1; + if (itemStack.getItem() instanceof ItemBucket bucket) { + maxForThisBucket = bucket.maxCharges; + } + + if (!ItemBucket.STATE_EMPTY.equals(state) && charges <= 0) { + long cycleTime = 620; + charges = (int) ((System.currentTimeMillis() / cycleTime) % maxForThisBucket) + 1; + } + + charges = Math.max(0, Math.min(charges, maxForThisBucket)); + IconCoordinate[] iconsForState = bucketIcons.get(state); + + if (iconsForState == null || charges >= iconsForState.length) { + return super.getIcon(entity, itemStack); + } + + IconCoordinate icon = iconsForState[charges]; + return (icon != null) ? icon : super.getIcon(entity, itemStack); + } +} \ No newline at end of file diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelBucketIron.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelBucketIron.java new file mode 100644 index 000000000..0e6313688 --- /dev/null +++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelBucketIron.java @@ -0,0 +1,20 @@ +package net.minecraft.client.render.item.model; + +import net.minecraft.core.item.Item; +import net.minecraft.core.item.ItemBucket; +import net.minecraft.core.util.collection.NamespaceID; + +import java.util.Set; + +public class ItemModelBucketIron extends ItemModelBucket { + public ItemModelBucketIron(Item item, String namespace) { + super(item, namespace); + Set validStates = Set.of( + ItemBucket.STATE_WATER, + ItemBucket.STATE_LAVA, + ItemBucket.STATE_MILK, + ItemBucket.STATE_ICECREAM + ); + this.initializeIcons(namespace, "bucket_iron", 1, validStates); + } +} \ No newline at end of file diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelBucketSteel.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelBucketSteel.java new file mode 100644 index 000000000..dff72dccb --- /dev/null +++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelBucketSteel.java @@ -0,0 +1,21 @@ +package net.minecraft.client.render.item.model; + +import net.minecraft.core.item.Item; +import net.minecraft.core.item.ItemBucket; +import net.minecraft.core.util.collection.NamespaceID; + +import java.util.Set; + +public class ItemModelBucketSteel extends ItemModelBucket { + public ItemModelBucketSteel(Item item, String namespace) { + super(item, namespace); + Set validStates = Set.of( + ItemBucket.STATE_WATER, + ItemBucket.STATE_LAVA, + ItemBucket.STATE_MILK, + ItemBucket.STATE_ICECREAM + ); + + this.initializeIcons(namespace, "bucket_steel", 3, validStates); + } +} \ No newline at end of file diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java index 8c5006024..0621b6019 100644 --- a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java +++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java @@ -241,9 +241,10 @@ public class ItemModelDispatcher extends Dispatcher { addDispatch(new ItemModelStandard(Items.DOOR_OAK, "minecraft")); addDispatch(new ItemModelStandard(Items.DOOR_GLASS, "minecraft")); addDispatch(new ItemModelDoorPainted(Items.DOOR_OAK_PAINTED)); - addDispatch(new ItemModelStandard(Items.BUCKET, "minecraft")); - addDispatch(new ItemModelStandard(Items.BUCKET_WATER, "minecraft")); - addDispatch(new ItemModelStandard(Items.BUCKET_LAVA, "minecraft").setFullBright()); + addDispatch(new ItemModelBucketIron(Items.BUCKET_IRON, "minecraft")); + addDispatch(new ItemModelBucketSteel(Items.BUCKET_STEEL, "minecraft")); + //addDispatch(new ItemModelStandard(Items.BUCKET_WATER, "minecraft")); + //addDispatch(new ItemModelStandard(Items.BUCKET_LAVA, "minecraft").setFullBright()); addDispatch(new ItemModelStandard(Items.MINECART, "minecraft")); addDispatch(new ItemModelStandard(Items.SADDLE, "minecraft")); addDispatch(new ItemModelStandard(Items.DOOR_IRON, "minecraft")); @@ -251,7 +252,7 @@ public class ItemModelDispatcher extends Dispatcher { addDispatch(new ItemModelStandard(Items.AMMO_SNOWBALL, "minecraft")); addDispatch(new ItemModelStandard(Items.BOAT, "minecraft")); addDispatch(new ItemModelStandard(Items.LEATHER, "minecraft")); - addDispatch(new ItemModelStandard(Items.BUCKET_MILK, "minecraft")); + //addDispatch(new ItemModelStandard(Items.BUCKET_MILK, "minecraft")); addDispatch(new ItemModelStandard(Items.BRICK_CLAY, "minecraft")); addDispatch(new ItemModelStandard(Items.CLAY, "minecraft")); addDispatch(new ItemModelStandard(Items.SUGARCANE, "minecraft")); @@ -345,7 +346,7 @@ public class ItemModelDispatcher extends Dispatcher { addDispatch(new ItemModelStandard(Items.OLIVINE, "minecraft")); addDispatch(new ItemModelStandard(Items.AMMO_PEBBLE, "minecraft")); addDispatch(new ItemModelStandard(Items.FOOD_CHERRY, "minecraft")); - addDispatch(new ItemModelStandard(Items.BUCKET_ICECREAM, "minecraft")); + //addDispatch(new ItemModelStandard(Items.BUCKET_ICECREAM, "minecraft")); addDispatch(new ItemModelStandard(Items.AMMO_ARROW_PURPLE, "minecraft")); addDispatch(new ItemModelLabel(Items.LABEL, "minecraft")); addDispatch(new ItemModelStandard(Items.JAR, "minecraft")); diff --git a/game/client/src/main/java/net/minecraft/client/render/texture/generator/TextureGeneratorRubyglassConduit.java b/game/client/src/main/java/net/minecraft/client/render/texture/generator/TextureGeneratorRubyglassConduit.java new file mode 100644 index 000000000..fa494b0f2 --- /dev/null +++ b/game/client/src/main/java/net/minecraft/client/render/texture/generator/TextureGeneratorRubyglassConduit.java @@ -0,0 +1,81 @@ +package net.minecraft.client.render.texture.generator; + +import net.minecraft.client.Minecraft; +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.InputStream; + +public class TextureGeneratorRubyglassConduit { + + private static int[] palette = null; + + public static BufferedImage generateConduitTexture(String shape, int strength, String layer) { + loadPalette(); + int color = palette[Math.max(0, Math.min(10, strength))]; + + String basePath = "/assets/minecraft/textures/block/rubyglass/conduit/" + shape + "_base.png"; + String maskPath = "/assets/minecraft/textures/block/rubyglass/conduit/" + shape + "_mask.png"; + + try { + BufferedImage baseImg = loadImage(basePath); + BufferedImage maskImg = loadImage(maskPath); + + if (baseImg == null || maskImg == null) return null; + + int width = baseImg.getWidth(); + int height = baseImg.getHeight(); + BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + int basePixel = baseImg.getRGB(x, y); + int maskPixel = maskImg.getRGB(x, y); + + boolean isRedstone = ((maskPixel >> 24) & 0xFF) > 128 && ((maskPixel >> 16) & 0xFF) > 128; + + if (layer.equals("emissive")) { + if (isRedstone) { + result.setRGB(x, y, (0xFF << 24) | color); + } else { + result.setRGB(x, y, 0x00000000); + } + } else { + if (isRedstone) { + result.setRGB(x, y, (0xFF << 24) | color); + } else { + result.setRGB(x, y, basePixel); + } + } + } + } + return result; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + private static BufferedImage loadImage(String path) { + try (InputStream stream = Minecraft.getMinecraft().texturePackList.getResourceAsStream(path)) { + if (stream != null) return ImageIO.read(stream); + } catch (Exception ignored) {} + return null; + } + + private static void loadPalette() { + if (palette != null) return; + palette = new int[11]; + + try { + BufferedImage img = loadImage("/assets/minecraft/textures/block/rubyglass/palette.png"); + if (img != null) { + for (int i = 0; i < 11; i++) { + int x = Math.min(i, img.getWidth() - 1); + palette[i] = img.getRGB(x, 0) & 0xFFFFFF; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/game/client/src/main/java/net/minecraft/client/render/texture/stitcher/AtlasStitcher.java b/game/client/src/main/java/net/minecraft/client/render/texture/stitcher/AtlasStitcher.java index d1c4725ca..107722067 100644 --- a/game/client/src/main/java/net/minecraft/client/render/texture/stitcher/AtlasStitcher.java +++ b/game/client/src/main/java/net/minecraft/client/render/texture/stitcher/AtlasStitcher.java @@ -229,7 +229,7 @@ public class AtlasStitcher { } BufferedImage image = CustomAtlasHandler.getTextureOverride(Minecraft.getMinecraft().texturePackList, path + ".png"); if(image == null) { - TexturePack pack = Minecraft.getMinecraft().texturePackList.getHighestPriorityTexturePackWithFile(path + ".png"); + TexturePack pack = Minecraft.getMinecraft().texturePackList.getHighestPriorityTexturePackWithFile(source + ".png"); if (pack != null) { for (int attempt = 0; attempt < 3; attempt++) { try (InputStream stream = pack.getResourceAsStream(path)) { diff --git a/game/client/src/main/java/net/minecraft/client/render/tileentity/UnusedRendererRubyglassConduit.java b/game/client/src/main/java/net/minecraft/client/render/tileentity/UnusedRendererRubyglassConduit.java new file mode 100644 index 000000000..27ca73ba7 --- /dev/null +++ b/game/client/src/main/java/net/minecraft/client/render/tileentity/UnusedRendererRubyglassConduit.java @@ -0,0 +1,280 @@ +package net.minecraft.client.render.tileentity; + +class UnusedRendererRubyglassConduit { + + /*private static final long MAGIC_PRIME_X = 3129871L; + private static final long MAGIC_PRIME_Y = 116129781L; + private long fastRandomSeed; + + public void doRender(TessellatorGeneral tessellator, TileEntityRubyglassConduit conduitTileEntity, double x, double y, double z, float partialTick) { + Player player = Minecraft.getMinecraft().thePlayer; + + if (!shouldRender(conduitTileEntity, player, partialTick)) + return; + + Side[] openSides = conduitTileEntity.openSides; + if (openSides == null || openSides.length == 0) + return; + + float powerRatio = conduitTileEntity.powerRatio; + int strength = conduitTileEntity.strength; + + // pre-calculate colors and thicknesses so it's not happening every frame + final float baseRed = 1.0f; + final float baseBlue = 0.04f + (0.2f * powerRatio); + final float baseGreen = 0.3f * powerRatio; + + final float innerGreen = Math.min(1.0f, baseGreen + 0.25f); + final float innerBlue = Math.min(1.0f, baseBlue + 0.25f); + final float coreGreen = Math.min(1.0f, baseGreen + 0.55f); + final float coreBlue = Math.min(1.0f, baseBlue + 0.55f); + + final float weakCoreGreen = coreGreen * 0.5f; + final float weakCoreBlue = coreBlue * 0.5f; + + final double baseThickness = 0.02 + (0.05 * (powerRatio * powerRatio)); + final double outerThickness = baseThickness * 3.0; + final double innerThickness = baseThickness * 1.5; + final double coreThickness = baseThickness * 0.4; + + //for corner joint connections + double coreDirectionX = 0; + double coreDirectionY = 0; + double coreDirectionZ = 0; + for (Side side : openSides) { + coreDirectionX += side.getOffsetX(); + coreDirectionY += side.getOffsetY(); + coreDirectionZ += side.getOffsetZ(); + } + + setupGL(x, y, z); + + if (conduitTileEntity.worldObj == null) return; + + this.fastRandomSeed = (conduitTileEntity.worldObj.getTotalWorldTime() / 2L) + ^ (long) conduitTileEntity.tilePos.x * MAGIC_PRIME_X + ^ (long) conduitTileEntity.tilePos.y * MAGIC_PRIME_Y + ^ (long) conduitTileEntity.tilePos.z; + + // calculate relative camera position to the block + double cameraX = player.x - conduitTileEntity.tilePos.x; + double cameraY = (player.y + player.getHeadHeight()) - conduitTileEntity.tilePos.y; + double cameraZ = player.z - conduitTileEntity.tilePos.z; + + tessellator.startDrawingQuads(); + for (Side side : openSides) { + renderBeamSide( + tessellator, side, cameraX, cameraY, cameraZ, strength, + baseRed, baseBlue, baseGreen, innerGreen, innerBlue, + coreGreen, coreBlue, weakCoreGreen, weakCoreBlue, + outerThickness, innerThickness, coreThickness, + coreDirectionX, coreDirectionY, coreDirectionZ + ); + } + tessellator.draw(); + + releaseGL(); + } + + private double nextJitterFormula(int strength) { + fastRandomSeed = (fastRandomSeed * 25214903917L + 11L) & ((1L << 48) - 1); + double baseJitter = (((double) fastRandomSeed / (1L << 48)) - 0.5) * 0.22; + + //calmer when off/weak + return strength == 0 ? baseJitter * 0.25 : baseJitter; + } + + private boolean shouldRender(TileEntityRubyglassConduit conduitTileEntity, Player player, float partialTick) { + if (player == null) return false; + + ItemStack boots = player.inventory.armorItemInSlot(HumanArmorShape.BOOTS); + if (boots == null || boots.getItem() != Blocks.BLOCK_RUBYGLASS.asItem()) + return false; + + return !shouldCull(conduitTileEntity, player, partialTick); + } + + private void setupGL(double x, double y, double z) { + GLRenderer.pushFrame(); + GLRenderer.modelM4f().translate((float) x, (float) y, (float) z); + GLRenderer.setShader(Shaders.COLOR); + GLRenderer.globalSetLightEnabled(false); + GLRenderer.enableState(State.BLEND); + GLRenderer.setBlendFunc(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA); + GLRenderer.setDepthMask(false); + } + + private void releaseGL() { + GLRenderer.setDepthMask(true); + GLRenderer.disableState(State.BLEND); + GLRenderer.globalSetLightEnabled(true); + GLRenderer.popFrame(); + } + + private void renderBeamSide( + TessellatorGeneral tessellator, + Side side, double cameraX, double cameraY, double cameraZ, + int strength, float baseRed, float baseBlue, float baseGreen, + float innerGreen, float innerBlue, float coreGreen, float coreBlue, + float weakCoreGreen, float weakCoreBlue, + double outerThickness, double innerThickness, double coreThickness, + double coreDirectionX, double coreDirectionY, double coreDirectionZ) { + + double startX = 0.5, startY = 0.5, startZ = 0.5; + double endX = 0.5 + (side.getOffsetX() * 0.5); + double endY = 0.5 + (side.getOffsetY() * 0.5); + double endZ = 0.5 + (side.getOffsetZ() * 0.5); + + int segments = 2; + int totalPoints = segments + 1; + + double[] pointX = new double[totalPoints]; + double[] pointY = new double[totalPoints]; + double[] pointZ = new double[totalPoints]; + + boolean jitterX = side.getOffsetX() == 0; + boolean jitterY = side.getOffsetY() == 0; + boolean jitterZ = side.getOffsetZ() == 0; + + // calculate coordinate points of the beam + pointX[0] = startX; + pointY[0] = startY; + pointZ[0] = startZ; + + for (int i = 1; i < segments; i++) { + double progress = i / (double) segments; + pointX[i] = startX + (endX - startX) * progress; + pointY[i] = startY + (endY - startY) * progress; + pointZ[i] = startZ + (endZ - startZ) * progress; + + if (jitterX) pointX[i] += nextJitterFormula(strength); + if (jitterY) pointY[i] += nextJitterFormula(strength); + if (jitterZ) pointZ[i] += nextJitterFormula(strength); + } + + pointX[segments] = endX; + pointY[segments] = endY; + pointZ[segments] = endZ; + + double[] rightVectorX = new double[totalPoints]; + double[] rightVectorY = new double[totalPoints]; + double[] rightVectorZ = new double[totalPoints]; + + for (int i = 0; i < totalPoints; i++) { + double directionX, directionY, directionZ; + + //joint connection + if (i == 0) { + //corners + if (coreDirectionX == 0 && coreDirectionY == 0 && coreDirectionZ == 0) { + directionX = side.getOffsetX(); + directionY = side.getOffsetY(); + directionZ = side.getOffsetZ(); + } else { + directionX = coreDirectionX; + directionY = coreDirectionY; + directionZ = coreDirectionZ; + } + } else if (i == totalPoints - 1) { + //edge of each block + directionX = side.getOffsetX(); + directionY = side.getOffsetY(); + directionZ = side.getOffsetZ(); + } else { + //between segments + directionX = pointX[i + 1] - pointX[i - 1]; + directionY = pointY[i + 1] - pointY[i - 1]; + directionZ = pointZ[i + 1] - pointZ[i - 1]; + } + + double directionLength = Math.sqrt(directionX * directionX + directionY * directionY + directionZ * directionZ); + if (directionLength != 0) { + directionX /= directionLength; + directionY /= directionLength; + directionZ /= directionLength; + } + + double toCameraX = cameraX - pointX[i]; + double toCameraY = cameraY - pointY[i]; + double toCameraZ = cameraZ - pointZ[i]; + + rightVectorX[i] = directionY * toCameraZ - directionZ * toCameraY; + rightVectorY[i] = directionZ * toCameraX - directionX * toCameraZ; + rightVectorZ[i] = directionX * toCameraY - directionY * toCameraX; + + double rightVectorLength = Math.sqrt(rightVectorX[i] * rightVectorX[i] + rightVectorY[i] * rightVectorY[i] + rightVectorZ[i] * rightVectorZ[i]); + if (rightVectorLength != 0) { + rightVectorX[i] /= rightVectorLength; + rightVectorY[i] /= rightVectorLength; + rightVectorZ[i] /= rightVectorLength; + } else { + rightVectorX[i] = 1; + rightVectorY[i] = 0; + rightVectorZ[i] = 0; + } + } + + //draw as continuous "ribbon" + if (strength != 0) { + tessellator.setColor4f(baseRed, baseGreen, baseBlue, 0.15f); + drawRibbonLayer(tessellator, pointX, pointY, pointZ, rightVectorX, rightVectorY, rightVectorZ, outerThickness); + } + + tessellator.setColor4f(baseRed, innerGreen, innerBlue, 0.4f); + drawRibbonLayer(tessellator, pointX, pointY, pointZ, rightVectorX, rightVectorY, rightVectorZ, innerThickness); + + if (strength != 0) { + tessellator.setColor4f(baseRed, coreGreen, coreBlue, 1.0f); + } else { + tessellator.setColor4f(1.0f, weakCoreGreen, weakCoreBlue, 1.0f); + } + drawRibbonLayer(tessellator, pointX, pointY, pointZ, rightVectorX, rightVectorY, rightVectorZ, coreThickness); + } + + private void drawRibbonLayer( + TessellatorGeneral tessellator, + double[] pointX, double[] pointY, double[] pointZ, + double[] rightVectorX, double[] rightVectorY, double[] rightVectorZ, + double thickness) { + + for (int i = 0; i < pointX.length - 1; i++) { + int nextIndex = i + 1; + + double currentPointX = pointX[i]; + double currentPointY = pointY[i]; + double currentPointZ = pointZ[i]; + + double currentRightOffsetX = rightVectorX[i] * thickness; + double currentRightOffsetY = rightVectorY[i] * thickness; + double currentRightOffsetZ = rightVectorZ[i] * thickness; + + double nextPointX = pointX[nextIndex]; + double nextPointY = pointY[nextIndex]; + double nextPointZ = pointZ[nextIndex]; + + double nextRightOffsetX = rightVectorX[nextIndex] * thickness; + double nextRightOffsetY = rightVectorY[nextIndex] * thickness; + double nextRightOffsetZ = rightVectorZ[nextIndex] * thickness; + + tessellator.addVertex(currentPointX + currentRightOffsetX, currentPointY + currentRightOffsetY, currentPointZ + currentRightOffsetZ); + tessellator.addVertex(nextPointX + nextRightOffsetX, nextPointY + nextRightOffsetY, nextPointZ + nextRightOffsetZ); + tessellator.addVertex(nextPointX - nextRightOffsetX, nextPointY - nextRightOffsetY, nextPointZ - nextRightOffsetZ); + tessellator.addVertex(currentPointX - currentRightOffsetX, currentPointY - currentRightOffsetY, currentPointZ - currentRightOffsetZ); + } + } + + private boolean shouldCull(TileEntityRubyglassConduit conduitTileEntity, Player player, float partialTick) { + double deltaX = (conduitTileEntity.tilePos.x + 0.5) - player.x; + double deltaY = (conduitTileEntity.tilePos.y + 0.5) - (player.y + player.getHeadHeight()); + double deltaZ = (conduitTileEntity.tilePos.z + 0.5) - player.z; + + double distanceSquared = deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ; + if (distanceSquared > 100) return true; + + Vector3dc lookVector = player.getViewVector(partialTick); + if (lookVector == null) return true; + + double dotProduct = (deltaX * lookVector.x() + deltaY * lookVector.y() + deltaZ * lookVector.z()); + return dotProduct < 0; + }*/ +} \ No newline at end of file diff --git a/game/client/src/main/java/net/minecraft/client/render/window/GameWindowGLFW.java b/game/client/src/main/java/net/minecraft/client/render/window/GameWindowGLFW.java index ce70ed33c..9cabce59c 100644 --- a/game/client/src/main/java/net/minecraft/client/render/window/GameWindowGLFW.java +++ b/game/client/src/main/java/net/minecraft/client/render/window/GameWindowGLFW.java @@ -499,6 +499,7 @@ public class GameWindowGLFW implements GameWindow { if (this.glDebugMessageCallback != null) this.glDebugMessageCallback.free(); this.stbiIconImages.forEach(STBImage::stbi_image_free); } + GLFW.glfwTerminate(); } public static class MonitorInfo { diff --git a/game/client/src/main/java/net/minecraft/client/util/helper/Colors.java b/game/client/src/main/java/net/minecraft/client/util/helper/Colors.java index baac5a316..2993e33f2 100644 --- a/game/client/src/main/java/net/minecraft/client/util/helper/Colors.java +++ b/game/client/src/main/java/net/minecraft/client/util/helper/Colors.java @@ -20,6 +20,7 @@ public abstract class Colors { public static final Color[] allFlagColors = new Color[16]; public static final Color[] allSignColors = new Color[16]; public static final Color[] allRedstoneColors = new Color[16]; + public static final Color[] allConduitColors = new Color[11]; public static final Color[] allPortalColors = new Color[16]; public static void loadDummyColors() { @@ -30,6 +31,7 @@ public abstract class Colors { Arrays.fill(allFlagColors, white); Arrays.fill(allSignColors, white); Arrays.fill(allRedstoneColors, white); + Arrays.fill(allConduitColors, white); Arrays.fill(allPortalColors, white); } @@ -40,6 +42,7 @@ public abstract class Colors { fillColorArray("/assets/minecraft/textures/misc/colors_lamps.png", allLampColors); fillColorArray("/assets/minecraft/textures/misc/colors_flag.png", allFlagColors); fillColorArray("/assets/minecraft/textures/misc/colors_redstone.png", allRedstoneColors); + fillColorArray("/assets/minecraft/textures/misc/colors_conduit.png", allConduitColors); fillColorArray("/assets/minecraft/textures/misc/colors_portal.png", allPortalColors); } diff --git a/game/client/src/main/java/net/minecraft/client/world/WorldClient.java b/game/client/src/main/java/net/minecraft/client/world/WorldClient.java index 0d935ae3a..c2bc17f4a 100644 --- a/game/client/src/main/java/net/minecraft/client/world/WorldClient.java +++ b/game/client/src/main/java/net/minecraft/client/world/WorldClient.java @@ -8,27 +8,17 @@ import net.minecraft.client.render.worldtype.WorldTypeFXDispatcher; import net.minecraft.client.world.chunk.provider.ChunkProviderDynamic; import net.minecraft.client.world.chunk.provider.ChunkProviderStatic; import net.minecraft.client.world.chunk.provider.ChunkProviderThreadedClient; -import net.minecraft.client.world.chunk.provider.ChunkProviderViewer; -import net.minecraft.core.Global; import net.minecraft.core.entity.player.Player; import net.minecraft.core.util.helper.MathHelper; 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.ChunkLoader; import net.minecraft.core.world.chunk.provider.ChunkProvider; import net.minecraft.core.world.pos.TilePos; -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.saveddata.SavedDataStorage; -import net.minecraft.core.world.season.SeasonManager; import net.minecraft.core.world.season.Seasons; import net.minecraft.core.world.settings.WorldConfiguration; -import net.minecraft.core.world.type.WorldType; -import net.minecraft.core.world.type.WorldTypes; import net.minecraft.core.world.weather.IPrecipitation; -import net.minecraft.core.world.weather.WeatherManager; import net.minecraft.core.world.weather.Weathers; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/circuit.json b/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/circuit.json deleted file mode 100644 index 84ef01a62..000000000 --- a/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/circuit.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:block/cube_all", - "textures": { - "all": "minecraft:block/rubyglass/circuit" - } -} \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_cap.json b/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_cap.json new file mode 100644 index 000000000..04f04c2a6 --- /dev/null +++ b/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_cap.json @@ -0,0 +1,40 @@ +{ + "format_version": "1.21.6", + "credit": "Made with Blockbench", + "textures": { + "closed": "minecraft:block/rubyglass/conduit/closed/closed", + "closed_overlay": "minecraft:block/rubyglass/conduit/closed/closed_overlay", + "open": "minecraft:block/rubyglass/conduit/open/open", + "open_overlay": "minecraft:block/rubyglass/conduit/open/open_overlay", + "plug": "minecraft:block/rubyglass/conduit/plug/plug", + "plug_overlay": "minecraft:block/rubyglass/conduit/plug/plug_overlay", + "particle": "minecraft:block/rubyglass/conduit/closed/closed" + }, + "elements": [ + { + "name": "Conduit Casing", + "from": [0, 0, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug", "cullface": "north"}, + "east": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug", "cullface": "east"}, + "south": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug", "cullface": "south"}, + "west": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug", "cullface": "west"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#closed", "cullface": "up"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#open", "cullface": "down"} + } + }, + { + "name": "Redstone Overlay", + "from": [0, 0, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug_overlay", "cullface": "north", "tintindex": 0, "shade": false}, + "east": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug_overlay", "cullface": "east", "tintindex": 0, "shade": false}, + "south": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug_overlay", "cullface": "south", "tintindex": 0, "shade": false}, + "west": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug_overlay", "cullface": "west", "tintindex": 0, "shade": false}, + "down": {"uv": [0, 0, 16, 16], "texture": "#open_overlay", "cullface": "down", "tintindex": 0, "shade": false} + } + } + ] +} \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_cap_off.json b/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_cap_off.json new file mode 100644 index 000000000..c823c86d8 --- /dev/null +++ b/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_cap_off.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.21.6", + "credit": "Made with Blockbench", + "textures": { + "closed": "minecraft:block/rubyglass/conduit/closed/closed", + "closed_overlay": "minecraft:block/rubyglass/conduit/closed/closed_overlay", + "open": "minecraft:block/rubyglass/conduit/open/open", + "open_overlay": "minecraft:block/rubyglass/conduit/open/open_overlay", + "plug": "minecraft:block/rubyglass/conduit/plug/plug", + "particle": "minecraft:block/rubyglass/conduit/closed/closed" + }, + "elements": [ + { + "name": "Conduit Casing", + "from": [0, 0, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug", "cullface": "north"}, + "east": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug", "cullface": "east"}, + "south": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug", "cullface": "south"}, + "west": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug", "cullface": "west"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#closed", "cullface": "up"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#open", "cullface": "down"} + } + } + ] +} \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_core.json b/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_core.json new file mode 100644 index 000000000..b3b4a9ed0 --- /dev/null +++ b/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_core.json @@ -0,0 +1,44 @@ +{ + "format_version": "1.21.6", + "credit": "Made with Blockbench", + "display": { + "gui": { "rotation": [ 30, 225, 0 ], "translation": [ 0, 0, 0 ], "scale": [ 0.625, 0.625, 0.625 ] }, + "ground": { "rotation": [ 0, 0, 0 ], "translation": [ 0, 3, 0 ], "scale": [ 0.25, 0.25, 0.25 ] }, + "fixed": { "rotation": [ 0, 0, 0 ], "translation": [ 0, 0, 0 ], "scale": [ 0.5, 0.5, 0.5 ] }, + "thirdperson_righthand": { "rotation": [ 75, 45, 0 ], "translation": [ 0, 2.5, 0 ], "scale": [ 0.375, 0.375, 0.375 ] }, + "firstperson_righthand": { "rotation": [ 0, 45, 0 ], "translation": [ 0, 0, 0 ], "scale": [ 0.4, 0.4, 0.4 ] } + }, + "textures": { + "closed": "minecraft:block/rubyglass/conduit/closed/closed", + "closed_overlay": "minecraft:block/rubyglass/conduit/closed/closed_overlay", + "particle": "minecraft:block/rubyglass/conduit/closed/closed" + }, + "elements": [ + { + "name": "Conduit Casing", + "from": [0, 0, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#closed", "cullface": "north"}, + "east": {"uv": [0, 0, 16, 16], "texture": "#closed", "cullface": "east"}, + "south": {"uv": [0, 0, 16, 16], "texture": "#closed", "cullface": "south"}, + "west": {"uv": [0, 0, 16, 16], "texture": "#closed", "cullface": "west"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#closed", "cullface": "up"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#closed", "cullface": "down"} + } + }, + { + "name": "Redstone Overlay", + "from": [0, 0, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#closed_overlay", "cullface": "north", "tintindex": 0, "shade": false}, + "east": {"uv": [0, 0, 16, 16], "texture": "#closed_overlay", "cullface": "east", "tintindex": 0, "shade": false}, + "south": {"uv": [0, 0, 16, 16], "texture": "#closed_overlay", "cullface": "south", "tintindex": 0, "shade": false}, + "west": {"uv": [0, 0, 16, 16], "texture": "#closed_overlay", "cullface": "west", "tintindex": 0, "shade": false}, + "up": {"uv": [0, 0, 16, 16], "texture": "#closed_overlay", "cullface": "up", "tintindex": 0, "shade": false}, + "down": {"uv": [0, 0, 16, 16], "texture": "#closed_overlay", "cullface": "down", "tintindex": 0, "shade": false} + } + } + ] +} \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_core_off.json b/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_core_off.json new file mode 100644 index 000000000..b84b0ad51 --- /dev/null +++ b/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_core_off.json @@ -0,0 +1,31 @@ +{ + "format_version": "1.21.6", + "credit": "Made with Blockbench", + "display": { + "gui": { "rotation": [ 30, 225, 0 ], "translation": [ 0, 0, 0 ], "scale": [ 0.625, 0.625, 0.625 ] }, + "ground": { "rotation": [ 0, 0, 0 ], "translation": [ 0, 3, 0 ], "scale": [ 0.25, 0.25, 0.25 ] }, + "fixed": { "rotation": [ 0, 0, 0 ], "translation": [ 0, 0, 0 ], "scale": [ 0.5, 0.5, 0.5 ] }, + "thirdperson_righthand": { "rotation": [ 75, 45, 0 ], "translation": [ 0, 2.5, 0 ], "scale": [ 0.375, 0.375, 0.375 ] }, + "firstperson_righthand": { "rotation": [ 0, 45, 0 ], "translation": [ 0, 0, 0 ], "scale": [ 0.4, 0.4, 0.4 ] } + }, + "textures": { + "closed": "minecraft:block/rubyglass/conduit/closed/closed", + "closed_overlay": "minecraft:block/rubyglass/conduit/closed/closed_overlay", + "particle": "minecraft:block/rubyglass/conduit/closed/closed" + }, + "elements": [ + { + "name": "Conduit Casing", + "from": [0, 0, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#closed", "cullface": "north"}, + "east": {"uv": [0, 0, 16, 16], "texture": "#closed", "cullface": "east"}, + "south": {"uv": [0, 0, 16, 16], "texture": "#closed", "cullface": "south"}, + "west": {"uv": [0, 0, 16, 16], "texture": "#closed", "cullface": "west"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#closed", "cullface": "up"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#closed", "cullface": "down"} + } + } + ] +} \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_corner.json b/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_corner.json new file mode 100644 index 000000000..70b5cc7bd --- /dev/null +++ b/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_corner.json @@ -0,0 +1,41 @@ +{ + "format_version": "1.21.6", + "credit": "Made with Blockbench", + "textures": { + "corner": "minecraft:block/rubyglass/conduit/corner/corner", + "corner_overlay": "minecraft:block/rubyglass/conduit/corner/corner_overlay", + "open": "minecraft:block/rubyglass/conduit/open/open", + "open_overlay": "minecraft:block/rubyglass/conduit/open/open_overlay", + "plug": "minecraft:block/rubyglass/conduit/plug/plug", + "plug_overlay": "minecraft:block/rubyglass/conduit/plug/plug_overlay", + "particle": "minecraft:block/rubyglass/conduit/closed/closed" + }, + "elements": [ + { + "name": "Conduit Casing", + "from": [0, 0, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#open", "cullface": "north"}, + "east": {"uv": [0, 0, 16, 16], "texture": "#corner", "cullface": "east"}, + "south": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug", "cullface": "south"}, + "west": {"uv": [16, 0, 0, 16], "texture": "#corner", "cullface": "west"}, + "up": {"uv": [0, 0, 16, 16], "rotation": 90, "texture": "#plug", "cullface": "up"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#open", "cullface": "down"} + } + }, + { + "name": "Redstone Overlay", + "from": [0, 0, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#open_overlay", "cullface": "north", "tintindex": 0, "shade": false}, + "east": {"uv": [0, 0, 16, 16], "texture": "#corner_overlay", "cullface": "east", "tintindex": 0, "shade": false}, + "south": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug_overlay", "cullface": "south", "tintindex": 0, "shade": false}, + "west": {"uv": [16, 0, 0, 16], "texture": "#corner_overlay", "cullface": "west", "tintindex": 0, "shade": false}, + "up": {"uv": [0, 0, 16, 16], "rotation": 90, "texture": "#plug_overlay", "cullface": "up", "tintindex": 0, "shade": false}, + "down": {"uv": [0, 0, 16, 16], "texture": "#open_overlay", "cullface": "down", "tintindex": 0, "shade": false} + } + } + ] +} \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_corner_off.json b/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_corner_off.json new file mode 100644 index 000000000..2c6590b5b --- /dev/null +++ b/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_corner_off.json @@ -0,0 +1,28 @@ +{ + "format_version": "1.21.6", + "credit": "Made with Blockbench", + "textures": { + "corner": "minecraft:block/rubyglass/conduit/corner/corner", + "corner_overlay": "minecraft:block/rubyglass/conduit/corner/corner_overlay", + "open": "minecraft:block/rubyglass/conduit/open/open", + "open_overlay": "minecraft:block/rubyglass/conduit/open/open_overlay", + "plug": "minecraft:block/rubyglass/conduit/plug/plug", + "plug_overlay": "minecraft:block/rubyglass/conduit/plug/plug_overlay", + "particle": "minecraft:block/rubyglass/conduit/closed/closed" + }, + "elements": [ + { + "name": "Conduit Casing", + "from": [0, 0, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#open", "cullface": "north"}, + "east": {"uv": [0, 0, 16, 16], "texture": "#corner", "cullface": "east"}, + "south": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug", "cullface": "south"}, + "west": {"uv": [16, 0, 0, 16], "texture": "#corner", "cullface": "west"}, + "up": {"uv": [0, 0, 16, 16], "rotation": 90, "texture": "#plug", "cullface": "up"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#open", "cullface": "down"} + } + } + ] +} \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_straight.json b/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_straight.json new file mode 100644 index 000000000..b10f4b890 --- /dev/null +++ b/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_straight.json @@ -0,0 +1,39 @@ +{ + "format_version": "1.21.6", + "credit": "Made with Blockbench", + "textures": { + "open": "minecraft:block/rubyglass/conduit/open/open", + "open_overlay": "minecraft:block/rubyglass/conduit/open/open_overlay", + "straight": "minecraft:block/rubyglass/conduit/straight/straight", + "straight_overlay": "minecraft:block/rubyglass/conduit/straight/straight_overlay", + "particle": "minecraft:block/rubyglass/conduit/closed/closed" + }, + "elements": [ + { + "name": "Conduit Casing", + "from": [0, 0, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 16], "rotation": 90, "texture": "#straight", "cullface": "north"}, + "east": {"uv": [0, 0, 16, 16], "rotation": 90, "texture": "#straight", "cullface": "east"}, + "south": {"uv": [0, 0, 16, 16], "rotation": 90, "texture": "#straight", "cullface": "south"}, + "west": {"uv": [0, 0, 16, 16], "rotation": 90, "texture": "#straight", "cullface": "west"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#open", "cullface": "up"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#open", "cullface": "down"} + } + }, + { + "name": "Redstone Overlay", + "from": [0, 0, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 16], "rotation": 90, "texture": "#straight_overlay", "cullface": "north", "tintindex": 0, "shade": false}, + "east": {"uv": [0, 0, 16, 16], "rotation": 90, "texture": "#straight_overlay", "cullface": "east", "tintindex": 0, "shade": false}, + "south": {"uv": [0, 0, 16, 16], "rotation": 90, "texture": "#straight_overlay", "cullface": "south", "tintindex": 0, "shade": false}, + "west": {"uv": [0, 0, 16, 16], "rotation": 90, "texture": "#straight_overlay", "cullface": "west", "tintindex": 0, "shade": false}, + "up": {"uv": [0, 0, 16, 16], "texture": "#open_overlay", "cullface": "up", "tintindex": 0, "shade": false}, + "down": {"uv": [0, 0, 16, 16], "texture": "#open_overlay", "cullface": "down", "tintindex": 0, "shade": false} + } + } + ] +} \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_straight_off.json b/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_straight_off.json new file mode 100644 index 000000000..f2cd1b03d --- /dev/null +++ b/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_straight_off.json @@ -0,0 +1,26 @@ +{ + "format_version": "1.21.6", + "credit": "Made with Blockbench", + "textures": { + "open": "minecraft:block/rubyglass/conduit/open/open", + "open_overlay": "minecraft:block/rubyglass/conduit/open/open_overlay", + "straight": "minecraft:block/rubyglass/conduit/straight/straight", + "straight_overlay": "minecraft:block/rubyglass/conduit/straight/straight_overlay", + "particle": "minecraft:block/rubyglass/conduit/closed/closed" + }, + "elements": [ + { + "name": "Conduit Casing", + "from": [0, 0, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 16], "rotation": 90, "texture": "#straight", "cullface": "north"}, + "east": {"uv": [0, 0, 16, 16], "rotation": 90, "texture": "#straight", "cullface": "east"}, + "south": {"uv": [0, 0, 16, 16], "rotation": 90, "texture": "#straight", "cullface": "south"}, + "west": {"uv": [0, 0, 16, 16], "rotation": 90, "texture": "#straight", "cullface": "west"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#open", "cullface": "up"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#open", "cullface": "down"} + } + } + ] +} \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/circuit.emiss.png b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/circuit.emiss.png deleted file mode 100644 index 4e1cbce88..000000000 Binary files a/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/circuit.emiss.png and /dev/null differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/circuit.png b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/circuit.png deleted file mode 100644 index 2e0638446..000000000 Binary files a/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/circuit.png and /dev/null differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/closed/closed.png b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/closed/closed.png new file mode 100644 index 000000000..6ee6ba2f1 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/closed/closed.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/closed/closed_overlay.emiss.png b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/closed/closed_overlay.emiss.png new file mode 100644 index 000000000..73b5ded4c Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/closed/closed_overlay.emiss.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/closed/closed_overlay.png b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/closed/closed_overlay.png new file mode 100644 index 000000000..21861dd34 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/closed/closed_overlay.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/corner/corner.png b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/corner/corner.png new file mode 100644 index 000000000..e53199bca Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/corner/corner.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/corner/corner_overlay.emiss.png b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/corner/corner_overlay.emiss.png new file mode 100644 index 000000000..256713ea1 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/corner/corner_overlay.emiss.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/corner/corner_overlay.png b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/corner/corner_overlay.png new file mode 100644 index 000000000..9c26af9cc Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/corner/corner_overlay.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/open/open.png b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/open/open.png new file mode 100644 index 000000000..29d057355 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/open/open.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/open/open_overlay.emiss.png b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/open/open_overlay.emiss.png new file mode 100644 index 000000000..a58287878 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/open/open_overlay.emiss.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/open/open_overlay.png b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/open/open_overlay.png new file mode 100644 index 000000000..4558bfef0 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/open/open_overlay.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/plug/plug.png b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/plug/plug.png new file mode 100644 index 000000000..996d2a5b2 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/plug/plug.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/plug/plug_overlay.emiss.png b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/plug/plug_overlay.emiss.png new file mode 100644 index 000000000..b87b4713f Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/plug/plug_overlay.emiss.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/plug/plug_overlay.png b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/plug/plug_overlay.png new file mode 100644 index 000000000..63f0acae3 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/plug/plug_overlay.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/straight/straight.png b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/straight/straight.png new file mode 100644 index 000000000..39bdded55 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/straight/straight.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/straight/straight_overlay.emiss.png b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/straight/straight_overlay.emiss.png new file mode 100644 index 000000000..08574d449 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/straight/straight_overlay.emiss.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/straight/straight_overlay.png b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/straight/straight_overlay.png new file mode 100644 index 000000000..a072df79a Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/block/rubyglass/conduit/straight/straight_overlay.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket.png deleted file mode 100644 index 13e9d12b4..000000000 Binary files a/game/client/src/main/resources/assets/minecraft/textures/item/bucket.png and /dev/null differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_icecream.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_icecream.png deleted file mode 100644 index 1d0d4619e..000000000 Binary files a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_icecream.png and /dev/null differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_iron/empty.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_iron/empty.png new file mode 100644 index 000000000..2f85139e7 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_iron/empty.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_iron/icecream_1.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_iron/icecream_1.png new file mode 100644 index 000000000..9460a1678 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_iron/icecream_1.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_iron/lava_1.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_iron/lava_1.png new file mode 100644 index 000000000..64e5b5bfc Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_iron/lava_1.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_iron/milk_1.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_iron/milk_1.png new file mode 100644 index 000000000..a5cda20b6 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_iron/milk_1.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_iron/water_1.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_iron/water_1.png new file mode 100644 index 000000000..565b495a7 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_iron/water_1.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_lava.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_lava.png deleted file mode 100644 index 6d3d261ef..000000000 Binary files a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_lava.png and /dev/null differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_milk.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_milk.png deleted file mode 100644 index 05a47069c..000000000 Binary files a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_milk.png and /dev/null differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/empty.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/empty.png new file mode 100644 index 000000000..e6bf60ca8 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/empty.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/icecream_1.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/icecream_1.png new file mode 100644 index 000000000..ace144950 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/icecream_1.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/icecream_2.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/icecream_2.png new file mode 100644 index 000000000..eeed898a0 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/icecream_2.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/icecream_3.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/icecream_3.png new file mode 100644 index 000000000..099ba0503 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/icecream_3.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/lava_1.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/lava_1.png new file mode 100644 index 000000000..8d24f4717 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/lava_1.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/lava_2.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/lava_2.png new file mode 100644 index 000000000..d2fcd159d Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/lava_2.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/lava_3.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/lava_3.png new file mode 100644 index 000000000..2b765f2a6 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/lava_3.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/milk_1.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/milk_1.png new file mode 100644 index 000000000..a7d88514c Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/milk_1.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/milk_2.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/milk_2.png new file mode 100644 index 000000000..2ba8cbd29 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/milk_2.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/milk_3.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/milk_3.png new file mode 100644 index 000000000..f695e6d4b Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/milk_3.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/water_1.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/water_1.png new file mode 100644 index 000000000..d1ab77267 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/water_1.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/water_2.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/water_2.png new file mode 100644 index 000000000..f5266e3ef Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/water_2.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/water_3.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/water_3.png new file mode 100644 index 000000000..ddf5f7bc5 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_steel/water_3.png differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_water.png b/game/client/src/main/resources/assets/minecraft/textures/item/bucket_water.png deleted file mode 100644 index 5cbaaba54..000000000 Binary files a/game/client/src/main/resources/assets/minecraft/textures/item/bucket_water.png and /dev/null differ diff --git a/game/client/src/main/resources/assets/minecraft/textures/misc/colors_conduit.png b/game/client/src/main/resources/assets/minecraft/textures/misc/colors_conduit.png new file mode 100644 index 000000000..5f2489fb5 Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/misc/colors_conduit.png differ diff --git a/game/core/src/main/java/net/minecraft/core/achievement/Achievement.java b/game/core/src/main/java/net/minecraft/core/achievement/Achievement.java index 2783692d9..fbddff06b 100644 --- a/game/core/src/main/java/net/minecraft/core/achievement/Achievement.java +++ b/game/core/src/main/java/net/minecraft/core/achievement/Achievement.java @@ -3,6 +3,7 @@ package net.minecraft.core.achievement; import net.minecraft.core.achievement.stat.StatDescFormatter; import net.minecraft.core.achievement.stat.Stat; import net.minecraft.core.item.IItemConvertible; +import net.minecraft.core.item.ItemStack; import net.minecraft.core.lang.I18n; import net.minecraft.core.util.collection.NamespaceID; @@ -17,21 +18,20 @@ public class Achievement extends Stat private StatDescFormatter statStringFormatter; public final int iconItemId; private Type type = TYPE_NORMAL; + public final ItemStack iconStack; - public Achievement(NamespaceID id, String name, IItemConvertible icon, Achievement parent) - { - this(id, name, icon.asItem().id, parent); - } - - public Achievement(NamespaceID id, String name, int iconItemId, Achievement parent) - { + public Achievement(NamespaceID id, String name, ItemStack icon, Achievement parent) { super(NamespaceID.fromPool(id.namespace(), "achievement/" + id.value()), "achievement." + name); - this.iconItemId = iconItemId; + this.iconStack = icon; + this.iconItemId = icon.itemID; this.description = "achievement." + name; - this.parent = parent; } + public Achievement(NamespaceID id, String name, IItemConvertible icon, Achievement parent) { + this(id, name, new ItemStack(icon), parent); + } + public Achievement setClientsideAchievement() { clientside = true; return this; diff --git a/game/core/src/main/java/net/minecraft/core/achievement/Achievements.java b/game/core/src/main/java/net/minecraft/core/achievement/Achievements.java index e72e72249..1fa32fe63 100644 --- a/game/core/src/main/java/net/minecraft/core/achievement/Achievements.java +++ b/game/core/src/main/java/net/minecraft/core/achievement/Achievements.java @@ -1,6 +1,7 @@ package net.minecraft.core.achievement; import net.minecraft.core.block.Blocks; +import net.minecraft.core.item.ItemBucket; import net.minecraft.core.item.Items; import net.minecraft.core.util.collection.NamespaceID; @@ -45,7 +46,7 @@ public abstract class Achievements new Achievement(NamespaceID.fromPool("minecraft", "bake_cake"), "bakeCake", Items.FOOD_CAKE, BUILD_HOE) .registerAchievement(); public static Achievement CRAFT_ICECREAM = - new Achievement(NamespaceID.fromPool("minecraft", "craft_icecream"), "craftIcecream", Items.BUCKET_ICECREAM, BUILD_HOE) + new Achievement(NamespaceID.fromPool("minecraft", "craft_icecream"), "craftIcecream", ItemBucket.createItemStack(Items.BUCKET_IRON, ItemBucket.STATE_ICECREAM, 1), BUILD_HOE) .registerAchievement(); public static Achievement CRAFT_PUMPKIN_PIE = new Achievement(NamespaceID.fromPool("minecraft", "craft_pumpkin_pie"), "craftPumpkinPie", Items.FOOD_PUMPKIN_PIE, BUILD_HOE) 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 c273b10ea..46c4fb18b 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 @@ -18,6 +18,8 @@ import org.jetbrains.annotations.Nullable; import java.util.Objects; import java.util.Random; +import static net.minecraft.core.block.BlockLogicRubyglassConduit.packEventConduitData; + public class BlockLogicActivator extends BlockLogicVeryRotatable { public static final int MASK_POWERED = 0b0000_1000; @@ -86,6 +88,13 @@ public class BlockLogicActivator } } + @Override + public void animationTick(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Random rand) { + final int meta = world.getBlockData(tilePos); + if ((meta & MASK_POWERED) == 0) {return;} + world.playBlockEvent(tilePos, LevelListener.EVENT_CONDUIT_SURFACE_PARTICLES, packEventConduitData(null, 10)); + } + @Override public void updateTick(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Random rand, final boolean isRandomTick) { this.useItem(world, tilePos, rand); diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java index 0d8bbaf2c..f64634037 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java @@ -181,8 +181,8 @@ public abstract class BlockLogicFluid extends BlockLogic { return null; } - protected static void fizz(final @NotNull World world, @NotNull TilePosc tilePos) { - world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, (float) tilePos.x() + 0.5F, (float) tilePos.y() + 0.5F, (float) tilePos.z() + 0.5F, "random.fizz", 0.5F, 2.6F + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.8F); + public static void fizz(final @NotNull World world, @NotNull TilePosc tilePos) { + world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, (float) tilePos.x() + 0.5F, (float) tilePos.y() + 0.5F, (float) tilePos.z() + 0.5F, "random.fizz", 1F, 2.6F + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.8F); for (int i = 0; i < 8; i++) { world.spawnParticle("largesmoke", (double) tilePos.x() + Math.random(), (double) tilePos.y() + 1.2D, (double) tilePos.z() + Math.random(), 0.0D, 0.0D, 0.0D, 0, 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 365d71345..01794530b 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 @@ -133,4 +133,15 @@ public class BlockLogicLamp extends BlockLogic implements IPainted { public void removeDye(@NotNull World world, @NotNull TilePosc tilePos) { world.setBlockDataNotify(tilePos, 0); } + + @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; + } + + return false; + } } \ No newline at end of file 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 39aef4bda..852fcacc4 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 @@ -9,6 +9,7 @@ import net.minecraft.core.item.ItemStack; import net.minecraft.core.util.helper.Axis; import net.minecraft.core.util.helper.Direction; import net.minecraft.core.util.helper.Side; +import net.minecraft.core.world.LevelListener; import net.minecraft.core.world.World; import net.minecraft.core.world.WorldSource; import net.minecraft.core.world.pos.TilePos; @@ -18,6 +19,9 @@ import org.jetbrains.annotations.Nullable; import java.util.Random; +import static net.minecraft.core.block.BlockLogicFarmland.isWet; +import static net.minecraft.core.block.BlockLogicRubyglassConduit.packEventConduitData; + public class BlockLogicMatcher extends BlockLogicAxisAligned { public final boolean isActive; @@ -85,11 +89,7 @@ public class BlockLogicMatcher extends BlockLogicAxisAligned { boolean backMatchesFront; Block fBlock = world.getBlockType(front); - if (fBlock == null) { - backMatchesFront = world.getBlockType(back) == null; - } else { - backMatchesFront = fBlock.isEquivalent(world, front, back); - } + backMatchesFront = fBlock.isEquivalent(world, front, back); if (!this.isActive && backMatchesFront) { world.setBlockTypeDataNotify(tilePos, Blocks.MATCHER_ACTIVE, world.getBlockData(tilePos)); @@ -100,33 +100,8 @@ public class BlockLogicMatcher extends BlockLogicAxisAligned { @Override public void animationTick(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Random rand) { - if (!this.isActive) { - return; - } - - final int brightness = 10; - double d = 0.0625; - for (int i = 0; i < Direction.directions.length; i++) { - Direction dir = Direction.directions[i]; - double px = (double) tilePos.x() + rand.nextFloat(); - double py = (double) tilePos.y() + rand.nextFloat(); - double pz = (double) tilePos.z() + rand.nextFloat(); - - if (!world.isBlockOpaqueCube(tilePos.add(dir, new TilePos()))) { - switch (dir) { - case UP -> py = (tilePos.y() + 1) + d; - case DOWN -> py = (tilePos.y()) - d; - case SOUTH -> pz = (tilePos.z() + 1) + d; - case NORTH -> pz = (tilePos.z()) - d; - case EAST -> px = (tilePos.x() + 1) + d; - case WEST -> px = (tilePos.x()) - d; - } - } - - if (px < tilePos.x() || px > (tilePos.x() + 1) || py < 0.0D || py > (tilePos.y() + 1) || pz < tilePos.z() || pz > (tilePos.z() + 1)) { - world.spawnParticle("reddust", px, py, pz, 0, 0, 0, brightness, false); - } - } + if (!this.isActive) {return;} + world.playBlockEvent(tilePos, LevelListener.EVENT_CONDUIT_SURFACE_PARTICLES, packEventConduitData(null, 10)); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassConduit.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassConduit.java new file mode 100644 index 000000000..8e527e43f --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassConduit.java @@ -0,0 +1,490 @@ +package net.minecraft.core.block; + +import net.minecraft.core.block.material.Material; +import net.minecraft.core.entity.Mob; +import net.minecraft.core.entity.player.Player; +import net.minecraft.core.sound.SoundCategory; +import net.minecraft.core.util.helper.Direction; +import net.minecraft.core.util.helper.Side; +import net.minecraft.core.world.LevelListener; +import net.minecraft.core.world.World; +import net.minecraft.core.world.WorldSource; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class BlockLogicRubyglassConduit extends BlockLogic { + + public static final Side[][] STATE_TABLE = { + {}, // 0 + {Side.BOTTOM}, {Side.TOP}, // 1-2 + {Side.NORTH}, {Side.SOUTH}, // 3-4 + {Side.WEST}, {Side.EAST}, // 5-6 + + {Side.BOTTOM, Side.TOP}, // 7 Y-Axis + {Side.NORTH, Side.SOUTH}, // 8 Z-Axis + {Side.WEST, Side.EAST}, // 9 X-Axis + + {Side.BOTTOM, Side.NORTH}, {Side.BOTTOM, Side.SOUTH}, // 10-11 + {Side.BOTTOM, Side.WEST}, {Side.BOTTOM, Side.EAST}, // 12-13 + {Side.TOP, Side.NORTH}, {Side.TOP, Side.SOUTH}, // 14-15 + {Side.TOP, Side.WEST}, {Side.TOP, Side.EAST}, // 16-17 + {Side.NORTH, Side.WEST}, {Side.NORTH, Side.EAST}, // 18-19 + {Side.SOUTH, Side.WEST}, {Side.SOUTH, Side.EAST} // 20-21 + }; + + //PROPAGATION_LENGTH can ONLY BE A MAXIMUM OF 10. Anymore and the data will become mangled. + //if changed after implementation, data of existing conduits will become mangled without a converter. + //TODO There are a couple of hardcoded segments of code that do not account for PROPAGATION_LENGTH + private static final int PROPAGATION_LENGTH = 10; + public static final int STATE_COUNT = 22; + + public BlockLogicRubyglassConduit(@NotNull Block block, @NotNull Material material) { + super(block, material); + } + + @Override + public int tickDelay() { + return 0; + } + + @Override + public void updateTick(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Random rand, final boolean isRandomTick) { + onNeighborChanged(world, tilePos, this.block); + } + + @Override + public void animationTick(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Random rand) { + int data = world.getBlockData(tilePos); + int strength = data / STATE_COUNT; + + if (strength > 0) { + world.playBlockEvent(tilePos, LevelListener.EVENT_CONDUIT_SURFACE_PARTICLES, packEventConduitData(Side.NONE, strength)); + } + } + + @Override + public boolean isSolidRender() { + return false; + } + + @Override + public boolean isCubeShaped() { + return false; + } + + @Override + public boolean isSignalSource() {return true;} + + @Override + public void onNeighborChanged(final @NotNull World world, final @NotNull TilePosc cTilePos, final @NotNull Block block) { + if (world.isClientSide) return; + world.getConduitHandler().onConduitUpdated(cTilePos); + } + + @Override + public void onPlacedByWorld(@NotNull World world, @NotNull TilePosc tilePos) { + super.onPlacedByWorld(world, tilePos); + if (!world.isClientSide) { + world.getConduitHandler().onConduitAdded(tilePos); + } + } + + @Override + public void onRemoved(@NotNull World world, @NotNull TilePosc tilePos, int data) { + super.onRemoved(world, tilePos, data); + if (!world.isClientSide) { + world.getConduitHandler().onConduitRemoved(tilePos, data); + } + } + + + /** + * Defines the placement and routing behavior of the conduit when placed into the world by an entity. + *

+ * This method handles two distinct placement modes: + *

    + *
  • Sneaking (Manual Placement): Bypasses auto-connection. If placed against a closed conduit port, + * it will force that port open and connect to it. Otherwise, it defaults to routing a connection from the + * clicked block face toward the placing entity.
  • + *
  • Standard (Auto-connection): Scans adjacent blocks for valid, open conduit ports. + *
      + *
    • 1 Valid Neighbor: Routes from the neighbor toward the entity.
    • + *
    • 2 Valid Neighbors: Creates a straight or corner connection linking both neighbors.
    • + *
    • 3+ Valid Neighbors: Defaults to routing from the block placed against toward the entity.
    • + *
    + *
  • + *
+ * @param world World the block is being placed in. + * @param cTilePos The position where this new conduit is being placed. + * @param sidePlacedOnto The face of the existing block that the entity clicked against to place this block. + * @param mob The entity (usually a Player) placing the block. + * @param xHit The X coordinate of the cursor hit on the block face. + * @param yHit The Y coordinate of the cursor hit on the block face. + */ + @Override + public void onPlacedByMob(final @NotNull World world, final @NotNull TilePosc cTilePos, final @NotNull Side sidePlacedOnto, final @NotNull Mob mob, final double xHit, final double yHit) { + Side sideFacingPlayer = Direction.getDirection(mob).getOpposite().getSide(); + Side sideClickedAgainst = sidePlacedOnto.getOpposite(); + + int stateToPlaceAs = 0; + if (mob.isSneaking()) { + boolean openedClosedFace = false; + TilePos clickedPos = new TilePos(cTilePos.x() + sideClickedAgainst.getOffsetX(), cTilePos.y() + sideClickedAgainst.getOffsetY(), cTilePos.z() + sideClickedAgainst.getOffsetZ()); + + if (world.getBlockType(clickedPos) == this.block) { + int clickedData = world.getBlockData(clickedPos); + + if (!isSideOpen(clickedData, sidePlacedOnto)) { + int clickedState = clickedData % STATE_COUNT; + int clickedStrength = clickedData / STATE_COUNT; + int newClickedState = getNextState(clickedState, sidePlacedOnto); + + if (newClickedState != clickedState) { + world.setBlockDataNotify(clickedPos, clickedStrength * STATE_COUNT + newClickedState); + this.onNeighborChanged(world, clickedPos, this.block); + openedClosedFace = true; + } + + } + } + + if (openedClosedFace) { + stateToPlaceAs = getNextState(0, sideClickedAgainst); + } else { + if (sideClickedAgainst != sideFacingPlayer && sideFacingPlayer != Side.NONE) { + stateToPlaceAs = getStateFromTwoSides(sideClickedAgainst, sideFacingPlayer); + } else { + stateToPlaceAs = getNextState(0, sideClickedAgainst); + } + } + } + else { + List validSides = new ArrayList<>(); + + for (Side side : Side.values()) { + TilePos nTilePos = new TilePos(cTilePos.x() + side.getOffsetX(), cTilePos.y() + side.getOffsetY(), cTilePos.z() + side.getOffsetZ()); + + if (world.getBlockType(nTilePos) == this.block) { + int nData = world.getBlockData(nTilePos); + + if (isSideOpen(nData, side.getOpposite())) { + validSides.add(side); + } + } + } + + int numOfValidSides = validSides.size(); + + if (numOfValidSides == 1) { + Side autoConnectedSide = validSides.get(0); + + if (sideFacingPlayer != autoConnectedSide && sideFacingPlayer != Side.NONE) { + stateToPlaceAs = getStateFromTwoSides(autoConnectedSide, sideFacingPlayer); + } else { + stateToPlaceAs = getNextState(0, autoConnectedSide); + } + } else if (numOfValidSides == 2) { + stateToPlaceAs = getStateFromTwoSides(validSides.get(0), validSides.get(1)); + } else if (numOfValidSides > 2) { + TilePos nTilePos = new TilePos(cTilePos).add(sideClickedAgainst); + + boolean isMatchingNeighbor = world.getBlockType(nTilePos) == this.block; + boolean isNeighborSideOpen = isSideOpen(world.getBlockData(nTilePos), sidePlacedOnto); + + if (isMatchingNeighbor && isNeighborSideOpen) { + if (sideFacingPlayer != sideClickedAgainst && sideFacingPlayer != Side.NONE) { + stateToPlaceAs = getStateFromTwoSides(sideClickedAgainst, sideFacingPlayer); + } else { + stateToPlaceAs = getNextState(0, sideClickedAgainst); + } + } + } + } + + if (stateToPlaceAs != 0) { + world.setBlockDataNotify(cTilePos, stateToPlaceAs); + this.onNeighborChanged(world, cTilePos, this.block); + } + } + + + /** + * Handles right-click interactions with an existing conduit in the world. + *

+ * This method controls the manual toggling of conduit connection ports. The interaction succeeds + * and toggles the port state under the following conditions: + *

    + *
  • The player is holding nothing (empty hand).
  • + *
  • The player is holding another conduit, but clicks on a closed port.
  • + *
+ *

+ * If the player is holding a different block/item, or holding a conduit and clicks an open port, + * this method yields the interaction to allow standard block placement or item usage. + *

+ * Successful interactions will update the block state, trigger neighbor updates, play activation + * sound effects, and spawn visual port particles. + * @param world The world containing the block. + * @param cTilePos The position of the conduit being interacted with. + * @param player The player interacting with the block. + * @param side The specific face of the conduit that was clicked (can be null if interacted via indirect means). + * @param xHit The precise X coordinate of the cursor hit on the block face. + * @param yHit The precise Y coordinate of the cursor hit on the block face. + * @return {@code true} if the interaction was consumed (port toggled); {@code false} if the interaction + * should pass through to default item/block placement logic. + */ + @Override + public boolean onInteracted(final @NotNull World world, final @NotNull TilePosc cTilePos, final @NotNull Player player, final @Nullable Side side, final double xHit, final double yHit) { + if(side == null) return false; + + boolean holdingNothing = player.getHeldItem() == null; + boolean holdingConduit = !holdingNothing && player.getHeldItem().itemID == this.block.id(); + + if (!holdingNothing && !holdingConduit) { + return false; + } + + int cData = world.getBlockData(cTilePos); + + if (holdingConduit && isSideOpen(cData, side)) { + return false; + } + + int cState = cData % STATE_COUNT; + int cStrength = cData / STATE_COUNT; + + int nextState = getNextState(cState, side); + + if (nextState != cState) { + world.setBlockDataNotify(cTilePos, cStrength * STATE_COUNT + nextState); + onNeighborChanged(world, cTilePos, this.block); + + world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, cTilePos.x(), cTilePos.y(), cTilePos.z(), "tile.activator.use", 1, 1.2f); + world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, cTilePos.x(), cTilePos.y(), cTilePos.z(), "note.hat", 0.7f, 0.4f); + world.playBlockEvent(cTilePos, LevelListener.EVENT_CONDUIT_PORT_PARTICLES, packEventConduitData(side, cStrength)); + + return true; + } + + return false; + } + + public static byte packEventConduitData(Side side, int strength) { + if (side == null) side = Side.NONE; + int s = Math.max(0, Math.min(10, strength)); + int sideId = side.getId() & 0x07; + return (byte) ((sideId << 4) | (s & 0x0F)); + } + + @Override + public boolean isEmittingSignal(final @NotNull WorldSource world, final @NotNull TilePosc tilePos, final @NotNull Side side) { + int data = world.getBlockData(tilePos); + int currentPower = data / STATE_COUNT; + + if (currentPower == 0) { + return false; + } + + //can only emit signal out of an open face + Side conduitFace = side.getOpposite(); + return isSideOpen(data, conduitFace); + } + + @Override + public boolean isEmittingDirectSignal(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side) { + int data = world.getBlockData(tilePos); + int currentPower = data / STATE_COUNT; + + if (currentPower == 0) { + return false; + } + + //can only emit signal out of an open face + Side conduitFace = side.getOpposite(); + return isSideOpen(data, conduitFace); + } + + + /** + * Dynamically determines the next state of a conduit based on a queried side (interacted with, placed against, trying to connect to). + * @param currentState The current state of the conduit + * @param sideQueried The side that was queried. + * @return The new conduit state based on the interaction + */ + private int getNextState(int currentState, @NotNull Side sideQueried) { + Side[] nestState = STATE_TABLE[currentState]; + + for (Side side : nestState) { + if (side == sideQueried) { + if (nestState.length == 1) return 0; + Side remainingSide = (nestState[0] == sideQueried) ? nestState[1] : nestState[0]; + return remainingSide.getId() + 1; + } + } + + if (nestState.length == 0) { + return sideQueried.getId() + 1; + } + else if (nestState.length == 1) { + return getStateFromTwoSides(nestState[0], sideQueried); + } + + return currentState; + } + + /** + * Determines a state that contains the two provided sides. + * @param s1 The first open side + * @param s2 The second open side + * @return The conduit state that matches the two side parameters or 0 if no match is found + */ + private int getStateFromTwoSides(@NotNull Side s1, @NotNull Side s2) { + for (int i = 7; i < STATE_TABLE.length; i++) { + Side[] pair = STATE_TABLE[i]; + + boolean match1 = (pair[0] == s1 || pair[1] == s1); + boolean match2 = (pair[0] == s2 || pair[1] == s2); + + if (match1 && match2) { + return i; + } + } + return 0; + } + + + + /** + * Determines the incoming signal strength from a neighboring block on any given side of the conduit and converts it.

+ * n = neighbor (ex. nTilePos = neighboring blocks TilePos)
+ * c = conduit (ex. cStrength = this conduit Signal Strength)
+ * @param world The world + * @param cTilePos The position of the conduit + * @param side The side to check + * @return A converted signal value from 0 to 7 + */ + public static int getAndConvertNeighborSignal(@NotNull WorldSource world, @NotNull TilePosc cTilePos, @NotNull Side side) { + + TilePos nTilePos = new TilePos(cTilePos.x() + side.getOffsetX(), cTilePos.y() + side.getOffsetY(), cTilePos.z() + side.getOffsetZ()); + Block nBlockType = world.getBlockType(nTilePos); + + int cStrength = world.getBlockData(cTilePos) / STATE_COUNT; + + if(nBlockType == Blocks.WIRE_REDSTONE) { + int nData = world.getBlockData(nTilePos); + int nStrength = nData & BlockLogicWireRedstone.MASK_POWER; + return signalConverter(nStrength, false); + } + + if (nBlockType == Blocks.RUBYGLASS_CONDUIT) { + int nData = world.getBlockData(nTilePos); + if (isSideOpen(nData, side.getOpposite())) { + int nStrength = nData / STATE_COUNT; + + if (nStrength <= cStrength) return 0; + + return nStrength - 1; + } + return 0; + } + + if (world instanceof World world1) { + + boolean isPowerCube = nBlockType == + Blocks.BLOCK_REDSTONE || + nBlockType == Blocks.PUMPKIN_REDSTONE || + nBlockType == Blocks.MATCHER_ACTIVE; + + if (world1.isBlockNormalCube(nTilePos) && !isPowerCube) { + for (Side s : Side.sides) { + TilePos queryPos = new TilePos(nTilePos.x() + s.getOffsetX(), nTilePos.y() + s.getOffsetY(), nTilePos.z() + s.getOffsetZ()); + Block queryBlock = world1.getBlockType(queryPos); + + if (queryBlock != Blocks.WIRE_REDSTONE && queryBlock != Blocks.RUBYGLASS_CONDUIT) { + if (queryBlock.isEmittingDirectSignal(world1, queryPos, s)) { + return PROPAGATION_LENGTH; + } + } + } + } else { + if (nBlockType.isEmittingSignal(world1, nTilePos, side)) { + return PROPAGATION_LENGTH; + } + } + } else { + if (nBlockType.isSignalSource() && nBlockType.isEmittingSignal(world, nTilePos, side)) { + return PROPAGATION_LENGTH; + } + } + return 0; + } + + /** + * Determines a conduit power level output toward a given side, or 0 if that side is closed.
+ * c = conduit (ex. cStrength = this conduit Signal Strength)
+ * @param cData The metadata of the conduit. + * @param sideTowardReceiver The side of the conduit facing the block asking for power. + * @return Conduit power (0-{@link #PROPAGATION_LENGTH}) + */ + public static int getOutputPower(int cData, @NotNull Side sideTowardReceiver) { + return isSideOpen(cData, sideTowardReceiver) ? cData / STATE_COUNT : 0; + } + + /** + * Determines if a specific side on a conduit is open.
+ * c = conduit (ex. cStrength = this conduit Signal Strength)
+ * @param cData The metadata of the conduit to check. + * @param side The side to check. + * @return true if the side is open, false otherwise. + */ + public static boolean isSideOpen(int cData, @NotNull Side side) { + int cState = cData % STATE_COUNT; + + if (cState == 0) { + return false; + } + + Side[] openSides = STATE_TABLE[cState]; + + for (Side s : openSides) { + if (s == side) { + return true; + } + } + + return false; + } + + /** + * Determines which sides on a given conduit are open.
+ * c = conduit (ex. cStrength = this conduit Signal Strength)
+ * @param cData The metadata of the conduit to check. + * @return a {@link Side} {@link Array} of sides that are open. + */ + public static Side[] getOpenSides(int cData){ + return STATE_TABLE[cData % STATE_COUNT]; + } + + public static final int[] REDSTONE_TO_CONDUIT = {0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10}; + public static final int[] CONDUIT_TO_REDSTONE = {0, 1, 2, 4, 5, 7, 8, 10, 11, 13, 14}; + + /** + * Converts signal strengths between redstone and conduit. + * @param strength The signal strength to convert + * @param conduitToRedstone Whether to convert conduit -> redstone or vice versa + * @return The converted signal strength (0-10)->(0-15) or (0-15)->(0-10) + */ + public static int signalConverter(int strength, boolean conduitToRedstone) { + return conduitToRedstone + ? CONDUIT_TO_REDSTONE[Math.max(0, Math.min(PROPAGATION_LENGTH, strength))] + : REDSTONE_TO_CONDUIT[Math.max(0, Math.min(15, strength))]; + } +} + + diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicWireRedstone.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicWireRedstone.java index 149ddad2f..04bb1f4eb 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicWireRedstone.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicWireRedstone.java @@ -9,6 +9,7 @@ import net.minecraft.core.current.util.BlockState; import net.minecraft.core.enums.EnumDropCause; import net.minecraft.core.item.ItemStack; import net.minecraft.core.item.Items; +import net.minecraft.core.sound.SoundCategory; import net.minecraft.core.util.helper.Axis; import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.World; @@ -264,6 +265,11 @@ public class BlockLogicWireRedstone extends BlockLogic implements ISupportable { } private int checkTarget(@NotNull World world, @NotNull TilePos tilePos, int sourceStrength) { + if(world.getBlockType(tilePos) == Blocks.RUBYGLASS_CONDUIT){ + int cStrength = world.getBlockData(tilePos) / BlockLogicRubyglassConduit.STATE_COUNT; + return Math.max(BlockLogicRubyglassConduit.signalConverter(cStrength, true), sourceStrength); + } + if (world.getBlockType(tilePos) != this.block) { return sourceStrength; } @@ -314,33 +320,33 @@ public class BlockLogicWireRedstone extends BlockLogic implements ISupportable { TilePos queryPos = new TilePos(); boolean negXShouldConnectTo = shouldConnectTo(source, tilePos.add(-1, 0, 0, queryPos), Side.WEST) || - shouldConnectToDiagonal(source, tilePos.add(-1, -1, 0, queryPos), Side.WEST, Side.BOTTOM); + shouldConnectToDiagonal(source, tilePos.add(-1, -1, 0, queryPos), Side.WEST, Side.BOTTOM); boolean posXShouldConnectTo = shouldConnectTo(source, tilePos.add(1, 0, 0, queryPos), Side.EAST) || - shouldConnectToDiagonal(source, tilePos.add(1, -1, 0, queryPos), Side.EAST, Side.BOTTOM); + shouldConnectToDiagonal(source, tilePos.add(1, -1, 0, queryPos), Side.EAST, Side.BOTTOM); boolean negZShouldConnectTo = shouldConnectTo(source, tilePos.add(0, 0, -1, queryPos), Side.NORTH) || - shouldConnectToDiagonal(source, tilePos.add(0, -1, -1, queryPos), Side.NORTH, Side.BOTTOM); + shouldConnectToDiagonal(source, tilePos.add(0, -1, -1, queryPos), Side.NORTH, Side.BOTTOM); boolean posZShouldConnectTo = shouldConnectTo(source, tilePos.add(0, 0, 1, queryPos), Side.SOUTH) || - shouldConnectToDiagonal(source, tilePos.add(0, -1, 1, queryPos), Side.SOUTH, Side.BOTTOM); + shouldConnectToDiagonal(source, tilePos.add(0, -1, 1, queryPos), Side.SOUTH, Side.BOTTOM); if (!source.isBlockNormalCube(tilePos.up(queryPos))) { if (isClimbableWall(source, tilePos.add(-1, 0, 0, queryPos), Side.WEST) && shouldConnectToDiagonal(source, tilePos.add(-1, 1, 0, queryPos), Side.WEST, Side.TOP)) - {negXShouldConnectTo = true;} + {negXShouldConnectTo = true;} if (isClimbableWall(source, tilePos.add(1, 0, 0, queryPos), Side.EAST) && shouldConnectToDiagonal(source, tilePos.add(1, 1, 0, queryPos), Side.EAST, Side.TOP)) - {posXShouldConnectTo = true;} + {posXShouldConnectTo = true;} if (isClimbableWall(source, tilePos.add(0, 0, -1, queryPos), Side.NORTH) && shouldConnectToDiagonal(source, tilePos.add(0, 1, -1, queryPos), Side.NORTH, Side.TOP)) - {negZShouldConnectTo = true;} + {negZShouldConnectTo = true;} if (isClimbableWall(source, tilePos.add(0, 0, 1, queryPos), Side.SOUTH) && shouldConnectToDiagonal(source, tilePos.add(0, 1, 1, queryPos), Side.SOUTH, Side.TOP)) - {posZShouldConnectTo = true;} + {posZShouldConnectTo = true;} } // Make wire emit block updates when a redirection happens if (source instanceof World world) { @@ -420,6 +426,9 @@ public class BlockLogicWireRedstone extends BlockLogic implements ISupportable { final Side direction = BlockLogicRepeater.getSideFromMeta(source.getBlockData(tilePos)); return side == direction || side == direction.getOpposite(); } + if (block == Blocks.RUBYGLASS_CONDUIT) { + return BlockLogicRubyglassConduit.isSideOpen(source.getBlockData(tilePos), side.getOpposite()); + } return block.isSignalSource(); } @@ -436,7 +445,7 @@ public class BlockLogicWireRedstone extends BlockLogic implements ISupportable { return false; } - // Most of the code below is relevant to fixing the visual behavior + //Most of the code below is relevant to fixing the visual behavior // of diagonal connections on both transparent and non-transparent blocks // (now that it is done get me out of this class :) I don't want to touch it again) @@ -512,21 +521,32 @@ public class BlockLogicWireRedstone extends BlockLogic implements ISupportable { } /** Helper to determine if a block acts as a solid cube for redstone climbing.
**/ - private static boolean isSolidWallForWire(@NotNull WorldSource world, @NotNull TilePos pos, @NotNull Side faceToCheck) { + private static boolean isSolidWallForWire(WorldSource world, TilePos pos, Side faceToCheck) { if (world.isBlockNormalCube(pos)) return true; - //leave separate + if (world.getBlockType(pos) == Blocks.RUBYGLASS_CONDUIT) { + return !BlockLogicRubyglassConduit.isSideOpen(world.getBlockData(pos), faceToCheck); + } return false; } - private static boolean isBlockingConduit(@NotNull WorldSource world, @NotNull TilePos pos, @NotNull Side openSide) { - //leave in preparation of conduit logic + private static boolean isBlockingConduit(WorldSource world, TilePos pos, Side openSide) { + if (world.getBlockType(pos) == Blocks.RUBYGLASS_CONDUIT) { + return BlockLogicRubyglassConduit.isSideOpen(world.getBlockData(pos), openSide); + } return false; } - /** Determines if redstone dust is allowed to visually climb the side of a block. **/ - public static boolean isClimbableWall(@NotNull WorldSource world, @NotNull TilePos wallTilePos, @NotNull Side directionToWall) { - if (world.isBlockNormalCube(wallTilePos)) return true; - //leave separate + /** + * Determines if redstone dust is allowed to visually climb the side of a block. + * Conduits, being an exception, can ONLY be climbed if the face pointing toward the bottom dust is closed. + */ + public static boolean isClimbableWall(WorldSource world, TilePos wallTilePos, Side directionToWall) { + if (world.isBlockNormalCube(wallTilePos)) { + return true; + } + if (world.getBlockType(wallTilePos) == Blocks.RUBYGLASS_CONDUIT) { + return !BlockLogicRubyglassConduit.isSideOpen(world.getBlockData(wallTilePos), directionToWall.getOpposite()); + } return false; } diff --git a/game/core/src/main/java/net/minecraft/core/block/Blocks.java b/game/core/src/main/java/net/minecraft/core/block/Blocks.java index d1594da1b..40b7fd06f 100644 --- a/game/core/src/main/java/net/minecraft/core/block/Blocks.java +++ b/game/core/src/main/java/net/minecraft/core/block/Blocks.java @@ -429,7 +429,7 @@ public final class Blocks { public static final @NotNull Block BEDROCK = register("bedrock", "minecraft:block/bedrock", 260, (b) -> new BlockLogicBedrock(b, Materials.STONE)) .withSound(BlockSounds.STONE).withSetUnbreakable().withBlastResistance(6000000F).withImmovableFlagSet() - .withTags(BlockTags.PISTON_CRUSHING, BlockTags.CHAINLINK_FENCES_CONNECT); + .withTags(BlockTags.PISTON_CRUSHING, BlockTags.CHAINLINK_FENCES_CONNECT, BlockTags.PREVENT_MOB_SPAWNS); public static final @NotNull Block BONESHALE = register("boneshale", "minecraft:block/boneshale", 261, (b) -> new BlockLogicBoneShale(b, Materials.STONE)) .withSound(BlockSounds.STONE).withHardness(16F).withBlastResistance(6000000F).withImmovableFlagSet() .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT, BlockTags.NETHER_MOBS_SPAWN); @@ -790,10 +790,10 @@ public final class Blocks { .withTags(BlockTags.MINEABLE_BY_AXE, BlockTags.PREVENT_MOB_SPAWNS); public static final @NotNull Block MOTION_SENSOR_IDLE = register("motionsensor.idle", "minecraft:block/motion_sensor_idle", 500, (BlockLogicSupplier)(b) -> new BlockLogicMotionSensor(b, false)) - .withSound(BlockSounds.STONE).withHardness(2.0F).withBlastResistance(10F).withDisabledNeighborNotifyOnMetadataChange().withOverrideColor(MaterialColor.stone) + .withSound(BlockSounds.STONE).withHardness(1.5F).withBlastResistance(10F).withDisabledNeighborNotifyOnMetadataChange().withOverrideColor(MaterialColor.stone) .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT); public static final @NotNull Block MOTION_SENSOR_ACTIVE = register("motionsensor.active", "minecraft:block/motion_sensor_active", 501, (BlockLogicSupplier)(b) -> new BlockLogicMotionSensor(b, true)) - .withSound(BlockSounds.STONE).withLightEmission(0.3F).withHardness(2.0F).withBlastResistance(10F).withOverrideColor(MaterialColor.stone).setStatParent(() -> MOTION_SENSOR_IDLE) + .withSound(BlockSounds.STONE).withLightEmission(0.3F).withHardness(1.5F).withBlastResistance(10F).withOverrideColor(MaterialColor.stone).setStatParent(() -> MOTION_SENSOR_IDLE) .withTags(BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT); public static final @NotNull Block REPEATER_IDLE = register("repeater.idle", "minecraft:block/repeater_idle", 510, (BlockLogicSupplier)b -> new BlockLogicRepeater(b, false)) @@ -848,11 +848,11 @@ public final class Blocks { .withTags(BlockTags.MINEABLE_BY_PICKAXE); public static final @NotNull Block DISPENSER_COBBLE_STONE = register("dispenser.cobble.stone", "minecraft:block/dispenser_cobble_stone", 560, BlockLogicDispenser::new) - .withSound(BlockSounds.STONE).withHardness(3.5F).withDisabledNeighborNotifyOnMetadataChange() - .withTags(BlockTags.MINEABLE_BY_PICKAXE); + .withSound(BlockSounds.STONE).withHardness(1.5F).withDisabledNeighborNotifyOnMetadataChange() + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.PREVENT_MOB_SPAWNS, BlockTags.CHAINLINK_FENCES_CONNECT); public static final @NotNull Block ACTIVATOR_COBBLE_NETHERRACK = register("activator.cobble.netherrack", "minecraft:block/activator_cobble_netherrack", 561, BlockLogicActivator::new) - .withSound(BlockSounds.STONE).withHardness(3.5F).withDisabledNeighborNotifyOnMetadataChange() - .withTags(BlockTags.MINEABLE_BY_PICKAXE); + .withSound(BlockSounds.STONE).withHardness(1.5F).withDisabledNeighborNotifyOnMetadataChange() + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT, BlockTags.PREVENT_MOB_SPAWNS); public static final @NotNull Block TRAPDOOR_PLANKS_OAK = register("trapdoor.planks.oak", "minecraft:block/trapdoor_planks_oak", 570, (b) -> new BlockLogicTrapDoor(b, Materials.WOOD)) .withSound(BlockSounds.WOOD).withHardness(3F).withDisabledNeighborNotifyOnMetadataChange() @@ -1142,9 +1142,9 @@ public final class Blocks { .withSound(BlockSounds.GLASS).withDisabledNeighborNotifyOnMetadataChange().withLightEmission(0.5F) .withTags(BlockTags.MINEABLE_BY_PICKAXE) .withOverrideColor(MaterialColor.rubyglass); - public static final Block RUBYGLASS_CIRCUIT = register("rubyglass.circuit", "minecraft:block/rubyglass_circuit", 824, (b) -> new BlockLogic(b, Materials.STONE)) - .withSound(BlockSounds.STONE).withDisabledNeighborNotifyOnMetadataChange().withHardness(1F) - .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.INFINITE_BURN, BlockTags.CAVES_CUT_THROUGH, BlockTags.NETHER_MOBS_SPAWN) + public static final Block RUBYGLASS_CONDUIT = register("rubyglass.conduit", "minecraft:block/rubyglass_conduit", 824, (BlockLogicSupplier) b -> new BlockLogicRubyglassConduit(b, Materials.STONE)) + .withSound(BlockSounds.STONE).withHardness(1.5F).withDisabledNeighborNotifyOnMetadataChange() + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT, BlockTags.PREVENT_MOB_SPAWNS) .withOverrideColor(MaterialColor.rubyglass); public static final Block RUBYGLASS_NODE = register("rubyglass.node", "minecraft:block/rubyglass_node", 826, (b) -> new BlockLogicOreRubyglass(b)) @@ -1373,11 +1373,11 @@ public final class Blocks { .withTags(BlockTags.MINEABLE_BY_PICKAXE); public static final @NotNull Block MATCHER = register("matcher", "minecraft:block/matcher", 1040, (b) -> new BlockLogicMatcher(b, false)) - .withSound(BlockSounds.STONE).withHardness(3.5F).withDisabledNeighborNotifyOnMetadataChange() - .withTags(BlockTags.MINEABLE_BY_PICKAXE); + .withSound(BlockSounds.STONE).withHardness(1.5F).withDisabledNeighborNotifyOnMetadataChange() + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT, BlockTags.PREVENT_MOB_SPAWNS); public static final @NotNull Block MATCHER_ACTIVE = register("matcher.active", "minecraft:block/matcher_active", 1041, (b) -> new BlockLogicMatcher(b, true)) - .withSound(BlockSounds.STONE).withHardness(3.5F).withDisabledNeighborNotifyOnMetadataChange() - .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU); + .withSound(BlockSounds.STONE).withHardness(1.5F).withDisabledNeighborNotifyOnMetadataChange() + .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.CHAINLINK_FENCES_CONNECT, BlockTags.PREVENT_MOB_SPAWNS); public static final @NotNull Block STAIRS_BRICK_DIAMOND = register("stairs.brick.diamond", "minecraft:block/stairs_brick_diamond", 1049, (BlockLogicSupplier)b -> new BlockLogicStairs(b, Blocks.BRICK_DIAMOND)) .withSound(BlockSounds.PERMAFROST).withDisabledNeighborNotifyOnMetadataChange().withLitInteriorSurface(true) 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 be9c13798..67bee6f83 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 @@ -4,27 +4,24 @@ import java.util.*; import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; -import net.minecraft.core.block.Block; import net.minecraft.core.block.Blocks; -import net.minecraft.core.block.motion.CarriedBlock; -import net.minecraft.core.block.tag.BlockTags; import net.minecraft.core.entity.Entity; import net.minecraft.core.entity.EntityItem; -import net.minecraft.core.entity.Mob; import net.minecraft.core.entity.player.Player; +import net.minecraft.core.world.save.conversion.ItemConverters; import net.minecraft.core.item.Item; import net.minecraft.core.item.ItemStack; import com.mojang.nbt.tags.CompoundTag; import com.mojang.nbt.tags.ListTag; import net.minecraft.core.net.packet.Packet; import net.minecraft.core.net.packet.PacketTileEntityData; -import net.minecraft.core.util.helper.Side; -import net.minecraft.core.world.ICarriable; import net.minecraft.core.world.World; import org.jetbrains.annotations.NotNull; import org.joml.primitives.AABBd; import org.joml.primitives.AABBdc; +import static net.minecraft.core.world.save.conversion.ItemConverters.legacyBucketConverter; + public class TileEntityBasket extends TileEntity { private int numUnitsInside = 0; private final Object2IntMap contents = new Object2IntArrayMap<>(); @@ -51,6 +48,9 @@ public class TileEntityBasket extends TileEntity { } private int getItemSizeUnits(final Item item) { + if (item == null) { + return 0; + } return 64 / item.getItemStackLimit(null); } @@ -255,6 +255,9 @@ public class TileEntityBasket extends TileEntity { } public static BasketEntry read(final CompoundTag tag) { + + legacyBucketConverter(tag); + final int id = tag.getShort("id"); final int damage = tag.getShort("Damage"); final CompoundTag data = tag.getCompound("Data"); 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 f2fab04d6..3a407f60c 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 @@ -12,6 +12,7 @@ import net.minecraft.core.data.registry.recipe.entry.RecipeEntryFurnace; import net.minecraft.core.entity.Entity; import net.minecraft.core.entity.EntityItem; import net.minecraft.core.entity.player.Player; +import net.minecraft.core.item.ItemBucket; import net.minecraft.core.item.Items; import net.minecraft.core.item.ItemStack; import net.minecraft.core.net.packet.PacketTileEntityData; @@ -19,7 +20,6 @@ import net.minecraft.core.net.packet.Packet; import net.minecraft.core.player.inventory.container.Container; import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.World; -import net.minecraft.core.world.pos.TilePos; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -172,45 +172,45 @@ public class TileEntityFurnace extends TileEntity } @Override - public void tick() - { + public void tick() { boolean isBurnTimeHigherThan0 = currentBurnTime > 0; boolean furnaceUpdated = false; - if(currentBurnTime > 0) - { + if(currentBurnTime > 0) { currentBurnTime--; } - if(worldObj == null || !worldObj.isClientSide) - { - if(worldObj == null || worldObj.getBlockId(tilePos.x, tilePos.y, tilePos.z) == Blocks.FURNACE_STONE_IDLE.id()) { - if(currentBurnTime == 0 && furnaceItemStacks[SLOT_INGREDIENT] == null) { - if(furnaceItemStacks[SLOT_FUEL] != null && furnaceItemStacks[SLOT_FUEL].itemID == Blocks.COBBLE_NETHERRACK.id()) { - furnaceItemStacks[SLOT_FUEL].stackSize--; - if(furnaceItemStacks[SLOT_FUEL].stackSize <= 0) furnaceItemStacks[SLOT_FUEL] = null; - updateFurnace(true); - furnaceUpdated = true; - } - } - } - - if(currentBurnTime == 0 && furnaceItemStacks[SLOT_FUEL] != null && canSmelt()) - { + + if(worldObj == null || !worldObj.isClientSide) { + if(worldObj == null || worldObj.getBlockId(tilePos.x, tilePos.y, tilePos.z) == Blocks.FURNACE_STONE_IDLE.id()) { + if(currentBurnTime == 0 && furnaceItemStacks[SLOT_INGREDIENT] == null) { + if(furnaceItemStacks[SLOT_FUEL] != null && furnaceItemStacks[SLOT_FUEL].itemID == Blocks.COBBLE_NETHERRACK.id()) { + furnaceItemStacks[SLOT_FUEL].stackSize--; + if(furnaceItemStacks[SLOT_FUEL].stackSize <= 0) furnaceItemStacks[SLOT_FUEL] = null; + updateFurnace(true); + furnaceUpdated = true; + } + } + } + + if(currentBurnTime == 0 && furnaceItemStacks[SLOT_FUEL] != null && canSmelt()) { maxBurnTime = currentBurnTime = getBurnTimeFromItem(furnaceItemStacks[SLOT_FUEL]); - if(currentBurnTime > 0) - { + if(currentBurnTime > 0) { furnaceUpdated = true; - if(furnaceItemStacks[SLOT_FUEL] != null) - { - if (furnaceItemStacks[SLOT_FUEL].getItem() == Items.BUCKET_LAVA) - { - furnaceItemStacks[SLOT_FUEL] = new ItemStack(Items.BUCKET); + + if(furnaceItemStacks[SLOT_FUEL] != null) { + ItemStack fuelStack = furnaceItemStacks[SLOT_FUEL]; + + if (fuelStack.getItem() instanceof ItemBucket && ItemBucket.getState(fuelStack) == ItemBucket.STATE_LAVA) { + + ItemBucket.setCharges(fuelStack, ItemBucket.getCharges(fuelStack) - 1); + + if (ItemBucket.getCharges(fuelStack) == 0) { + ItemBucket.setState(fuelStack, ItemBucket.STATE_EMPTY); + } } - else - { - furnaceItemStacks[SLOT_FUEL].stackSize--; - if(furnaceItemStacks[SLOT_FUEL].stackSize <= 0) - { + else { + fuelStack.stackSize--; + if(fuelStack.stackSize <= 0) { furnaceItemStacks[SLOT_FUEL] = null; } } @@ -218,26 +218,24 @@ public class TileEntityFurnace extends TileEntity } } - if(isBurning() && canSmelt()) - { + if(isBurning() && canSmelt()) { currentCookTime++; - if(currentCookTime == maxCookTime) - { + if(currentCookTime == maxCookTime) { currentCookTime = 0; smeltItem(); furnaceUpdated = true; } - } else + } else { currentCookTime = 0; + } - if(isBurnTimeHigherThan0 != (currentBurnTime > 0)) - { + if(isBurnTimeHigherThan0 != (currentBurnTime > 0)) { furnaceUpdated = true; updateFurnace(false); } } - if(furnaceUpdated) - { + + if(furnaceUpdated) { setChanged(); } } @@ -317,11 +315,9 @@ public class TileEntityFurnace extends TileEntity } } - private int getBurnTimeFromItem(ItemStack itemStack) - { - if(itemStack == null) - return 0; - return LookupFuelFurnace.instance.getFuelYield(itemStack.getItem().id); + private int getBurnTimeFromItem(ItemStack itemStack) { + if (itemStack == null) return 0; + return LookupFuelFurnace.instance.getFuelYield(itemStack); } @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 209aeb4bf..5414b53e6 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 @@ -279,10 +279,9 @@ public class TileEntityFurnaceBlast extends TileEntity } } - private int getBurnTimeFromItem(final ItemStack itemStack) { - if (itemStack == null) - return 0; - return LookupFuelFurnaceBlast.instance.getFuelYield(itemStack.getItem().id); + private int getBurnTimeFromItem(ItemStack itemStack) { + if (itemStack == null) return 0; + return LookupFuelFurnaceBlast.instance.getFuelYield(itemStack); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityTrommel.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityTrommel.java index cf28b7b55..39d1731ce 100644 --- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityTrommel.java +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityTrommel.java @@ -11,7 +11,6 @@ import net.minecraft.core.block.BlockLogicTrommel; import net.minecraft.core.block.motion.CarriedBlock; import net.minecraft.core.block.Block; import net.minecraft.core.crafting.LookupFuelFurnace; -import net.minecraft.core.data.DataLoader; import net.minecraft.core.data.registry.recipe.entry.RecipeEntryTrommel; import net.minecraft.core.data.registry.Registries; import net.minecraft.core.entity.Entity; @@ -19,15 +18,14 @@ import net.minecraft.core.entity.EntityItem; import net.minecraft.core.entity.monster.MobSlime; import net.minecraft.core.entity.player.Player; import net.minecraft.core.item.Item; +import net.minecraft.core.item.ItemBucket; import net.minecraft.core.item.Items; import net.minecraft.core.item.ItemStack; import net.minecraft.core.player.inventory.container.Container; import net.minecraft.core.util.helper.Direction; import net.minecraft.core.util.helper.MathHelper; -import net.minecraft.core.world.Dimension; import net.minecraft.core.world.World; import net.minecraft.core.world.pos.TilePos; -import net.minecraft.core.world.save.LevelStorageDummy; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -214,23 +212,27 @@ public class TileEntityTrommel extends TileEntity if(!canProduce(SLOTS_INGREDIENT[this.nextToSieve])) { this.nextToSieve = (this.nextToSieve + 1) % SLOTS_INGREDIENT.length; } - if(this.burnTime == 0 && canProduce(SLOTS_INGREDIENT[this.nextToSieve])) - { + if(this.burnTime == 0 && canProduce(SLOTS_INGREDIENT[this.nextToSieve])) { this.currentItemBurnTime = this.burnTime = getItemBurnTime(this.itemStacks[SLOT_FUEL]); - if(this.burnTime > 0) - { + + if(this.burnTime > 0) { flag1 = true; - if(this.itemStacks[SLOT_FUEL] != null) - { - if(this.itemStacks[SLOT_FUEL].getItem() == Items.BUCKET_LAVA) { - this.itemStacks[SLOT_FUEL] = new ItemStack(Items.BUCKET); - }else { - this.itemStacks[SLOT_FUEL].stackSize--; - if(this.itemStacks[SLOT_FUEL].stackSize <= 0) - { + if(this.itemStacks[SLOT_FUEL] != null) { + ItemStack fuelStack = this.itemStacks[SLOT_FUEL]; + + if (fuelStack.getItem() instanceof ItemBucket && ItemBucket.getState(fuelStack) == ItemBucket.STATE_LAVA) { + + ItemBucket.setCharges(fuelStack, ItemBucket.getCharges(fuelStack) - 1); + + if (ItemBucket.getCharges(fuelStack) == 0) { + ItemBucket.setState(fuelStack, ItemBucket.STATE_EMPTY); + } + } else { + fuelStack.stackSize--; + if(fuelStack.stackSize <= 0) { this.itemStacks[SLOT_FUEL] = null; } - } + } } } } @@ -408,9 +410,8 @@ public class TileEntityTrommel extends TileEntity private int getItemBurnTime(ItemStack itemStack) { - if(itemStack == null) - return 0; - return LookupFuelFurnace.instance.getFuelYield(itemStack.getItem().id); + if(itemStack == null) return 0; + return LookupFuelFurnace.instance.getFuelYield(itemStack); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/crafting/LookupFuelFurnace.java b/game/core/src/main/java/net/minecraft/core/crafting/LookupFuelFurnace.java index 1ca5ca011..addeb075d 100644 --- a/game/core/src/main/java/net/minecraft/core/crafting/LookupFuelFurnace.java +++ b/game/core/src/main/java/net/minecraft/core/crafting/LookupFuelFurnace.java @@ -3,15 +3,19 @@ package net.minecraft.core.crafting; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import net.minecraft.core.item.Items; +import net.minecraft.core.item.ItemStack; +import net.minecraft.core.item.ItemBucket; import net.minecraft.core.block.Blocks; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; +import java.util.function.Predicate; public class LookupFuelFurnace { public static final LookupFuelFurnace instance = new LookupFuelFurnace(); protected final Int2IntMap fuelList = new Int2IntOpenHashMap(); + protected final Map, Integer> advancedFuelList = new LinkedHashMap<>(); protected LookupFuelFurnace() { register(); @@ -83,17 +87,33 @@ public class LookupFuelFurnace { addFuelEntry(Items.COAL.id, 1600); addFuelEntry(Items.NETHERCOAL.id, 6400); - addFuelEntry(Items.BUCKET_LAVA.id, 20000); + addAdvancedFuelEntry(stack -> stack.getItem() instanceof ItemBucket && ItemBucket.getState(stack) == ItemBucket.STATE_LAVA, 12800); } public void addFuelEntry(int id, int fuelYield) { fuelList.put(id, fuelYield); } + public void addAdvancedFuelEntry(Predicate condition, int fuelYield) { + advancedFuelList.put(condition, fuelYield); + } + public int getFuelYield(int id) { return fuelList.getOrDefault(id, 0); } + public int getFuelYield(ItemStack stack) { + if (stack == null) return 0; + + for (Map.Entry, Integer> entry : advancedFuelList.entrySet()) { + if (entry.getKey().test(stack)) { + return entry.getValue(); + } + } + + return getFuelYield(stack.getItem().id); + } + public Int2IntMap getFuelList() { return fuelList; } diff --git a/game/core/src/main/java/net/minecraft/core/current/conduit/ConduitHandler.java b/game/core/src/main/java/net/minecraft/core/current/conduit/ConduitHandler.java new file mode 100644 index 000000000..d0a6ea9b8 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/current/conduit/ConduitHandler.java @@ -0,0 +1,181 @@ +package net.minecraft.core.current.conduit; + +import net.minecraft.core.block.Block; +import net.minecraft.core.block.Blocks; +import net.minecraft.core.block.BlockLogicRubyglassConduit; +import net.minecraft.core.util.helper.Side; +import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; + +import java.util.*; + + +/** + * One-Dimensional Implementation of Alternate Current for rubyglass conduits.
+ * Handles the logic and updates for any given conduit network and seamlessly integrates with other redstone components.
+ * + * @author Melon Mojito (@melon_mojito) + */ +public class ConduitHandler { + private final World world; + private boolean updating = false; + private final Queue updateQueue = new LinkedList<>(); + + public ConduitHandler(World world) { + this.world = world; + } + + public void onConduitUpdated(TilePosc pos) { + queueUpdate(new TilePos(pos)); + } + + public void onConduitAdded(TilePosc pos) { + queueUpdate(new TilePos(pos)); + } + + public void onConduitRemoved(TilePosc pos, int oldData) { + //update the sides this conduit was connected to + for (Side side : BlockLogicRubyglassConduit.getOpenSides(oldData)) { + TilePos nPos = new TilePos(pos).add(side); + if (world.getBlockType(nPos) == Blocks.RUBYGLASS_CONDUIT) { + queueUpdate(nPos); + } + } + } + + private void queueUpdate(TilePos pos) { + updateQueue.add(pos); + if (!updating) { + processQueue(); + } + } + + private void processQueue() { + updating = true; + try { + while (!updateQueue.isEmpty()) { + TilePos startPos = updateQueue.poll(); + // Ensure the block is still a conduit before updating the network, + // as it could have been broken while sitting in the queue. + if (world.getBlockType(startPos) == Blocks.RUBYGLASS_CONDUIT) { + updateNetwork(startPos); + } + } + } finally { + updating = false; + } + } + + private void updateNetwork(TilePos startPos) { + //build the network + Set network = new HashSet<>(); + Queue toSearch = new LinkedList<>(); + toSearch.add(startPos); + + while (!toSearch.isEmpty()) { + TilePos pos = toSearch.poll(); + if (network.add(pos)) { + int data = world.getBlockData(pos); + for (Side side : BlockLogicRubyglassConduit.getOpenSides(data)) { + TilePos nPos = new TilePos(pos).add(side); + if (world.getBlockType(nPos) == Blocks.RUBYGLASS_CONDUIT && + BlockLogicRubyglassConduit.isSideOpen(world.getBlockData(nPos), side.getOpposite())) { + toSearch.add(nPos); + } + } + } + } + + //external sources: levers, buttons, etc. + Map externalPower = new HashMap<>(); + for (TilePos tilePos : network) { + int data = world.getBlockData(tilePos); + int currentPower = data / BlockLogicRubyglassConduit.STATE_COUNT; + int maxExternalPower = 0; + + for (Side side : BlockLogicRubyglassConduit.getOpenSides(data)) { + TilePos nTilePos = new TilePos(tilePos).add(side); + Block nBlockType = world.getBlockType(nTilePos); + + if (nBlockType != Blocks.RUBYGLASS_CONDUIT) { + int external = BlockLogicRubyglassConduit.getAndConvertNeighborSignal(world, tilePos, side); + + //break the recursive loop for redstone dust + if (nBlockType == Blocks.WIRE_REDSTONE) { + if (external < currentPower) { + external = 0; + } + } + + if (external > maxExternalPower) maxExternalPower = external; + } + } + externalPower.put(tilePos, maxExternalPower); + } + + //propagate from roots with priority + Map newPowerLevels = new HashMap<>(); + for (TilePos tilePos : network) newPowerLevels.put(tilePos, 0); + + PriorityQueue powerQueue = new PriorityQueue<>((a, b) -> Integer.compare(b.currentPower, a.currentPower)); + for (Map.Entry entry : externalPower.entrySet()) { + if (entry.getValue() > 0) { + powerQueue.add(new ConduitNode(entry.getKey(), entry.getValue())); + } + } + + while (!powerQueue.isEmpty()) { + ConduitNode node = powerQueue.poll(); + //ignore weaker path + if (node.currentPower <= newPowerLevels.get(node.tilePos)) continue; + + newPowerLevels.put(node.tilePos, node.currentPower); + + //propagate power down the line + if (node.currentPower > 1) { + int data = world.getBlockData(node.tilePos); + for (Side side : BlockLogicRubyglassConduit.getOpenSides(data)) { + TilePos nPos = new TilePos(node.tilePos).add(side); + if (network.contains(nPos)) { + powerQueue.add(new ConduitNode(nPos, node.currentPower - 1)); + } + } + } + } + + Set blocksToNotify = new HashSet<>(); + for (TilePos tilePos : network) { + int oldData = world.getBlockData(tilePos); + int oldPower = oldData / BlockLogicRubyglassConduit.STATE_COUNT; + int newPower = newPowerLevels.get(tilePos); + + if (oldPower != newPower) { + int state = oldData % BlockLogicRubyglassConduit.STATE_COUNT; + + //suppress recursive neighbor updates while data is being set + world.noNeighborUpdate = true; + world.setBlockDataNotify(tilePos, newPower * BlockLogicRubyglassConduit.STATE_COUNT + state); + world.noNeighborUpdate = false; + + //queue updates ONLY for blocks facing the open sides that ARE NOT conduits in this network + for (Side side : BlockLogicRubyglassConduit.getOpenSides(state)) { + TilePos targetPos = new TilePos(tilePos).add(side); + if (!network.contains(targetPos)) { + blocksToNotify.add(targetPos); + } + } + } + } + + //notify all neighbors after the network is done with its logic/updates + for (TilePos nTilePos : blocksToNotify) { + Block neighborBlockType = world.getBlockType(nTilePos); + neighborBlockType.onNeighborChanged(world, nTilePos, Blocks.RUBYGLASS_CONDUIT); + + if (neighborBlockType != Blocks.WIRE_REDSTONE) { + world.notifyBlocksOfNeighborChange(nTilePos, Blocks.RUBYGLASS_CONDUIT); + } + } + } +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/current/conduit/ConduitNode.java b/game/core/src/main/java/net/minecraft/core/current/conduit/ConduitNode.java new file mode 100644 index 000000000..2a829e0e1 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/current/conduit/ConduitNode.java @@ -0,0 +1,13 @@ +package net.minecraft.core.current.conduit; + +import net.minecraft.core.world.pos.TilePos; + +public class ConduitNode { + TilePos tilePos; + int currentPower; + + ConduitNode(TilePos tilePos, int currentPower) { + this.tilePos = tilePos; + this.currentPower = currentPower; + } +} diff --git a/game/core/src/main/java/net/minecraft/core/current/wire/Node.java b/game/core/src/main/java/net/minecraft/core/current/wire/Node.java index 87ae2910b..efabe2edc 100644 --- a/game/core/src/main/java/net/minecraft/core/current/wire/Node.java +++ b/game/core/src/main/java/net/minecraft/core/current/wire/Node.java @@ -15,7 +15,7 @@ import java.util.Arrays; * * @author Space Walker */ -class Node { +public class Node { // flags that encode the Node type private static final int CONDUCTOR = 0b01; diff --git a/game/core/src/main/java/net/minecraft/core/current/wire/PriorityQueue.java b/game/core/src/main/java/net/minecraft/core/current/wire/PriorityQueue.java index 5f38cce11..30b00cf1b 100644 --- a/game/core/src/main/java/net/minecraft/core/current/wire/PriorityQueue.java +++ b/game/core/src/main/java/net/minecraft/core/current/wire/PriorityQueue.java @@ -7,7 +7,7 @@ import java.util.AbstractQueue; import java.util.Arrays; import java.util.Iterator; -class PriorityQueue extends AbstractQueue { +public class PriorityQueue extends AbstractQueue { private static final int OFFSET = -BlockLogicWireRedstone.SIGNAL_MIN; diff --git a/game/core/src/main/java/net/minecraft/core/current/wire/SimpleQueue.java b/game/core/src/main/java/net/minecraft/core/current/wire/SimpleQueue.java index 0fcef5f66..405861d9c 100644 --- a/game/core/src/main/java/net/minecraft/core/current/wire/SimpleQueue.java +++ b/game/core/src/main/java/net/minecraft/core/current/wire/SimpleQueue.java @@ -3,7 +3,7 @@ package net.minecraft.core.current.wire; import java.util.AbstractQueue; import java.util.Iterator; -class SimpleQueue extends AbstractQueue { +public class SimpleQueue extends AbstractQueue { private WireNode head; private WireNode tail; diff --git a/game/core/src/main/java/net/minecraft/core/current/wire/WireConnection.java b/game/core/src/main/java/net/minecraft/core/current/wire/WireConnection.java index b2bb579e0..86c6fa7bd 100644 --- a/game/core/src/main/java/net/minecraft/core/current/wire/WireConnection.java +++ b/game/core/src/main/java/net/minecraft/core/current/wire/WireConnection.java @@ -7,7 +7,7 @@ package net.minecraft.core.current.wire; * * @author Space Walker */ -class WireConnection { +public class WireConnection { /** The connected wire. */ final WireNode wire; diff --git a/game/core/src/main/java/net/minecraft/core/current/wire/WireConnectionManager.java b/game/core/src/main/java/net/minecraft/core/current/wire/WireConnectionManager.java index a1309f169..4725ac1a7 100644 --- a/game/core/src/main/java/net/minecraft/core/current/wire/WireConnectionManager.java +++ b/game/core/src/main/java/net/minecraft/core/current/wire/WireConnectionManager.java @@ -1,12 +1,15 @@ package net.minecraft.core.current.wire; +import net.minecraft.core.block.BlockLogicRubyglassConduit; +import net.minecraft.core.block.Blocks; import net.minecraft.core.current.wire.WireHandler.Directions; import net.minecraft.core.current.wire.WireHandler.NodeProvider; +import net.minecraft.core.util.helper.Side; import java.util.Arrays; import java.util.function.Consumer; -class WireConnectionManager { +public class WireConnectionManager { /** The owner of these connections. */ final WireNode owner; @@ -44,8 +47,15 @@ class WireConnectionManager { clear(); } - boolean belowIsConductor = nodes.getNeighbor(owner, Directions.DOWN).isConductor(); - boolean aboveIsConductor = nodes.getNeighbor(owner, Directions.UP).isConductor(); + //tried my best to keep original AltCurrent naming schemes when changing code here + + Node ownerDown = nodes.getNeighbor(owner, Directions.DOWN); + boolean belowIsConductor = ownerDown.isConductor(); + + Node ownerUp = nodes.getNeighbor(owner, Directions.UP); + boolean aboveIsConductor = ownerUp.isConductor(); + // Check if the block directly above the bottom wire is an open conduit facing down + boolean aboveIsOpenDown = isConduitOpenTowards(ownerUp, Directions.DOWN); for (int iDir = 0; iDir < Directions.HORIZONTAL.length; iDir++) { Node neighbor = nodes.getNeighbor(owner, iDir); @@ -57,19 +67,35 @@ class WireConnectionManager { } boolean sideIsConductor = neighbor.isConductor(); + int iOppDir = Directions.iOpposite(iDir); + + //looking downwards logic + boolean blockedDown = sideIsConductor || + isConduitOpenTowards(ownerDown, iDir) || + isConduitOpenTowards(neighbor, Directions.UP); - if (!sideIsConductor) { + if (!blockedDown) { Node node = nodes.getNeighbor(neighbor, Directions.DOWN); if (node.isWire()) { - add(node.asWire(), iDir, belowIsConductor, true); + boolean offerDown = belowIsConductor || + (ownerDown.state.is(Blocks.RUBYGLASS_CONDUIT) && !isConduitOpenTowards(ownerDown, iDir)); + add(node.asWire(), iDir, offerDown, true); } } - if (!aboveIsConductor) { + + //looking upwards logic + boolean blockedUp = aboveIsConductor || + aboveIsOpenDown || + isConduitOpenTowards(neighbor, iOppDir); + + if (!blockedUp) { Node node = nodes.getNeighbor(neighbor, Directions.UP); if (node.isWire()) { - add(node.asWire(), iDir, true, sideIsConductor); + boolean acceptUp = sideIsConductor || + (neighbor.state.is(Blocks.RUBYGLASS_CONDUIT) && !isConduitOpenTowards(neighbor, iOppDir)); + add(node.asWire(), iDir, true, acceptUp); } } } @@ -79,6 +105,29 @@ class WireConnectionManager { } } + /** + * Checks if a node is a Rubyglass Conduit and if a specific directional port is open. + * @param node The node to check + * @param iDir The Alternate Current direction we are querying + * @return true if the node is a conduit AND the port facing iDir is open + */ + private boolean isConduitOpenTowards(Node node, int iDir) { + if (node.state.is(Blocks.RUBYGLASS_CONDUIT)) { + Side face = Side.NONE; + face = switch (iDir) { + case Directions.WEST -> Side.WEST; + case Directions.NORTH -> Side.NORTH; + case Directions.EAST -> Side.EAST; + case Directions.SOUTH -> Side.SOUTH; + case Directions.DOWN -> Side.BOTTOM; + case Directions.UP -> Side.TOP; + default -> face; + }; + return face != Side.NONE && BlockLogicRubyglassConduit.isSideOpen(node.state.get(), face); + } + return false; + } + private void clear() { Arrays.fill(heads, null); diff --git a/game/core/src/main/java/net/minecraft/core/current/wire/WireHandler.java b/game/core/src/main/java/net/minecraft/core/current/wire/WireHandler.java index 6884d9b05..61f8c1841 100644 --- a/game/core/src/main/java/net/minecraft/core/current/wire/WireHandler.java +++ b/game/core/src/main/java/net/minecraft/core/current/wire/WireHandler.java @@ -1,5 +1,6 @@ package net.minecraft.core.current.wire; +import net.minecraft.core.block.BlockLogicRubyglassConduit; import net.minecraft.core.block.BlockLogicWireRedstone; import net.minecraft.core.block.Block; import net.minecraft.core.block.Blocks; @@ -754,6 +755,32 @@ public class WireHandler { continue; } + //conduit logic + if (neighboringNode.state.is(Blocks.RUBYGLASS_CONDUIT)) { + int cData = neighboringNode.state.get(); + + Side conduitFace = getSide(iDir); + + if (BlockLogicRubyglassConduit.isSideOpen(cData, conduitFace)) { + int cStrength = cData / BlockLogicRubyglassConduit.STATE_COUNT; + int convertedStrength = BlockLogicRubyglassConduit.signalConverter(cStrength, true); + + //step down the signal strength when passing from conduit to wire + convertedStrength = Math.max(0, convertedStrength - 1); + + //if signal is less than current power, set to 0 + if (convertedStrength < wire.currentPower) { + convertedStrength = 0; + } + + if (convertedStrength > maxExternalPower) { + maxExternalPower = convertedStrength; + } + } + //this continue took me hours to find. I hate my life + continue; + } + if (neighboringNode.isConductor() && hasDirectSignalTo(wire, neighboringNode, Directions.iOpposite(iDir))) { maxExternalPower = POWER_MAX; } @@ -769,9 +796,9 @@ public class WireHandler { } } - private static @NotNull Side getSideFromDirection(int iDirection) { + private static @NotNull Side getSide(int iDir) { Side wireSide = Side.NONE; - wireSide = switch (iDirection) { + wireSide = switch (iDir) { case Directions.WEST -> Side.WEST; case Directions.NORTH -> Side.NORTH; case Directions.EAST -> Side.EAST; @@ -818,6 +845,10 @@ public class WireHandler { for (int iDir : Directions.I_EXCEPT[except]) { Node neighbor = getNeighbor(node, iDir); + if (neighbor.state.is(Blocks.WIRE_REDSTONE) || neighbor.state.is(Blocks.RUBYGLASS_CONDUIT)) { + continue; + } + if (neighbor.isSignalSource() && neighbor.state.hasDirectSignal(this.world, neighbor.pos, Directions.ALL[iDir])) { return true; } diff --git a/game/core/src/main/java/net/minecraft/core/current/wire/WireNode.java b/game/core/src/main/java/net/minecraft/core/current/wire/WireNode.java index b949ee832..0f8529fca 100644 --- a/game/core/src/main/java/net/minecraft/core/current/wire/WireNode.java +++ b/game/core/src/main/java/net/minecraft/core/current/wire/WireNode.java @@ -17,7 +17,7 @@ import org.slf4j.Logger; * * @author Space Walker */ -class WireNode extends Node { +public class WireNode extends Node { private static final Logger LOGGER = LogUtils.getLogger(); final WireConnectionManager connections; diff --git a/game/core/src/main/java/net/minecraft/core/current/wire/WorldHelper.java b/game/core/src/main/java/net/minecraft/core/current/wire/WorldHelper.java index ade1e452a..5c61fc059 100644 --- a/game/core/src/main/java/net/minecraft/core/current/wire/WorldHelper.java +++ b/game/core/src/main/java/net/minecraft/core/current/wire/WorldHelper.java @@ -8,7 +8,7 @@ import net.minecraft.core.world.pos.TilePos; import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; -class WorldHelper { +public class WorldHelper { private static final int Y_MIN = 0; diff --git a/game/core/src/main/java/net/minecraft/core/data/registry/Registries.java b/game/core/src/main/java/net/minecraft/core/data/registry/Registries.java index 3a9aa57b1..6d0139818 100644 --- a/game/core/src/main/java/net/minecraft/core/data/registry/Registries.java +++ b/game/core/src/main/java/net/minecraft/core/data/registry/Registries.java @@ -6,6 +6,7 @@ import net.minecraft.core.data.registry.recipe.RecipeEntryBase; import net.minecraft.core.data.registry.recipe.RecipeRegistry; import net.minecraft.core.data.registry.recipe.entry.*; import net.minecraft.core.item.Item; +import net.minecraft.core.item.ItemBucket; import net.minecraft.core.item.ItemStack; import net.minecraft.core.data.gamerule.GameRule; import net.minecraft.core.data.gamerule.GameRules; @@ -174,6 +175,24 @@ public class Registries extends Registry> { new ItemStack(Items.TOOL_SWORD_DIAMOND, 1, -1), new ItemStack(Items.TOOL_SWORD_STEEL, 1, -1))); + // Find every single ItemBucket currently registered in the game + List allBuckets = new ArrayList<>(); + for (Item item : Item.itemsList) { + if (item instanceof ItemBucket bucket) { + allBuckets.add(bucket); + } + } + + // Dynamically register ItemGroups for all bucket states + for (NamespaceID stateId : ItemBucket.getRegisteredStateIds()) { + if (ItemBucket.STATE_EMPTY.equals(stateId)) continue; + List variations = new ArrayList<>(); + for (ItemBucket bucket : allBuckets) { + variations.add(ItemBucket.createRecipeInput(bucket, stateId)); + } + ITEM_GROUPS.register(stateId.namespace() + ":" + stateId.value() + "_buckets", variations); + } + if (RECIPES == null) new RecipeRegistry(); } diff --git a/game/core/src/main/java/net/minecraft/core/data/registry/recipe/RecipeSymbol.java b/game/core/src/main/java/net/minecraft/core/data/registry/recipe/RecipeSymbol.java index a6e35927b..297c4c08a 100644 --- a/game/core/src/main/java/net/minecraft/core/data/registry/recipe/RecipeSymbol.java +++ b/game/core/src/main/java/net/minecraft/core/data/registry/recipe/RecipeSymbol.java @@ -1,5 +1,7 @@ package net.minecraft.core.data.registry.recipe; +import com.mojang.nbt.tags.CompoundTag; +import com.mojang.nbt.tags.Tag; import net.minecraft.core.data.registry.Registries; import net.minecraft.core.item.ItemStack; @@ -154,19 +156,39 @@ public class RecipeSymbol { return null; } - public boolean matches(ItemStack stack){ - if(stack == null) return false; + public boolean matches(ItemStack stack) { + if (stack == null) return false; List stacks = resolve(); - boolean found = false; + for (ItemStack resolvedStack : stacks) { - boolean foundId = resolvedStack.itemID == stack.itemID; - boolean foundMeta = resolvedStack.getMetadata() == -1 || resolvedStack.getMetadata() == stack.getMetadata(); - if (foundId && foundMeta) { - found = true; - break; + if (resolvedStack.itemID != stack.itemID) continue; + if (resolvedStack.getMetadata() != -1 && resolvedStack.getMetadata() != stack.getMetadata()) continue; + + CompoundTag resolvedData = resolvedStack.getData(); + if (resolvedData.getValue().isEmpty()) return true; + + if (isNBTPresentAndEqual(resolvedData, stack.getData())) return true; + } + return false; + } + + /** + * Checks if all tags in the requirement are present in the tagToCompare tag + * If present, the values of the tags must be equal to return true + * @param requirement The requirement tag + * @param tagToCompare The tag to compare + * @return True if all tags are present and equal, false otherwise + */ + private boolean isNBTPresentAndEqual(CompoundTag requirement, CompoundTag tagToCompare) { + for (String key : requirement.getValue().keySet()) { + Tag requirementTag = requirement.getTag(key); + Tag comparrisonTag = tagToCompare.getTag(key); + + if (comparrisonTag == null || !comparrisonTag.equals(requirementTag)) { + return false; } } - return found; + return true; } public char getSymbol() { diff --git a/game/core/src/main/java/net/minecraft/core/data/registry/recipe/entry/RecipeEntryCrafting.java b/game/core/src/main/java/net/minecraft/core/data/registry/recipe/entry/RecipeEntryCrafting.java index 548e63057..c8796b640 100644 --- a/game/core/src/main/java/net/minecraft/core/data/registry/recipe/entry/RecipeEntryCrafting.java +++ b/game/core/src/main/java/net/minecraft/core/data/registry/recipe/entry/RecipeEntryCrafting.java @@ -2,6 +2,7 @@ package net.minecraft.core.data.registry.recipe.entry; import net.minecraft.core.data.registry.recipe.SearchQuery; import net.minecraft.core.data.registry.recipe.RecipeEntryBase; +import net.minecraft.core.item.IItemContainer; import net.minecraft.core.item.ItemStack; import net.minecraft.core.player.inventory.container.ContainerCrafting; @@ -35,9 +36,38 @@ public abstract class RecipeEntryCrafting extends RecipeEntryBase public abstract boolean matchesQuery(SearchQuery query); + public boolean consumesContainer() { + return false; + } + + public ItemStack[] onCraftResult(ContainerCrafting containerCrafting) { + ItemStack[] returnStack = new ItemStack[9]; + for (int i = 0; i < containerCrafting.getContainerSize(); i++) { + ItemStack itemstack1 = containerCrafting.getItem(i); + if (itemstack1 == null) { + continue; + } + + ItemStack gridStackSnapshot = ItemStack.copyItemStack(itemstack1); + containerCrafting.removeItem(i, 1); + + if (!consumesContainer()) { + + if (gridStackSnapshot.getItem() instanceof IItemContainer customContainer) { + if (customContainer.hasContainerItem(gridStackSnapshot)) { + containerCrafting.setItem(i, customContainer.getContainerItemStack(gridStackSnapshot)); + } + } + else if (gridStackSnapshot.getItem().hasContainerItem()) { + assert gridStackSnapshot.getItem().getContainerItem() != null; + containerCrafting.setItem(i, new ItemStack(gridStackSnapshot.getItem().getContainerItem())); + } + } + } + return returnStack; + } + public abstract ItemStack getCraftingResult(ContainerCrafting containerCrafting); public abstract int getRecipeSize(); - - public abstract ItemStack[] onCraftResult(ContainerCrafting containerCrafting); } diff --git a/game/core/src/main/java/net/minecraft/core/data/registry/recipe/entry/RecipeEntryCraftingShaped.java b/game/core/src/main/java/net/minecraft/core/data/registry/recipe/entry/RecipeEntryCraftingShaped.java index 2a9c91fb3..b15a81821 100644 --- a/game/core/src/main/java/net/minecraft/core/data/registry/recipe/entry/RecipeEntryCraftingShaped.java +++ b/game/core/src/main/java/net/minecraft/core/data/registry/recipe/entry/RecipeEntryCraftingShaped.java @@ -9,6 +9,7 @@ import net.minecraft.core.data.registry.recipe.RecipeNamespace; import net.minecraft.core.data.registry.recipe.RecipeSymbol; import net.minecraft.core.data.registry.recipe.adapter.RecipeCraftingShapedJsonAdapter; import net.minecraft.core.data.registry.recipe.adapter.RecipeJsonAdapter; +import net.minecraft.core.item.IItemContainer; import net.minecraft.core.item.ItemStack; import net.minecraft.core.player.inventory.container.ContainerCrafting; @@ -193,19 +194,8 @@ public class RecipeEntryCraftingShaped extends RecipeEntryCrafting= food.getTicksPerHeal()) { - tickCounter = 0; - healRemaining--; - entity.heal(1); + this.tickCounter++; + + if (this.tickCounter >= this.foodItem.getTicksPerHeal(this.stack)) { + this.tickCounter = 0; + this.healRemaining--; + this.entity.heal(1); } } -} +} \ No newline at end of file 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 e857d5465..6b58551ce 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 @@ -40,7 +40,7 @@ public abstract class Mob extends Entity { public static boolean SPAWN_NO_AI = false; public static final int DATA_VARIANT = 1; public static final int DATA_HEALTH = 2; - protected @NotNull Map consumedFood = new HashMap<>(); + protected Map consumedFood = new HashMap<>(); public int heartsHalvesLife; // public float timeOffs; // public float rotA; @@ -318,15 +318,15 @@ public abstract class Mob extends Entity { } } - List finishedFood = new ArrayList<>(); - for (Map.Entry entry : this.consumedFood.entrySet()) { + List finishedFood = new ArrayList<>(); + for (Map.Entry entry : this.consumedFood.entrySet()) { entry.getValue().tick(); if (entry.getValue().isFinished()) { finishedFood.add(entry.getKey()); } } - for (ItemFood food : finishedFood) { - this.consumedFood.remove(food); + for (String foodKey : finishedFood) { + this.consumedFood.remove(foodKey); } this.prevRotationUnused = this.unusedRotation1; this.yBodyRotO = this.yBodyRot; @@ -480,15 +480,20 @@ public abstract class Mob extends Entity { return totalHealingRemaining; } - public void eatFood(ItemFood food) { - if (food == null) return; - if (food.getTicksPerHeal() == 0 || this.world.getGameRuleValue(GameRules.INSTANT_HEALING)) { - heal(food.getHealAmount()); + public void eatFood(ItemStack stack) { + if (stack == null || !(stack.getItem() instanceof ItemFood)) return; + + ItemFood foodItem = (ItemFood) stack.getItem(); + + if (foodItem.getTicksPerHeal(stack) == 0 || this.world.getGameRuleValue(GameRules.INSTANT_HEALING)) { + heal(foodItem.getHealAmount(stack)); } else { - if (this.consumedFood.containsKey(food)) { - this.consumedFood.get(food).addFood(); + String key = stack.getItemKey(); + + if (this.consumedFood.containsKey(key)) { + this.consumedFood.get(key).addFood(stack); } else { - this.consumedFood.put(food, new ConsumedFood(this, food)); + this.consumedFood.put(key, new ConsumedFood(this, stack)); } } } diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/MobCow.java b/game/core/src/main/java/net/minecraft/core/entity/animal/MobCow.java index 7ea0ed3d0..12e6eb0e4 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/animal/MobCow.java +++ b/game/core/src/main/java/net/minecraft/core/entity/animal/MobCow.java @@ -1,11 +1,10 @@ package net.minecraft.core.entity.animal; import net.minecraft.core.WeightedRandomLootObject; -import net.minecraft.core.entity.AgedMob; -import net.minecraft.core.entity.MobAge; import net.minecraft.core.entity.player.Player; +import net.minecraft.core.item.ItemBucket; +import net.minecraft.core.item.ItemBucketSteel; import net.minecraft.core.item.Items; -import net.minecraft.core.item.ItemBucketEmpty; import net.minecraft.core.item.ItemStack; import com.mojang.nbt.tags.CompoundTag; import net.minecraft.core.item.tag.ItemTags; @@ -80,14 +79,14 @@ public class MobCow } @Override - public boolean interact(@NotNull Player player) - { + public boolean interact(@NotNull Player player) { ItemStack itemstack = player.inventory.getCurrentItem(); - if(itemstack != null && itemstack.itemID == Items.BUCKET.id) - { - ItemBucketEmpty.useBucket(player, new ItemStack(Items.BUCKET_MILK)); + + if (itemstack != null && itemstack.getItem() instanceof ItemBucket) { + ItemBucket.useBucket(itemstack, player, this.world, ItemBucket.STATE_MILK); return true; } + return super.interact(player); } diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java b/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java index c7c69cf40..a4665d0a3 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java +++ b/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java @@ -656,7 +656,7 @@ public class MobWolf player.inventory.setItem(player.inventory.getCurrentSlot(), null); } } - heal(itemfood.getHealAmount()); + heal(itemfood.getHealAmount(itemstack)); return true; } } diff --git a/game/core/src/main/java/net/minecraft/core/entity/monster/MobSnowman.java b/game/core/src/main/java/net/minecraft/core/entity/monster/MobSnowman.java index 0dec555e9..b9d2ce69d 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/monster/MobSnowman.java +++ b/game/core/src/main/java/net/minecraft/core/entity/monster/MobSnowman.java @@ -4,6 +4,9 @@ import net.minecraft.core.WeightedRandomLootObject; import net.minecraft.core.block.Blocks; import net.minecraft.core.entity.Entity; import net.minecraft.core.entity.projectile.ProjectileSnowball; +import net.minecraft.core.item.ItemBucket; +import net.minecraft.core.item.ItemBucketSteel; +import net.minecraft.core.item.ItemStack; import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.item.Items; import net.minecraft.core.world.World; @@ -103,11 +106,13 @@ public class MobSnowman extends MobMonster } @Override - protected void dropDeathItems() - { - if (random.nextInt(1000) == 0){ - dropItem(Items.BUCKET_ICECREAM.id, 1); + protected void dropDeathItems() { + if (random.nextInt(1000) == 0) { + dropItem(ItemBucket.createItemStack(Items.BUCKET_IRON, ItemBucket.STATE_ICECREAM, 1), 0.0F); + } else if (random.nextInt(8192) == 0) { + dropItem(ItemBucket.createItemStack(Items.BUCKET_STEEL, ItemBucket.STATE_ICECREAM, 3), 0.0F); } + super.dropDeathItems(); } } diff --git a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java index ad5c30688..6a57f5029 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java +++ b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java @@ -35,6 +35,7 @@ import net.minecraft.core.enums.ArtType; import net.minecraft.core.enums.EnumDropCause; import net.minecraft.core.enums.EnumSleepStatus; import net.minecraft.core.item.Item; +import net.minecraft.core.item.ItemBucket; import net.minecraft.core.item.ItemStack; import net.minecraft.core.item.Items; import net.minecraft.core.item.tool.ItemToolSword; diff --git a/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java b/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java index 09b9cfc3e..fabb99dc7 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java +++ b/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java @@ -802,11 +802,11 @@ public class EntityMinecart extends Entity implements Container { break; case FURNACE_CART: ItemStack itemstack = player.inventory.getCurrentItem(); - if (itemstack != null && LookupFuelFurnace.instance.getFuelYield(itemstack.itemID) > 0 && itemstack.consumeItem(player)) { + if (itemstack != null && LookupFuelFurnace.instance.getFuelYield(itemstack) > 0 && itemstack.consumeItem(player)) { if (itemstack.stackSize <= 0) { player.inventory.setItem(player.inventory.getCurrentSlot(), null); } - setFuel(getFuel() + MathHelper.round(((LookupFuelFurnace.instance.getFuelYield(itemstack.itemID) / 1600F) * 1200))); + setFuel(getFuel() + MathHelper.round(((LookupFuelFurnace.instance.getFuelYield(itemstack) / 1600F) * 1200))); } this.xPush = this.x - player.x; this.zPush = this.z - player.z; diff --git a/game/core/src/main/java/net/minecraft/core/item/IFood.java b/game/core/src/main/java/net/minecraft/core/item/IFood.java new file mode 100644 index 000000000..14cce954e --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/item/IFood.java @@ -0,0 +1,10 @@ +package net.minecraft.core.item; + +public interface IFood { + + int getHealAmount(); + + int getTicksPerHeal(); + + boolean getIsWolfsFavoriteMeat(); +} diff --git a/game/core/src/main/java/net/minecraft/core/item/IItemContainer.java b/game/core/src/main/java/net/minecraft/core/item/IItemContainer.java new file mode 100644 index 000000000..377480961 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/item/IItemContainer.java @@ -0,0 +1,9 @@ +package net.minecraft.core.item; + +public interface IItemContainer { + + boolean hasContainerItem(ItemStack stack); + + ItemStack getContainerItemStack(ItemStack stack); + +} \ No newline at end of file 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 9418e8ead..cd66d85aa 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 @@ -1,98 +1,493 @@ package net.minecraft.core.item; -import net.minecraft.core.block.entity.TileEntityActivator; -import net.minecraft.core.util.helper.Direction; -import net.minecraft.core.util.phys.HitResult; +import com.mojang.nbt.tags.CompoundTag; import net.minecraft.core.block.Block; +import net.minecraft.core.block.BlockLogicFluid; import net.minecraft.core.block.Blocks; +import net.minecraft.core.block.entity.TileEntityActivator; +import net.minecraft.core.block.material.Materials; import net.minecraft.core.block.tag.BlockTags; +import net.minecraft.core.entity.animal.MobCow; import net.minecraft.core.entity.player.Player; import net.minecraft.core.enums.EnumDropCause; import net.minecraft.core.sound.SoundCategory; +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.world.Dimension; +import net.minecraft.core.util.phys.AABB; +import net.minecraft.core.util.phys.HitResult; import net.minecraft.core.world.World; -import net.minecraft.core.world.biome.Biome; -import net.minecraft.core.world.biome.BiomeTags; import net.minecraft.core.world.pos.TilePos; import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.joml.primitives.AABBd; +import org.joml.primitives.AABBdc; + +import java.util.*; + +public abstract class ItemBucket extends ItemFood implements IItemContainer { + + public record BucketState( + String name, + boolean isEdible, + int healAmount, + int ticksPerHeal, + @Nullable Block fluidBlock, + boolean canPlace + ) { + + + /** + * Constructor for Food/Edible Buckets + */ + public BucketState(String name, int healAmount, int ticksPerHeal) { + this(name, true, healAmount, ticksPerHeal, null, false); + } + /** + * Constructor for Fluid Buckets + */ + public BucketState(String name, @Nullable Block fluidBlock, boolean canPlace) { + this(name, false, 0, 0, fluidBlock, canPlace); + } + } + + private static final Map STATE_REGISTRY = new LinkedHashMap<>(); + public static final NamespaceID STATE_EMPTY = new NamespaceID("minecraft", "empty"); + public static final NamespaceID STATE_WATER = new NamespaceID("minecraft", "water"); + public static final NamespaceID STATE_LAVA = new NamespaceID("minecraft", "lava"); + public static final NamespaceID STATE_MILK = new NamespaceID("minecraft", "milk"); + public static final NamespaceID STATE_ICECREAM = new NamespaceID("minecraft", "icecream"); + + static { + registerState(STATE_EMPTY, new BucketState("empty", null, false)); + registerState(STATE_WATER, new BucketState("water", Blocks.FLUID_WATER_FLOWING, true)); + registerState(STATE_LAVA, new BucketState("lava", Blocks.FLUID_LAVA_FLOWING, true)); + registerState(STATE_MILK, new BucketState("milk", 0, 0)); + registerState(STATE_ICECREAM, new BucketState("icecream", 15, 4)); + } + + public static NamespaceID registerState(NamespaceID id, BucketState state) { + if (STATE_REGISTRY.containsKey(id)) { + throw new IllegalArgumentException("Bucket state '" + id + "' is already registered!"); + } + STATE_REGISTRY.put(id, state); + return id; + } + + public static BucketState getBucketState(NamespaceID id) { + if (id == null || !STATE_REGISTRY.containsKey(id)) { + return STATE_REGISTRY.get(STATE_EMPTY); + } + return STATE_REGISTRY.get(id); + } + + public static String getStateName(NamespaceID id) { + return id.value(); + } + + public static Set getRegisteredStateIds() { + return STATE_REGISTRY.keySet(); + } -import java.util.Random; + public static boolean isFluid(NamespaceID id) { return getBucketState(id).fluidBlock() != null; } + public static boolean isEdible(NamespaceID id) { return getBucketState(id).isEdible(); } + public static int getMaxStates() { return STATE_REGISTRY.size(); } -public class ItemBucket extends Item { - private final @Nullable Block blockToPlace; + @Override + public int getHealAmount(ItemStack stack) {return getBucketState(getState(stack)).healAmount();} + @Override + public int getTicksPerHeal(ItemStack stack) {return getBucketState(getState(stack)).ticksPerHeal();} + + @Nullable + private NamespaceID getFluidStateAt(World world, TilePosc tilePos) { + if (world.getBlockMaterial(tilePos) == Materials.WATER) return STATE_WATER; + if (world.getBlockMaterial(tilePos) == Materials.LAVA) return STATE_LAVA; + return null; + } + + public final int maxCharges; - public ItemBucket(@NotNull String name, @NotNull String namespaceId, int id, @Nullable Block blockToPlace) { - super(name, namespaceId, id); - this.maxStackSize = 1; - this.blockToPlace = blockToPlace; + public ItemBucket(@NotNull String name, @NotNull String namespaceId, int id, int maxCharges) { + super(name, namespaceId, id, 0, 0, false, 64); + this.maxCharges = maxCharges; + this.maxStackSize = 64; } @Override - public @Nullable ItemStack onUse(@NotNull ItemStack selfStack, @NotNull World world, @NotNull Player player) { - if (this.blockToPlace == null) { - // Milk - return new ItemStack(Items.BUCKET); + public @NotNull String getLanguageKey(@NotNull ItemStack itemStack){ + NamespaceID state = getState(itemStack); + if (STATE_EMPTY.equals(state)) return super.getKey(); + return super.getKey() + "." + getStateName(state).replace("_", ""); + } + + @Override + public ItemStack onUse(@NotNull ItemStack itemStack, @NotNull World world, @NotNull Player player) { + NamespaceID currentStateId = getState(itemStack); + BucketState currentState = getBucketState(currentStateId); + + if (currentState.isEdible() && !currentState.canPlace()) { + return handleAirClick(itemStack, world, player); } double reachDistance = player.getGamemode().getBlockReachDistance(); - HitResult rayCast = player.rayCast(reachDistance, 1f, false, false, false); + HitResult hitResultFluid = player.rayCast(reachDistance, 1f, true, false, false); + HitResult hitResultNoFluid = player.rayCast(reachDistance, 1f, false, false, false); - if (!(rayCast instanceof HitResult.Tile hitTile)) { - return selfStack; + if (hitResultFluid == null) { + return handleAirClick(itemStack, world, player); + } else if (hitResultFluid instanceof HitResult.Entity) { + return handleEntityClick(itemStack, world, player); + } else if (hitResultFluid instanceof HitResult.Tile hitTileFluid) { + TilePosc tilePos = hitTileFluid.tilePos; + boolean isSourceBlock = world.getBlockData(tilePos) == 0; + + if (isSourceBlock) { + NamespaceID targetStateId = getFluidStateAt(world, tilePos); + + boolean isEmptyScoop = STATE_EMPTY.equals(currentStateId); + boolean isRefillScoop = currentStateId.equals(targetStateId) && getCharges(itemStack) < this.maxCharges; + + if (targetStateId != null && (isEmptyScoop || isRefillScoop)) { + return tryPickupFluid(itemStack, world, player, tilePos, targetStateId); + } + } + + if (currentState.canPlace() && hitResultNoFluid instanceof HitResult.Tile hitTileNoFluid) { + return tryPlaceFluid(itemStack, world, player, hitTileNoFluid); + } } - TilePos rayCastPos = new TilePos(hitTile.tilePos); - if (!world.canMineBlock(player, rayCastPos)) { - return selfStack; + 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; + + 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); + + if (itemStack.stackSize > 1) { + return splitBucket(itemStack, player, targetState, world); + } else { + NamespaceID currentState = getState(itemStack); + if (STATE_EMPTY.equals(currentState)) { + setState(itemStack, targetState); + setCharges(itemStack, 1); + } else { + setCharges(itemStack, getCharges(itemStack) + 1); + } + return itemStack; } + } - Block block = world.getBlockType(rayCastPos); - if (!block.hasTag(BlockTags.PLACE_OVERWRITES) && !block.hasTag(BlockTags.BROKEN_BY_FLUIDS)) { + protected ItemStack tryPlaceFluid(ItemStack itemStack, World world, Player player, HitResult.Tile hitTile) { + TilePos rayCastPos = new TilePos(hitTile.tilePos); + if (!world.canMineBlock(player, rayCastPos)) return itemStack; + + Block blockAtPos = world.getBlockType(rayCastPos); + if (!blockAtPos.hasTag(BlockTags.PLACE_OVERWRITES) && !blockAtPos.hasTag(BlockTags.BROKEN_BY_FLUIDS)) { Side side = hitTile.side; rayCastPos.x += side.getOffsetX(); rayCastPos.y += side.getOffsetY(); rayCastPos.z += side.getOffsetZ(); } - if (rayCastPos.y < 0 || rayCastPos.y >= world.getHeightBlocks()) { - return selfStack; - } + if (rayCastPos.y < 0 || rayCastPos.y >= world.getHeightBlocks()) return itemStack; if (world.isAirBlock(rayCastPos) || !world.getBlockMaterial(rayCastPos).isSolid()) { - if (this.blockToPlace == Blocks.FLUID_WATER_FLOWING) { - world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, rayCastPos.x + 0.5F, rayCastPos.y + 0.5F, rayCastPos.z + 0.5F, "liquid.splash", 0.5f, 1.0f); + NamespaceID stateId = getState(itemStack); + BucketState bucketState = getBucketState(stateId); + + if (bucketState.fluidBlock() != null) { + + if(STATE_LAVA.equals(stateId)){ + BlockLogicFluid.fizz(world, rayCastPos); + world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, rayCastPos.x + 0.5F, rayCastPos.y + 0.5F, rayCastPos.z + 0.5F, "liquid.lavapop", 1f, 1f); + } + if(STATE_WATER.equals(stateId)){ + world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, rayCastPos.x + 0.5F, rayCastPos.y + 0.5F, rayCastPos.z + 0.5F, "liquid.splash", 0.65f, 1f); + } + + final Block replacedBlock = world.getBlockType(rayCastPos); + final int replacedData = world.getBlockData(rayCastPos); + + world.setBlockTypeNotify(rayCastPos, bucketState.fluidBlock()); + replacedBlock.dropWithCause(world, EnumDropCause.WORLD, rayCastPos, replacedData, null, null); + + player.swingItem(); + + if (player.getGamemode().hasBlockConsumption()) { + setCharges(itemStack, getCharges(itemStack) - 1); + if (getCharges(itemStack) == 0) setState(itemStack, STATE_EMPTY); + } } - final var replacedBlock = world.getBlockType(rayCastPos); - final var replacedMeta = world.getBlockData(rayCastPos); - world.setBlockTypeNotify(rayCastPos, this.blockToPlace); - replacedBlock.dropWithCause(world, EnumDropCause.WORLD, rayCastPos, replacedMeta, null, null); - // is this being called afterwards intentional? - - player.swingItem(); - if (player.getGamemode().hasBlockConsumption()) { - return new ItemStack(Items.BUCKET); + } + return itemStack; + } + + protected ItemStack handleAirClick(ItemStack itemStack, World world, Player player) { + NamespaceID state = getState(itemStack); + if (isEdible(state)) { + return handleEdibleConsumption(itemStack, world, player); + } + return itemStack; + } + + protected ItemStack handleEntityClick(ItemStack itemStack, World world, Player player) { + return handleAirClick(itemStack, world, player); + } + + protected ItemStack handleEdibleConsumption(@NotNull ItemStack itemStack, @NotNull World world, @NotNull Player player) { + NamespaceID state = getState(itemStack); + BucketState bucketState = getBucketState(state); + + if (player.getHealth() < player.getMaxHealth() || STATE_MILK.equals(state)) { + player.eatFood(itemStack); + String sound = bucketState.ticksPerHeal() >= 10 ? "random.bite_extended" : "random.bite"; + world.playSoundAtEntity(player, player, sound, 0.5f + (itemRand.nextFloat() - itemRand.nextFloat()) * 0.1f, 1.1f + (itemRand.nextFloat() - itemRand.nextFloat()) * 0.1f); + + if (itemStack.stackSize == 1) { + return this.getContainerItemStack(itemStack); + } else { + itemStack.stackSize--; + ItemStack container = this.getContainerItemStack(itemStack); + player.inventory.insertItem(container, true); } } + return itemStack; + } + + public static void useBucket(ItemStack itemStack, Player player, World world, NamespaceID targetState) { + boolean isStacked = itemStack.stackSize > 1; + NamespaceID currentState = getState(itemStack); + + int limit = (itemStack.getItem() instanceof ItemBucket bucket) ? bucket.maxCharges : 1; - return selfStack; + if (STATE_EMPTY.equals(currentState) || (currentState.equals(targetState) && getCharges(itemStack) < limit)) { + if (!isStacked) { + if (STATE_EMPTY.equals(currentState)) { + setState(itemStack, targetState); + } + setCharges(itemStack, getCharges(itemStack) + 1); + } else { + splitBucket(itemStack, player, targetState, world); + } + } + } + + protected static ItemStack splitBucket(@NotNull ItemStack itemStack, @NotNull Player player, NamespaceID state, @NotNull World world) { + itemStack.stackSize--; + ItemStack splitItemStack = new ItemStack(itemStack.getItem(), 1); + setState(splitItemStack, state); + setCharges(splitItemStack, 1); + + player.inventory.insertItem(splitItemStack, true); + if (splitItemStack.stackSize > 0) { + world.dropItem((int) player.x, (int) player.y, (int) player.z, splitItemStack); + } + return itemStack; + } + + public static int getCharges(@NotNull ItemStack stack) { + return stack.getData().getIntegerOrDefault("Charges", 0); + } + + public static void setCharges(@NotNull ItemStack stack, int charges) { + CompoundTag tag = stack.getData(); + if (charges <= 0) { + tag.getValue().remove("State"); + tag.getValue().remove("Charges"); + } else { + tag.putInt("Charges", charges); + } + } + + public static NamespaceID getState(@NotNull ItemStack stack) { + CompoundTag tag = stack.getData(); + if (tag.containsKey("State")) { + String stateStr = tag.getString("State"); + if (stateStr.contains(":")) { + try { + return new NamespaceID(stateStr); + } catch (HardIllegalArgumentException ignored) { + } + } + } + return STATE_EMPTY; + } + + public static void setState(@NotNull ItemStack stack, NamespaceID state) { + CompoundTag tag = stack.getData(); + if (state == null || STATE_EMPTY.equals(state)) { + tag.getValue().remove("State"); + tag.getValue().remove("Charges"); + } else { + tag.putString("State", state.toString()); + } } @Override - public void onUseByActivator(@NotNull ItemStack selfStack, @NotNull World world, @NotNull TileEntityActivator activator, @NotNull Random random, @NotNull TilePosc blockPos, @NotNull Direction direction, double offX, double offY, double offZ) { - if (this.blockToPlace == null) { - selfStack.itemID = Items.BUCKET.id; - return; + public int getItemStackLimit(@Nullable ItemStack itemStack) { + return (itemStack == null || STATE_EMPTY.equals(getState(itemStack))) ? 64 : 1; + } + + @Override + public boolean hasContainerItem(ItemStack stack) { + return true; + } + + @Override + public ItemStack getContainerItemStack(ItemStack stack) { + ItemStack leftover = stack.copy(); + leftover.stackSize = 1; + + int currentCharges = getCharges(leftover); + if (currentCharges > 1) { + setCharges(leftover, currentCharges - 1); + } else { + setState(leftover, STATE_EMPTY); } + + return leftover; + } + + public static ItemStack createItemStack(Item type, NamespaceID state, int charges) { + ItemStack stack = new ItemStack(type); + setState(stack, state); + setCharges(stack, charges); + return stack; + } + + public static ItemStack createRecipeInput(Item type, NamespaceID state) { + ItemStack stack = new ItemStack(type); + setState(stack, state); + return stack; + } + + @Override + public void onUseByActivator(@NotNull ItemStack selfStack, @NotNull World world, @NotNull TileEntityActivator activator, @NotNull Random random, @NotNull TilePosc blockPos, @NotNull Direction direction, double offX, double offY, double offZ) { + NamespaceID currentStateId = getState(selfStack); + BucketState currentState = getBucketState(currentStateId); + TilePos posAhead = blockPos.add(direction, new TilePos()); - Block b = world.getBlockType(posAhead); - if (b.hasTag(BlockTags.PLACE_OVERWRITES) || b.hasTag(BlockTags.BROKEN_BY_FLUIDS)) { - world.setBlockTypeNotify(posAhead, this.blockToPlace); - world.getBlockType(posAhead).dropWithCause(world, EnumDropCause.WORLD, posAhead, world.getBlockData(posAhead), null, null); + Block blockAhead = world.getBlockType(posAhead); + + boolean isEmptyScoop = STATE_EMPTY.equals(currentStateId); + boolean isMilkScoop = STATE_MILK.equals(currentStateId) && getCharges(selfStack) < this.maxCharges; + + if (isEmptyScoop || isMilkScoop) { + AABBd cowArea = new AABBd(posAhead.x, posAhead.y, posAhead.z, posAhead.x + 1, posAhead.y + 1, posAhead.z + 1); + List cows = world.getEntitiesWithinAABB(MobCow.class, cowArea); + + if (!cows.isEmpty()) { + if (selfStack.stackSize > 1 && !canActivatorAccept(activator, selfStack.getItem(), STATE_MILK)) { + return; + } + + world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, posAhead.x + 0.5F, posAhead.y + 0.5F, posAhead.z + 0.5F, "item.pickup", 2.2f, 0.5f); + handleActivatorFill(selfStack, STATE_MILK, activator); + return; + } + } + + boolean isSourceBlock = world.getBlockData(posAhead) == 0; + if (isSourceBlock) { + NamespaceID targetStateId = getFluidStateAt(world, posAhead); + boolean isRefillScoop = currentStateId.equals(targetStateId) && getCharges(selfStack) < this.maxCharges; + + if (targetStateId != null && (isEmptyScoop || isRefillScoop)) { + if (selfStack.stackSize > 1 && !canActivatorAccept(activator, selfStack.getItem(), targetStateId)) { + return; + } - selfStack.itemID = Items.BUCKET.id; + world.setBlockTypeNotify(posAhead, Blocks.AIR); + world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, posAhead.x + 0.5F, posAhead.y + 0.5F, posAhead.z + 0.5F, "item.pickup", 2.2f, 0.5f); + + handleActivatorFill(selfStack, targetStateId, activator); + return; + } + } + + if (currentState.canPlace() && currentState.fluidBlock() != null) { + if (blockAhead.hasTag(BlockTags.PLACE_OVERWRITES) || blockAhead.hasTag(BlockTags.BROKEN_BY_FLUIDS)) { + + if (STATE_LAVA.equals(currentStateId)) { + BlockLogicFluid.fizz(world, posAhead); + world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, posAhead.x + 0.5F, posAhead.y + 0.5F, posAhead.z + 0.5F, "liquid.lavapop", 1f, 1f); + } else if (STATE_WATER.equals(currentStateId)) { + world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, posAhead.x + 0.5F, posAhead.y + 0.5F, posAhead.z + 0.5F, "liquid.splash", 0.65f, 1f); + } + + int replacedData = world.getBlockData(posAhead); + world.setBlockTypeNotify(posAhead, currentState.fluidBlock()); + blockAhead.dropWithCause(world, EnumDropCause.WORLD, posAhead, replacedData, null, null); + + setCharges(selfStack, getCharges(selfStack) - 1); + if (getCharges(selfStack) == 0) { + setState(selfStack, STATE_EMPTY); + } + } + } + } + + /** + * Handles stack splitting and filling for the activator. + * Assumes inventory space has already been verified via canActivatorAccept. + */ + private void handleActivatorFill(ItemStack selfStack, NamespaceID targetStateId, TileEntityActivator activator) { + NamespaceID currentStateId = getState(selfStack); + + if (selfStack.stackSize > 1) { + selfStack.stackSize--; + + ItemStack filledBucket = new ItemStack(selfStack.getItem(), 1); + setState(filledBucket, targetStateId); + setCharges(filledBucket, 1); + + for (int i = 0; i < activator.getContainerSize(); i++) { + if (activator.locked(i)) continue; + + ItemStack slotStack = activator.getItem(i); + + if (slotStack == null) { + activator.setItem(i, filledBucket); + break; + } + else if (slotStack.itemID == filledBucket.itemID && getState(slotStack).equals(getState(filledBucket)) && slotStack.stackSize < slotStack.getMaxStackSize()) { + slotStack.stackSize++; + break; + } + } + } else { + if (STATE_EMPTY.equals(currentStateId)) { + setState(selfStack, targetStateId); + setCharges(selfStack, 1); + } else { + setCharges(selfStack, getCharges(selfStack) + 1); + } + } + } + + /** + * Checks if the activator has a valid, unlocked slot to accept the specified filled bucket. + */ + private boolean canActivatorAccept(TileEntityActivator activator, Item item, NamespaceID targetState) { + for (int i = 0; i < activator.getContainerSize(); i++) { + if (activator.locked(i)) continue; + + ItemStack slotStack = activator.getItem(i); + + if (slotStack == null) { + return true; + } + + if (slotStack.itemID == item.id && getState(slotStack).equals(targetState) && slotStack.stackSize < slotStack.getMaxStackSize()) { + return true; + } } + return false; } -} +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemBucketEmpty.java b/game/core/src/main/java/net/minecraft/core/item/ItemBucketEmpty.java deleted file mode 100644 index a13f2fa63..000000000 --- a/game/core/src/main/java/net/minecraft/core/item/ItemBucketEmpty.java +++ /dev/null @@ -1,93 +0,0 @@ -package net.minecraft.core.item; - -import net.minecraft.core.block.Blocks; -import net.minecraft.core.block.entity.TileEntityActivator; -import net.minecraft.core.block.material.Materials; -import net.minecraft.core.entity.animal.MobCow; -import net.minecraft.core.entity.player.Player; -import net.minecraft.core.util.helper.Direction; -import net.minecraft.core.util.phys.HitResult; -import net.minecraft.core.world.World; -import net.minecraft.core.world.pos.TilePos; -import net.minecraft.core.world.pos.TilePosc; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.joml.primitives.AABBd; -import org.joml.primitives.AABBdc; - -import java.util.List; -import java.util.Random; - -public class ItemBucketEmpty extends Item { - - public ItemBucketEmpty(@NotNull String name, @NotNull String namespaceId, int id) { - super(name, namespaceId, id); - this.maxStackSize = 64; - } - - @Override - public @Nullable ItemStack onUse(@NotNull ItemStack selfStack, @NotNull World world, @NotNull Player player) { - double reachDistance = player.getGamemode().getBlockReachDistance(); - HitResult hitResult = player.rayCast(reachDistance, 1f, true, false, false); - - if (hitResult == null) { - return selfStack; - } - if (hitResult instanceof HitResult.Tile hitTile) { - if (!world.canMineBlock(player, hitTile.tilePos)) { - return selfStack; - } else if (world.getBlockMaterial(hitTile.tilePos) == Materials.WATER && world.getBlockData(hitTile.tilePos) == 0) { - if (useBucket(player, new ItemStack(Items.BUCKET_WATER))) { - world.setBlockTypeNotify(hitTile.tilePos, Blocks.AIR); - player.swingItem(); - } - } else if (world.getBlockMaterial(hitTile.tilePos) == Materials.LAVA && world.getBlockData(hitTile.tilePos) == 0) { - if (useBucket(player, new ItemStack(Items.BUCKET_LAVA))) { - world.setBlockTypeNotify(hitTile.tilePos, Blocks.AIR); - player.swingItem(); - } - } - } - return selfStack; - } - - @Override - public void onUseByActivator(@NotNull ItemStack selfStack, @NotNull World world, @NotNull TileEntityActivator activator, @NotNull Random random, @NotNull TilePosc blockPos, @NotNull Direction direction, double offX, double offY, double offZ) { - if (selfStack.stackSize > 1) { // TODO figure out wtf to do for stacked buckets for this - return; - } - - TilePos shiftedPos = blockPos.add(direction, new TilePos()); - if (world.getBlockMaterial(shiftedPos) == Materials.WATER && world.getBlockData(shiftedPos) == 0) { - world.setBlockTypeNotify(shiftedPos, Blocks.AIR); - selfStack.itemID = Items.BUCKET_WATER.id; - return; - } else if (world.getBlockMaterial(shiftedPos) == Materials.LAVA && world.getBlockData(shiftedPos) == 0) { - world.setBlockTypeNotify(shiftedPos, Blocks.AIR); - selfStack.itemID = Items.BUCKET_LAVA.id; - return; - } - - AABBdc box = new AABBd(shiftedPos.x, shiftedPos.y, shiftedPos.z, shiftedPos.x + 1, shiftedPos.y + 1, shiftedPos.z + 1); - List entities = world.getEntitiesWithinAABB(MobCow.class, box); - if (!entities.isEmpty()) { - selfStack.itemID = Items.BUCKET_MILK.id; - } - } - - public static boolean useBucket(@NotNull Player player, @NotNull ItemStack itemToGive) { - ItemStack currentItem = player.inventory.getCurrentItem(); - if (currentItem == null || currentItem.stackSize <= 1) { - player.inventory.setItem(player.inventory.getCurrentSlot(), itemToGive); - return true; - } else { - player.inventory.insertItem(itemToGive, true); - if (itemToGive.stackSize < 1) { - player.inventory.getCurrentItem().consumeItem(player); - return true; - } - } - return false; - } - -} diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemBucketIceCream.java b/game/core/src/main/java/net/minecraft/core/item/ItemBucketIceCream.java deleted file mode 100644 index acd284640..000000000 --- a/game/core/src/main/java/net/minecraft/core/item/ItemBucketIceCream.java +++ /dev/null @@ -1,22 +0,0 @@ -package net.minecraft.core.item; - -import net.minecraft.core.entity.player.Player; -import net.minecraft.core.world.World; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class ItemBucketIceCream extends ItemFood { - - public ItemBucketIceCream(@NotNull String name, @NotNull String namespaceId, int id, int healAmount, int ticksPerHeal) { - super(name, namespaceId, id, healAmount, ticksPerHeal, false, 1); - this.maxStackSize = 1; - } - @Override - public @Nullable ItemStack onUse(@NotNull ItemStack selfStack, @NotNull World world, @NotNull Player player) { - if (player.getHealth() < player.getMaxHealth()){ - super.onUse(selfStack, world, player); - return new ItemStack(Items.BUCKET); - } - return selfStack; - } -} diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemBucketIron.java b/game/core/src/main/java/net/minecraft/core/item/ItemBucketIron.java new file mode 100644 index 000000000..95905d071 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/item/ItemBucketIron.java @@ -0,0 +1,12 @@ +package net.minecraft.core.item; + +import org.jetbrains.annotations.NotNull; + +public class ItemBucketIron extends ItemBucket { + + public static final int MAX_CHARGES = 1; + + public ItemBucketIron(@NotNull String name, @NotNull String namespaceId, int id) { + super(name, namespaceId, id, MAX_CHARGES); + } +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemBucketSteel.java b/game/core/src/main/java/net/minecraft/core/item/ItemBucketSteel.java new file mode 100644 index 000000000..11b5e8032 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/item/ItemBucketSteel.java @@ -0,0 +1,12 @@ +package net.minecraft.core.item; + +import org.jetbrains.annotations.NotNull; + +public class ItemBucketSteel extends ItemBucket { + + public static final int MAX_CHARGES = 3; + + public ItemBucketSteel(@NotNull String name, @NotNull String namespaceId, int id) { + super(name, namespaceId, id, MAX_CHARGES); + } +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemFood.java b/game/core/src/main/java/net/minecraft/core/item/ItemFood.java index 505f80cab..93a510a53 100644 --- a/game/core/src/main/java/net/minecraft/core/item/ItemFood.java +++ b/game/core/src/main/java/net/minecraft/core/item/ItemFood.java @@ -15,7 +15,6 @@ public class ItemFood extends Item { this.healAmount = healAmount; this.ticksPerHeal = ticksPerHeal; this.isWolfsFavoriteMeat = favouriteWolfMeat; - this.maxStackSize = maxStackSize; } @@ -24,18 +23,17 @@ public class ItemFood extends Item { if(player.getHealth() < player.getMaxHealth() && player.getHealth() + player.getTotalHealingRemaining() < player.getMaxHealth() && selfStack.consumeItem(player)) { - player.eatFood(this); - world.playSoundAtEntity(player, player, this.ticksPerHeal >= 10 ? "random.bite_extended" : "random.bite", 0.5f + (itemRand.nextFloat() - itemRand.nextFloat()) * 0.1f, 1.1f + (itemRand.nextFloat() - itemRand.nextFloat()) * 0.1f); + player.eatFood(selfStack); + world.playSoundAtEntity(player, player, this.getTicksPerHeal(selfStack) >= 10 ? "random.bite_extended" : "random.bite", 0.5f + (itemRand.nextFloat() - itemRand.nextFloat()) * 0.1f, 1.1f + (itemRand.nextFloat() - itemRand.nextFloat()) * 0.1f); } return selfStack; } - public int getHealAmount() - { + public int getHealAmount(ItemStack stack) { return this.healAmount; } - public int getTicksPerHeal() { + public int getTicksPerHeal(ItemStack stack) { return this.ticksPerHeal; } diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemStack.java b/game/core/src/main/java/net/minecraft/core/item/ItemStack.java index 94adda0c5..acd647ec6 100644 --- a/game/core/src/main/java/net/minecraft/core/item/ItemStack.java +++ b/game/core/src/main/java/net/minecraft/core/item/ItemStack.java @@ -20,6 +20,8 @@ import org.jetbrains.annotations.Nullable; import java.util.Objects; +import static net.minecraft.core.world.save.conversion.ItemConverters.legacyBucketConverter; + public final class ItemStack { public int stackSize; @@ -405,6 +407,9 @@ public final class ItemStack { if(nbt == null) { return null; } + + legacyBucketConverter(nbt); + ItemStack stack = new ItemStack(); stack.readFromNBT(nbt); if(stack.stackSize <= 0) { @@ -486,4 +491,8 @@ public final class ItemStack { this.tag = tag; } + public @NotNull ItemStack withTagValue(@NotNull String key, int value) { + this.tag.putInt(key, value); + return this; + } } diff --git a/game/core/src/main/java/net/minecraft/core/item/Items.java b/game/core/src/main/java/net/minecraft/core/item/Items.java index a9a2f7b42..895ae1556 100644 --- a/game/core/src/main/java/net/minecraft/core/item/Items.java +++ b/game/core/src/main/java/net/minecraft/core/item/Items.java @@ -60,6 +60,13 @@ public final class Items { public static Item WHEAT; public static Item FOOD_BREAD; + public static Item BUCKET_IRON; + public static Item BUCKET_STEEL; + //public static Item BUCKET_WATER; + //public static Item BUCKET_LAVA; + //public static Item BUCKET_MILK; + //public static Item BUCKET_ICECREAM; + public static Item ARMOR_HELMET_LEATHER; public static Item ARMOR_CHESTPLATE_LEATHER; public static Item ARMOR_LEGGINGS_LEATHER; @@ -94,9 +101,6 @@ public final class Items { public static Item FOOD_APPLE_GOLD; public static Item SIGN; public static Item DOOR_OAK; - public static Item BUCKET; - public static Item BUCKET_WATER; - public static Item BUCKET_LAVA; public static Item MINECART; public static Item SADDLE; public static Item DOOR_IRON; @@ -104,7 +108,6 @@ public final class Items { public static Item AMMO_SNOWBALL; public static Item BOAT; public static Item LEATHER; - public static Item BUCKET_MILK; public static Item BRICK_CLAY; public static Item CLAY; public static Item SUGARCANE; @@ -171,7 +174,6 @@ public final class Items { public static Item OLIVINE; public static Item AMMO_PEBBLE; public static Item FOOD_CHERRY; - public static Item BUCKET_ICECREAM; public static Item AMMO_ARROW_PURPLE; public static Item LABEL; public static Item JAR; @@ -326,9 +328,9 @@ public final class Items { FOOD_APPLE_GOLD = (new ItemFood("food.apple.gold", "minecraft:item/food_apple_gold", 16450, 42, 0, false, 1)); SIGN = (new ItemSign("sign", "minecraft:item/sign", 16451)); DOOR_OAK = (new ItemDoor("door.oak", "minecraft:item/door_oak", 16452, Blocks.DOOR_PLANKS_OAK_BOTTOM, Blocks.DOOR_PLANKS_OAK_TOP)); - BUCKET = (new ItemBucketEmpty("bucket", "minecraft:item/bucket", 16453)); - BUCKET_WATER = (new ItemBucket("bucket.water", "minecraft:item/bucket_water", 16454, Blocks.FLUID_WATER_FLOWING)).setContainerItem(BUCKET); - BUCKET_LAVA = (new ItemBucket("bucket.lava", "minecraft:item/bucket_lava", 16455, Blocks.FLUID_LAVA_FLOWING)).setContainerItem(BUCKET); + //16453 DO NOT TOUCH THIS ID, LEGACY BUCKET CONVERTS FROM IT + //16454 DO NOT TOUCH THIS ID, LEGACY BUCKET CONVERTS FROM IT + //16455 DO NOT TOUCH THIS ID, LEGACY BUCKET CONVERTS FROM IT MINECART = (new ItemMinecart("minecart", "minecraft:item/minecart", 16456, EntityMinecart.PASSENGER_CART)); SADDLE = (new ItemSaddle("saddle", "minecraft:item/saddle", 16457)); DOOR_IRON = (new ItemDoor("door.iron", "minecraft:item/door_iron", 16458, Blocks.DOOR_IRON_BOTTOM, Blocks.DOOR_IRON_TOP)); @@ -336,7 +338,7 @@ public final class Items { AMMO_SNOWBALL = (new ItemSnowball("ammo.snowball", "minecraft:item/ammo_snowball", 16460)); BOAT = (new ItemBoat("boat", "minecraft:item/boat", 16461)); LEATHER = (new Item("leather", "minecraft:item/leather", 16462)); - BUCKET_MILK = (new ItemBucket("bucket.milk", "minecraft:item/bucket_milk", 16463, null)).setContainerItem(BUCKET); + //16463 DO NOT TOUCH THIS ID, LEGACY BUCKET CONVERTS FROM IT BRICK_CLAY = (new Item("brick.clay", "minecraft:item/brick_clay", 16464)); CLAY = (new Item("clay", "minecraft:item/clay", 16465)); SUGARCANE = (new ItemPlaceable("sugarcane", "minecraft:item/sugarcane", 16466, Blocks.SUGARCANE)); @@ -403,7 +405,7 @@ public final class Items { OLIVINE = (new Item("olivine", "minecraft:item/olivine", 16513)); AMMO_PEBBLE = (new ItemPebble("ammo.pebble", "minecraft:item/ammo_pebble", 16514)); FOOD_CHERRY = (new ItemFood("food.cherry", "minecraft:item/food_cherry", 16515, 2, 2, false, 2)); - BUCKET_ICECREAM = (new ItemBucketIceCream("bucket.icecream", "minecraft:item/bucket_icecream", 16516, 10, 4)).setContainerItem(BUCKET); + //16516 DO NOT TOUCH THIS ID, LEGACY BUCKET CONVERTS FROM IT AMMO_ARROW_PURPLE = (new Item("ammo.arrow.purple", "minecraft:item/ammo_arrow_purple", 16517)).withTags(ItemTags.NOT_IN_CREATIVE_MENU); LABEL = (new ItemLabel("label", "minecraft:item/label", 16518)); JAR = (new ItemJar("jar", "minecraft:item/jar", 16519)); @@ -450,5 +452,8 @@ public final class Items { ARMOR_WOLF_DIAMOND = new ItemArmor<>("armor.wolf.diamond", "minecraft:item/armor_wolf_diamond", 16559, ArmorMaterial.DIAMOND, WolfArmorShape.BODY); ARMOR_WOLF_GOLD = new ItemArmor<>("armor.wolf.gold", "minecraft:item/armor_wolf_gold", 16560, ArmorMaterial.GOLD, WolfArmorShape.BODY); ARMOR_WOLF_STEEL = new ItemArmor<>("armor.wolf.steel", "minecraft:item/armor_wolf_steel", 16561, ArmorMaterial.STEEL, WolfArmorShape.BODY); + + BUCKET_IRON = (new ItemBucketIron("bucket.iron", "minecraft:item/bucket_iron", 16562)); + BUCKET_STEEL = (new ItemBucketSteel("bucket.steel", "minecraft:item/bucket_steel", 16563)); } } diff --git a/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuInventoryCreative.java b/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuInventoryCreative.java index 67c963377..a721eea58 100644 --- a/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuInventoryCreative.java +++ b/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuInventoryCreative.java @@ -3,15 +3,13 @@ package net.minecraft.core.player.inventory.menu; import net.minecraft.core.block.Block; import net.minecraft.core.block.IPainted; import net.minecraft.core.block.tag.BlockTags; -import net.minecraft.core.item.ItemCoal; +import net.minecraft.core.item.*; import net.minecraft.core.item.tag.ItemTags; import net.minecraft.core.lang.I18n; -import net.minecraft.core.item.Item; -import net.minecraft.core.item.Items; -import net.minecraft.core.item.ItemStack; import net.minecraft.core.block.Blocks; import net.minecraft.core.player.inventory.container.ContainerInventory; import net.minecraft.core.player.inventory.slot.SlotCreative; +import net.minecraft.core.util.collection.NamespaceID; import net.minecraft.core.util.helper.DyeColor; import java.util.ArrayList; @@ -156,6 +154,16 @@ public class MenuInventoryCreative extends MenuInventory for (DyeColor color : DyeColor.values()) { creativeItems.add(new ItemStack(item, 1, color.itemMeta)); } + } else if (item instanceof ItemBucket bucket) { + creativeItems.add(new ItemStack(item)); + for (NamespaceID stateId : ItemBucket.getRegisteredStateIds()) { + if (ItemBucket.STATE_EMPTY.equals(stateId)) continue; + ItemStack itemStack = new ItemStack(item, 1); + ItemBucket.setState(itemStack, stateId); + ItemBucket.setCharges(itemStack, bucket.maxCharges); + + creativeItems.add(itemStack); + } } else { creativeItems.add(new ItemStack(item)); } 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 cd181212d..2b7fabb42 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 @@ -4,9 +4,7 @@ import net.minecraft.core.achievement.Achievements; import net.minecraft.core.block.Blocks; import net.minecraft.core.data.registry.Registries; import net.minecraft.core.entity.player.Player; -import net.minecraft.core.item.Item; -import net.minecraft.core.item.Items; -import net.minecraft.core.item.ItemStack; +import net.minecraft.core.item.*; import net.minecraft.core.item.tool.ItemToolHoe; import net.minecraft.core.item.tool.ItemToolPickaxe; import net.minecraft.core.item.tool.ItemToolSword; @@ -41,7 +39,7 @@ public class SlotResult extends Slot if(item.id == Blocks.FURNACE_STONE_IDLE.id()) thePlayer.addStat(Achievements.BUILD_FURNACE, 1); if(item.id == Items.FOOD_BREAD.id) thePlayer.addStat(Achievements.MAKE_BREAD, 1); if(item.id == Items.FOOD_CAKE.id) thePlayer.addStat(Achievements.BAKE_CAKE, 1); - if(item.id == Items.BUCKET_ICECREAM.id) thePlayer.addStat(Achievements.CRAFT_ICECREAM, 1); + if(item instanceof ItemBucket && ItemBucket.getState(itemStack) == ItemBucket.STATE_ICECREAM) 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/world/LevelListener.java b/game/core/src/main/java/net/minecraft/core/world/LevelListener.java index 80eeaa56b..9312da9e5 100644 --- a/game/core/src/main/java/net/minecraft/core/world/LevelListener.java +++ b/game/core/src/main/java/net/minecraft/core/world/LevelListener.java @@ -48,6 +48,20 @@ public interface LevelListener * data: unused */ int EVENT_PISTON_RETRACT = 1007; + /** + * data: is a packed byte containing a {@link net.minecraft.core.util.helper.Side} and a conduit signal strength (0-10)
+ * Bits 0-3: Signal Strength (Value: 0-10)
+ * Bits 4-6: Side ID (Value: 0-5, or 7 for NONE)
+ * Bit 7: Unused (Reserved)
+ */ + int EVENT_CONDUIT_PORT_PARTICLES = 1008; + /** + * data: is a packed byte containing a {@link net.minecraft.core.util.helper.Side} and a conduit signal strength (0-10)
+ * Bits 0-3: Signal Strength (Value: 0-10)
+ * Bits 4-6: Side ID (Value: 0-5, or 7 for NONE)
+ * Bit 7: Unused (Reserved)
+ */ + int EVENT_CONDUIT_SURFACE_PARTICLES = 1009; /** * Redraw block in singleplayer and send block change packet in multiplayer.
diff --git a/game/core/src/main/java/net/minecraft/core/world/World.java b/game/core/src/main/java/net/minecraft/core/world/World.java index abd382df0..97881ef47 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 @@ -12,6 +12,7 @@ import net.minecraft.core.block.material.Material; import net.minecraft.core.block.material.Materials; import net.minecraft.core.block.support.ISupport; import net.minecraft.core.block.tag.BlockTags; +import net.minecraft.core.current.conduit.ConduitHandler; import net.minecraft.core.current.wire.WireHandler; import net.minecraft.core.data.gamerule.GameRule; import net.minecraft.core.data.gamerule.GameRules; @@ -147,6 +148,7 @@ public abstract class World implements MutableWorldSource { private final @NotNull WeatherManager weatherManager; private final @NotNull CommandManager commandManager = new CommandManager(isServer); private final @NotNull WireHandler wireHandler = new WireHandler(this); + private final @NotNull ConduitHandler conduitHandler = new ConduitHandler(this); private final @NotNull LightingEngine lightingEngine = new LightingEngineLegacy(this); private World( @@ -304,6 +306,10 @@ public abstract class World implements MutableWorldSource { return this.wireHandler; } + public @NotNull ConduitHandler getConduitHandler() { + return this.conduitHandler; + } + protected abstract @NotNull ChunkProvider createChunkProvider(@NotNull LevelStorage levelStorage); /* { final ChunkLoader chunkLoader = this.levelStorage.getChunkLoader(this.dimension); return accessor.createChunkProvider(this, chunkLoader); @@ -2026,6 +2032,7 @@ public abstract class World implements MutableWorldSource { if (this.getGameRuleValue(GameRules.DO_DAY_CYCLE)) { this.levelData.setWorldTime(this.levelData.getWorldTime() + 1L); } + this.levelData.setTotalWorldTime(this.levelData.getTotalWorldTime() + 1L); this.runtime++; @@ -2593,6 +2600,10 @@ public abstract class World implements MutableWorldSource { return this.levelData.getWorldTime(); } + public long getTotalWorldTime() { + return this.levelData.getTotalWorldTime(); + } + public Difficulty getDifficulty() { return this.levelData.getDifficulty(); } diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkDecoratorSkyblock.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkDecoratorSkyblock.java index 8ebb9d387..22f1bdc6b 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkDecoratorSkyblock.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkDecoratorSkyblock.java @@ -3,6 +3,7 @@ package net.minecraft.core.world.generate.chunk.skyblock; import net.minecraft.core.block.Blocks; import net.minecraft.core.block.entity.TileEntity; import net.minecraft.core.block.entity.TileEntityChest; +import net.minecraft.core.item.ItemBucket; import net.minecraft.core.item.ItemStack; import net.minecraft.core.item.Items; import net.minecraft.core.world.chunk.Chunk; @@ -24,7 +25,7 @@ public class ChunkDecoratorSkyblock chunk.setBlockIDWithMetadata(4 & (Chunk.CHUNK_SIZE_X - 1), 67, -3 & (Chunk.CHUNK_SIZE_Z - 1), Blocks.CHEST_PLANKS_OAK.id(), 3); TileEntity tileEntity = chunk.getTileEntity(4 & (Chunk.CHUNK_SIZE_X - 1), 67, -3 & (Chunk.CHUNK_SIZE_Z - 1)); if (tileEntity instanceof TileEntityChest chest) { - chest.setItem(0, new ItemStack(Items.BUCKET_LAVA, 1)); + chest.setItem(0, ItemBucket.createItemStack(Items.BUCKET_IRON, ItemBucket.STATE_LAVA, 1)); chest.setItem(1, new ItemStack(Blocks.ICE, 1)); } } diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureDungeon.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureDungeon.java index 3e7b5eeac..326a5a857 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureDungeon.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureDungeon.java @@ -35,7 +35,7 @@ public class WorldFeatureDungeon extends WorldFeature { this.chestLoot.addEntry(new WeightedRandomLootObject(Items.WHEAT.getDefaultStack(), 1, 4), 100); this.chestLoot.addEntry(new WeightedRandomLootObject(Items.GUNPOWDER.getDefaultStack(), 1, 4), 100); this.chestLoot.addEntry(new WeightedRandomLootObject(Items.STRING.getDefaultStack(), 1, 4), 100); - this.chestLoot.addEntry(new WeightedRandomLootObject(Items.BUCKET.getDefaultStack()), 100); + this.chestLoot.addEntry(new WeightedRandomLootObject(Items.BUCKET_IRON.getDefaultStack()), 100); this.chestLoot.addEntry(new WeightedRandomLootObject(Items.FOOD_APPLE_GOLD.getDefaultStack()), 1); this.chestLoot.addEntry(new WeightedRandomLootObject(Items.DUST_REDSTONE.getDefaultStack(), 1, 4), 50); for (int i = 0; i < 9; i++) { diff --git a/game/core/src/main/java/net/minecraft/core/world/pos/TilePosc.java b/game/core/src/main/java/net/minecraft/core/world/pos/TilePosc.java index d700240a4..8824a90f0 100644 --- a/game/core/src/main/java/net/minecraft/core/world/pos/TilePosc.java +++ b/game/core/src/main/java/net/minecraft/core/world/pos/TilePosc.java @@ -93,4 +93,5 @@ public interface TilePosc { return this.x() == tilePos.x() && this.y() == tilePos.y() && this.z() == tilePos.z(); } + } diff --git a/game/core/src/main/java/net/minecraft/core/world/save/LevelData.java b/game/core/src/main/java/net/minecraft/core/world/save/LevelData.java index 76247fd7c..cbc14fe5c 100644 --- a/game/core/src/main/java/net/minecraft/core/world/save/LevelData.java +++ b/game/core/src/main/java/net/minecraft/core/world/save/LevelData.java @@ -53,6 +53,11 @@ public class LevelData { tag.getInteger("SpawnZ") ); data.worldTime = tag.getLong("Time"); + if (tag.containsKey("TotalTime")) { + data.totalWorldTime = tag.getLong("TotalTime"); + } else { + data.totalWorldTime = data.worldTime; + } data.lastTimePlayed = tag.getLong("LastPlayed"); data.sizeOnDisk = tag.getLong("SizeOnDisk"); data.saveVersion = tag.getInteger("version"); @@ -77,6 +82,7 @@ public class LevelData { out.putInt("SpawnY", levelData.spawnPos.y); out.putInt("SpawnZ", levelData.spawnPos.z); out.putLong("Time", levelData.worldTime); + out.putLong("TotalTime", levelData.totalWorldTime); out.putLong("SizeOnDisk", levelData.sizeOnDisk); out.putLong("LastPlayed", System.currentTimeMillis()); out.putString("LevelName", levelData.levelName); @@ -132,6 +138,7 @@ public class LevelData { private final @NotNull SpawnerConfig spawnerConfig; private long worldTime; + private long totalWorldTime; private long lastTimePlayed; private long sizeOnDisk; private @Nullable UUID lastPlayerUUID; @@ -183,6 +190,7 @@ public class LevelData { this.spawnPos.set(levelData.spawnPos); this.worldTime = levelData.worldTime; + this.totalWorldTime = levelData.totalWorldTime; this.lastTimePlayed = levelData.lastTimePlayed; this.sizeOnDisk = levelData.sizeOnDisk; this.playerTag = levelData.playerTag; @@ -214,6 +222,14 @@ public class LevelData { this.worldTime = time; } + public long getTotalWorldTime() { + return this.totalWorldTime; + } + + public void setTotalWorldTime(final long time) { + this.totalWorldTime = time; + } + public long getSizeOnDisk() { return this.sizeOnDisk; } diff --git a/game/core/src/main/java/net/minecraft/core/world/save/conversion/ItemConverters.java b/game/core/src/main/java/net/minecraft/core/world/save/conversion/ItemConverters.java new file mode 100644 index 000000000..b419ad579 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/world/save/conversion/ItemConverters.java @@ -0,0 +1,44 @@ +package net.minecraft.core.world.save.conversion; + +import com.mojang.nbt.tags.CompoundTag; +import net.minecraft.core.item.ItemBucket; +import net.minecraft.core.util.collection.NamespaceID; + +public class ItemConverters { + /** + * Migrates legacy bucket IDs to the new NBT-based Bucket system. + */ + public static void legacyBucketConverter(CompoundTag tag) { + short id = tag.getShort("id"); + NamespaceID newState = null; + + short ironBucketId = 16562; + + if (id == 16453) { + tag.putShort("id", ironBucketId); + } + else if (id == 16454) { // Legacy Water + tag.putShort("id", ironBucketId); + newState = ItemBucket.STATE_WATER; + } + else if (id == 16455) { // Legacy Lava + tag.putShort("id", ironBucketId); + newState = ItemBucket.STATE_LAVA; + } + else if (id == 16463) { // Legacy Milk + tag.putShort("id", ironBucketId); + newState = ItemBucket.STATE_MILK; + } + else if (id == 16516) { // Legacy Ice Cream + tag.putShort("id", ironBucketId); + newState = ItemBucket.STATE_ICECREAM; + } + + if (newState != null) { + CompoundTag dataTag = tag.containsKey("Data") ? tag.getCompound("Data") : new CompoundTag(); + dataTag.putString("State", newState.toString()); + dataTag.putInt("Charges", 1); + tag.putCompound("Data", dataTag); + } + } +} \ No newline at end of file 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 12ac246e3..a6f2a4100 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 @@ -113,8 +113,7 @@ public class WeatherManager { } else if (this.nextWeather != null && this.weatherIntensity >= 0.0f) { this.weatherIntensity -= 0.002f; if (!this.world.isClientSide) { - if (this.currentWeather instanceof IPrecipitation) { - final @NotNull IPrecipitation precipitation = (IPrecipitation) this.currentWeather; + if (this.currentWeather instanceof @NotNull IPrecipitation precipitation) { if (this.world.dayCanHaveRainbow && this.world.rainbowTicks <= 0 && this.weatherIntensity < 0.5f && diff --git a/game/core/src/main/resources/assets/minecraft/lang/en_US/item.lang b/game/core/src/main/resources/assets/minecraft/lang/en_US/item.lang index 739522bf8..1783d0edc 100644 --- a/game/core/src/main/resources/assets/minecraft/lang/en_US/item.lang +++ b/game/core/src/main/resources/assets/minecraft/lang/en_US/item.lang @@ -208,12 +208,6 @@ item.sign.painted.white.desc=Mark your land, or write a message. item.door.oak.name=Wooden Door item.door.oak.desc=Every house needs one. -item.bucket.name=Bucket -item.bucket.desc=Used to hold various liquids. -item.bucket.water.name=Water Bucket -item.bucket.water.desc=A bucket full of the deep blue. -item.bucket.lava.name=Lava Bucket -item.bucket.lava.desc=A bucket full of molten rock. Hot! item.minecart.name=Minecart item.minecart.desc=An iron vehicle for exploring the deep underground. item.saddle.name=Saddle @@ -228,8 +222,6 @@ item.boat.name=Boat item.boat.desc=Sail the seven seas! item.leather.name=Leather item.leather.desc=A flat cow. Can be used to make armor. -item.bucket.milk.name=Bucket of Milk -item.bucket.milk.desc=Good for your bones. item.brick.clay.name=Clay Brick item.brick.clay.desc=Put 4 of these together to create a solid foundation. item.clay.name=Clay @@ -369,8 +361,6 @@ item.ammo.pebble.name=Pebble item.ammo.pebble.desc=A chunk of rock found buried in the soil. item.food.cherry.name=Cherries item.food.cherry.desc=Red berries that come in pairs. -item.bucket.icecream.name=Bucket of Ice Cream -item.bucket.icecream.desc=A frosty treat sprinkled with chocolate chips and a cherry! item.ammo.fireball.name=Fire Charge item.ammo.fireball.desc=Ammo for a hand cannon. Scatters fire over a wide area. item.ammo.arrow.purple.name=Purple Arrow @@ -378,6 +368,28 @@ item.ammo.arrow.purple.desc=How did you get this?! item.label.name=Label item.label.desc=Allows you to name items and creatures. Can be dyed. +item.bucket.iron.name=Iron Bucket +item.bucket.iron.desc=Used to hold various liquids. +item.bucket.iron.water.name=Iron Water Bucket +item.bucket.iron.water.desc=A bucket full of the deep blue. +item.bucket.iron.lava.name=Iron Lava Bucket +item.bucket.iron.lava.desc=A bucket full of molten rock. Hot! +item.bucket.iron.milk.name=Iron Bucket of Milk +item.bucket.iron.milk.desc=Good for your bones. +item.bucket.iron.icecream.name=Iron Bucket of Ice Cream +item.bucket.iron.icecream.desc=A frosty treat sprinkled with chocolate chips and a cherry! + +item.bucket.steel.name=Steel Bucket +item.bucket.steel.desc=Used to hold various liquid. +item.bucket.steel.water.name=Steel Water Bucket +item.bucket.steel.water.desc=A large bucket full of the deep blue. +item.bucket.steel.lava.name=Steel Lava Bucket +item.bucket.steel.lava.desc=A large bucket full of molten rock. Hot! +item.bucket.steel.milk.name=Steel Bucket of Milk +item.bucket.steel.milk.desc=Excessively good for your bones! +item.bucket.steel.icecream.name=Steel Bucket of Ice Cream +item.bucket.steel.icecream.desc=Maybe a little too much ice cream... + item.candle.soulwax.name=Soul Wax Candle item.candle.soulwax.desc=A waxy brown candle that glows with an unnatural light. diff --git a/game/core/src/main/resources/assets/minecraft/lang/en_US/tile.lang b/game/core/src/main/resources/assets/minecraft/lang/en_US/tile.lang index 711231fb9..887050e81 100644 --- a/game/core/src/main/resources/assets/minecraft/lang/en_US/tile.lang +++ b/game/core/src/main/resources/assets/minecraft/lang/en_US/tile.lang @@ -1442,8 +1442,8 @@ tile.block.rubyglass.desc=A translucent glass-like crystal brimming with energy. tile.rubyglass.sprout.name=Rubyglass Bud tile.rubyglass.sprout.desc=A small bud of rubyglass, branching out in many directions. -tile.rubyglass.circuit.name=Rubyglass Circuit -tile.rubyglass.circuit.desc=Netherrack etched with lines of rubyglass. It resonates with latent power. +tile.rubyglass.conduit.name=Rubyglass Conduit +tile.rubyglass.conduit.desc=Netherrack etched with lines of rubyglass. It resonates with latent power. tile.vent.name=Chimney tile.vent.desc=A rocky column that emits a stream of smoke. diff --git a/util/datagen/src/main/java/net/minecraft/datagen/WorkbenchGenerator.java b/util/datagen/src/main/java/net/minecraft/datagen/WorkbenchGenerator.java index d663aa894..b1a0c2994 100644 --- a/util/datagen/src/main/java/net/minecraft/datagen/WorkbenchGenerator.java +++ b/util/datagen/src/main/java/net/minecraft/datagen/WorkbenchGenerator.java @@ -1,12 +1,9 @@ package net.minecraft.datagen; import net.minecraft.core.block.Block; -import net.minecraft.core.data.registry.recipe.entry.RecipeEntryCraftingWithTool; -import net.minecraft.core.data.registry.recipe.entry.RecipeEntryDyeing; -import net.minecraft.core.data.registry.recipe.entry.RecipeEntryRepairable; -import net.minecraft.core.data.registry.recipe.entry.RecipeEntryScrap; -import net.minecraft.core.data.registry.recipe.entry.RecipeEntryUndyeing; +import net.minecraft.core.data.registry.recipe.entry.*; import net.minecraft.core.item.Item; +import net.minecraft.core.item.ItemBucket; import net.minecraft.datagen.recipeBuilders.RecipeBuilder; import net.minecraft.datagen.recipeBuilders.RecipeBuilderShaped; import net.minecraft.core.block.Blocks; @@ -150,12 +147,12 @@ class WorkbenchGenerator { RecipeBuilder.Shaped(CORE_NAMESPACE) .setShape( - "#S#", - "#N#", - "#R#") + "###", + "CSR", + "###") .addInput('#', Blocks.COBBLE_NETHERRACK) .addInput('S', Blocks.SOULSAND) - .addInput('N', Items.RUBYGLASS_CRYSTAL) + .addInput('C', Blocks.RUBYGLASS_CONDUIT) .addInput('R', Items.DUST_REDSTONE) .create("activator", Blocks.ACTIVATOR_COBBLE_NETHERRACK.getDefaultStack()); @@ -373,12 +370,12 @@ class WorkbenchGenerator { RecipeBuilder.Shapeless(CORE_NAMESPACE) .addInput(Blocks.SPONGE_DRY) - .addInput(Items.BUCKET_WATER) + .addInput("minecraft:water_buckets") .create("sponge_to_wet_sponge", Blocks.SPONGE_WET.getDefaultStack()); RecipeBuilder.Shapeless(CORE_NAMESPACE) .addInput(Blocks.PUMICE_DRY) - .addInput(Items.BUCKET_LAVA) + .addInput("minecraft:lava_buckets") .create("pumice_to_wet_pumice", Blocks.PUMICE_WET.getDefaultStack()); RecipeBuilder.Shapeless(CORE_NAMESPACE) @@ -529,7 +526,15 @@ class WorkbenchGenerator { "# #", " # ") .addInput('#', Items.INGOT_IRON) - .create("bucket", Items.BUCKET.getDefaultStack()); + .create("iron_bucket", Items.BUCKET_IRON.getDefaultStack()); + + RecipeBuilder.Shaped(CORE_NAMESPACE) + .setShape( + "# #", + "*#*") + .addInput('#', Items.INGOT_STEEL) + .addInput('*', Items.INGOT_STEEL_CRUDE) + .create("steel_bucket", Items.BUCKET_STEEL.getDefaultStack()); RecipeBuilder.Shaped(CORE_NAMESPACE) .setShape( @@ -1060,33 +1065,32 @@ class WorkbenchGenerator { .addInput(new ItemStack(Items.DYE, 1, DyeColor.BROWN.itemMeta)) .create("cookie", new ItemStack(Items.FOOD_COOKIE, 16)); - RecipeBuilderShaped cake = RecipeBuilder.Shaped(CORE_NAMESPACE) + RecipeBuilderShaped cakeBase = RecipeBuilder.Shaped(CORE_NAMESPACE) .setShape( "AAA", "BEB", "CCC") - .setConsumeContainer(false); - - cake.addInput('A', Items.BUCKET_MILK) + .setConsumeContainer(false) + .addInput('A', "minecraft:milk_buckets") .addInput('B', Items.DUST_SUGAR) - .addInput('E', Items.EGG_CHICKEN) - .addInput('C', Items.DOUGH) - .create("cake", Items.FOOD_CAKE.getDefaultStack()); + .addInput('C', Items.DOUGH); - cake.addInput('A', Items.BUCKET_MILK) - .addInput('B', Items.DUST_SUGAR) - .addInput('E', Blocks.PUMPKIN) - .addInput('C', Items.DOUGH) - .create("pumpkin_pie", Items.FOOD_PUMPKIN_PIE.getDefaultStack()); + cakeBase.addInput('E', Items.EGG_CHICKEN).create("cake", Items.FOOD_CAKE.getDefaultStack()); + cakeBase.addInput('E', Blocks.PUMPKIN).create("pumpkin_pie", Items.FOOD_PUMPKIN_PIE.getDefaultStack()); - RecipeBuilder.Shaped(CORE_NAMESPACE) - .setShape( - "XXX", - "X#X", - "XXX") - .addInput('X', Blocks.BLOCK_GOLD) - .addInput('#', Items.FOOD_APPLE) - .create("golden_apple", Items.FOOD_APPLE_GOLD.getDefaultStack()); + generateIceCreamProgression(Items.BUCKET_IRON, "iron"); + generateIceCreamProgression(Items.BUCKET_STEEL, "steel"); + + RecipeBuilder.Shapeless(CORE_NAMESPACE).addInput(Items.SUGARCANE).create("sugar_cane_to_sugar", new ItemStack(Items.DUST_SUGAR, 3)); + } + + /** + * Dynamically generates the Ice Cream crafting progression for any given bucket type. + * @param bucketItem The Item instance of the bucket (Items.BUCKET_STEEL, Items.BUCKET_IRON, etc.) + * @param materialName The string name for the recipe ID ("steel", "iron", etc.) + */ + public static void generateIceCreamProgression(Item bucketItem, String materialName) { + int max = ((ItemBucket) bucketItem).maxCharges; RecipeBuilder.Shaped(CORE_NAMESPACE) .setShape( @@ -1096,11 +1100,23 @@ class WorkbenchGenerator { .addInput('Y', Items.FOOD_CHERRY) .addInput('O', new ItemStack(Items.DYE, 1, DyeColor.BROWN.itemMeta)) .addInput('#', Items.AMMO_SNOWBALL) - .addInput('X', Items.BUCKET_MILK) + .addInput('X', ItemBucket.createRecipeInput(bucketItem, ItemBucket.STATE_MILK)) .setConsumeContainer(true) - .create("ice_cream_bucket", Items.BUCKET_ICECREAM.getDefaultStack()); + .create("icecream_bucket_" + materialName + "_from_milk", ItemBucket.createItemStack(bucketItem, ItemBucket.STATE_ICECREAM, 1)); - RecipeBuilder.Shapeless(CORE_NAMESPACE).addInput(Items.SUGARCANE).create("sugar_cane_to_sugar", new ItemStack(Items.DUST_SUGAR, 3)); + for (int currentCharge = 1; currentCharge < max; currentCharge++) { + RecipeBuilder.Shaped(CORE_NAMESPACE) + .setShape( + " Y ", + "#O#", + " X ") + .addInput('Y', Items.FOOD_CHERRY) + .addInput('O', new ItemStack(Items.DYE, 1, DyeColor.BROWN.itemMeta)) + .addInput('#', Items.AMMO_SNOWBALL) + .addInput('X', ItemBucket.createItemStack(bucketItem, ItemBucket.STATE_ICECREAM, currentCharge)) + .setConsumeContainer(true) + .create("icecream_bucket_" + materialName + "_upgrade_" + currentCharge + "_to_" + (currentCharge + 1), ItemBucket.createItemStack(bucketItem, ItemBucket.STATE_ICECREAM, currentCharge + 1)); + } } private static void generateDyes() { @@ -1329,31 +1345,32 @@ class WorkbenchGenerator { RecipeBuilder.Shaped(CORE_NAMESPACE) .setShape( "#Q#", - "#S#", - "#R#" + "#C#", + "#Q#" ) .addInput('#', Blocks.COBBLE_NETHERRACK) .addInput('Q', Items.QUARTZ) - .addInput('R', Items.RUBYGLASS_CRYSTAL) - .addInput('S', Blocks.SOULSAND) + .addInput('C', Blocks.RUBYGLASS_CONDUIT) .create("matcher", new ItemStack(Blocks.MATCHER, 1)); RecipeBuilder.Shaped(CORE_NAMESPACE) .setShape( "XOX", - "OOO", + "ORO", "XOX") + .addInput('R', Items.DUST_REDSTONE) .addInput('O', Items.RUBYGLASS_CRYSTAL) .addInput('X', Blocks.COBBLE_NETHERRACK) - .create("rubyglass_circuit", new ItemStack(Blocks.RUBYGLASS_CIRCUIT, 1)); + .create("rubyglass_conduit", new ItemStack(Blocks.RUBYGLASS_CONDUIT, 1)); RecipeBuilder.Shaped(CORE_NAMESPACE) .setShape( "###", - "#RB", + "CQB", "###") - .addInput('#', Blocks.COBBLE_NETHERRACK) - .addInput('R', Items.RUBYGLASS_CRYSTAL) + .addInput('#', Blocks.COBBLE_STONE_MOSSY) + .addInput('C', Blocks.RUBYGLASS_CONDUIT) + .addInput('Q', Items.QUARTZ) .addInput('B', Items.BONE) .create("motion_sensor", Blocks.MOTION_SENSOR_IDLE.getDefaultStack()); } diff --git a/util/datagen/src/main/java/net/minecraft/datagen/recipeBuilders/RecipeBuilderShaped.java b/util/datagen/src/main/java/net/minecraft/datagen/recipeBuilders/RecipeBuilderShaped.java index 9765b4c1b..1bafdf30a 100644 --- a/util/datagen/src/main/java/net/minecraft/datagen/recipeBuilders/RecipeBuilderShaped.java +++ b/util/datagen/src/main/java/net/minecraft/datagen/recipeBuilders/RecipeBuilderShaped.java @@ -20,17 +20,18 @@ public class RecipeBuilderShaped extends RecipeBuilderBase{ protected int height; protected boolean consumeContainer = DEFAULT_CONSUME_CONTAINER; protected boolean allowMirrored = DEFAULT_ALLOW_MIRROR; - protected final HashMap symbolShapedMap = new HashMap<>(); + protected HashMap symbolShapedMap = new HashMap<>(); + /** - * Used for creating new shaped workbench recipes. - * @param modID Namespace to create recipe under + * Used for creating new-shaped workbench recipes. + * @param modID Namespace to create a recipe under */ public RecipeBuilderShaped(String modID){ super(modID); } /** - * Used for creating new shaped workbench recipes. - * @param modID Namespace to create recipe under + * Used for creating new-shaped workbench recipes. + * @param modID Namespace to create a recipe under * @param shape Recipe shape in symbol representation */ public RecipeBuilderShaped(String modID, String... shape) { @@ -101,22 +102,21 @@ public class RecipeBuilderShaped extends RecipeBuilderBase{ /** * Specifies whether the recipe should consume container items. *
{@code
-     *     RecipeBuilderShaped("minecraft")
-     *       .setShape(
-     *          "BBB",
-     *          "SES",
-     *          "WWW")
-     *       .addInput('B', Item.bucketMilk)
-     *       .addInput('S', Item.dustSugar)
-     *       .addInput('E', Item.eggChicken)
-     *       .addInput('W', Item.wheat)
-     *       .setConsumeContainer(false) // Recipe will return empty buckets when crafted
-     *       .create("cake", Item.cake.getDefaultStack());
+     * RecipeBuilder.Shaped("minecraft")
+     *      .setShape(
+     *          "AAA",
+     *          "BEB",
+     *          "CCC")
+     *      .addInput('A', "minecraft:milk_buckets")
+     *      .addInput('B', Items.DUST_SUGAR)
+     *      .addInput('E', Items.EGG_CHICKEN)
+     *      .addInput('C', Items.DOUGH)
+     *      .setConsumeContainer(false) // Recipe will leave empty or decremented buckets behind
+     *      .create("cake", Items.FOOD_CAKE.getDefaultStack());
      * }
* @param consumeContainer Should consume ContainerItem * @return Copy of {@link RecipeBuilderShaped} */ - @SuppressWarnings({"unused"}) public RecipeBuilderShaped setConsumeContainer(boolean consumeContainer){ RecipeBuilderShaped builder = this.clone(this); builder.consumeContainer = consumeContainer; @@ -129,6 +129,13 @@ public class RecipeBuilderShaped extends RecipeBuilderBase{ return builder; } + @Override + public RecipeBuilderShaped clone() { + RecipeBuilderShaped cloned = (RecipeBuilderShaped) super.clone(); + cloned.symbolShapedMap = new HashMap<>(this.symbolShapedMap); + return cloned; + } + /** * Assigns an item to an item symbol defined in the shape (see {@link #setShape(String...)}) * @param templateSymbol Item symbol character @@ -184,8 +191,8 @@ public class RecipeBuilderShaped extends RecipeBuilderBase{ @SuppressWarnings({"unused"}) public RecipeBuilderShaped addInput(char templateSymbol, RecipeSymbol symbol){ if (templateSymbol == ' ') throw new IllegalArgumentException("Cannot assign item to protected symbol ' ' pick a different symbol for your recipe input"); - RecipeBuilderShaped builder = this.clone(this); - symbolShapedMap.put(templateSymbol, symbol); + RecipeBuilderShaped builder = this.clone(); + builder.symbolShapedMap.put(templateSymbol, symbol); return builder; } @@ -199,15 +206,15 @@ public class RecipeBuilderShaped extends RecipeBuilderBase{ if (shape[y].length() > x) { cha = shape[y].charAt(x); } - RecipeSymbol tempplate = symbolShapedMap.get(cha); - if (tempplate == null){ + RecipeSymbol template = symbolShapedMap.get(cha); + if (template == null){ recipe[x + y * width] = null; } else { - if(tempplate.getItemGroup() == null){ - RecipeSymbol s = new RecipeSymbol(cha == null ? ' ' : cha, tempplate.getStack()); + if(template.getItemGroup() == null){ + RecipeSymbol s = new RecipeSymbol(cha == null ? ' ' : cha, template.getStack()); recipe[x + y * width] = s; } else { - recipe[x + y * width] = new RecipeSymbol(cha == null ? ' ' : cha, tempplate.getStack(), tempplate.getItemGroup()); + recipe[x + y * width] = new RecipeSymbol(cha == null ? ' ' : cha, template.getStack(), template.getItemGroup()); } } diff --git a/util/datagen/src/main/java/net/minecraft/datagen/recipeBuilders/RecipeBuilderShapeless.java b/util/datagen/src/main/java/net/minecraft/datagen/recipeBuilders/RecipeBuilderShapeless.java index c9c644c2f..f73b51f76 100644 --- a/util/datagen/src/main/java/net/minecraft/datagen/recipeBuilders/RecipeBuilderShapeless.java +++ b/util/datagen/src/main/java/net/minecraft/datagen/recipeBuilders/RecipeBuilderShapeless.java @@ -12,15 +12,24 @@ import java.util.ArrayList; import java.util.List; public class RecipeBuilderShapeless extends RecipeBuilderBase{ - private final List symbolShapelessList = new ArrayList<>(); + + private List symbolShapelessList = new ArrayList<>(); + /** * Used for creating new shapeless workbench recipes. - * @param modID Namespace to create recipe under + * @param modID Namespace to create a recipe under */ public RecipeBuilderShapeless(String modID) { super(modID); } + @Override + public RecipeBuilderShapeless clone() { + RecipeBuilderShapeless cloned = (RecipeBuilderShapeless) super.clone(); + cloned.symbolShapelessList = new ArrayList<>(this.symbolShapelessList); + return cloned; + } + /** * @param stack Item to add to recipe's item list * @return Copy of {@link RecipeBuilderShapeless} @@ -66,10 +75,11 @@ public class RecipeBuilderShapeless extends RecipeBuilderBase{ */ @SuppressWarnings({"unused"}) public RecipeBuilderShapeless addInput(RecipeSymbol symbol){ - RecipeBuilderShapeless builder = this.clone(this); - symbolShapelessList.add(symbol); + RecipeBuilderShapeless builder = this.clone(); + builder.symbolShapelessList.add(symbol); return builder; } + @Override @SuppressWarnings({"unused", "unchecked"}) public void create(String recipeID, ItemStack outputStack) {