diff --git a/build.gradle b/build.gradle index 15283b7..25a9c51 100644 --- a/build.gradle +++ b/build.gradle @@ -10,6 +10,10 @@ base { archivesName = project.archives_base_name } +loom { + accessWidenerPath = file("src/main/resources/vanilla-addition.accesswidener") +} + repositories { // Add repositories to retrieve artifacts from in here. // You should only use this when depending on other mods because diff --git a/src/main/generated/data/minecraft/tags/block/beacon_base_blocks.json b/src/main/generated/data/minecraft/tags/block/beacon_base_blocks.json index 2dd6798..6f62b5c 100644 --- a/src/main/generated/data/minecraft/tags/block/beacon_base_blocks.json +++ b/src/main/generated/data/minecraft/tags/block/beacon_base_blocks.json @@ -1,5 +1,6 @@ { "values": [ - "vanilla-addition:steel_block" + "vanilla-addition:steel_block", + "vanilla-addition:light_beacon_base" ] } \ No newline at end of file diff --git a/src/main/generated/data/minecraft/tags/block/mineable/pickaxe.json b/src/main/generated/data/minecraft/tags/block/mineable/pickaxe.json index 6746ff4..082e925 100644 --- a/src/main/generated/data/minecraft/tags/block/mineable/pickaxe.json +++ b/src/main/generated/data/minecraft/tags/block/mineable/pickaxe.json @@ -35,6 +35,8 @@ "minecraft:magenta_stained_glass_pane", "minecraft:pink_stained_glass_pane", "vanilla-addition:steel_block", + "vanilla-addition:light_beacon_base", + "vanilla-addition:portable_beacon_base", "vanilla-addition:stone_wall", "vanilla-addition:smooth_stone_wall", "vanilla-addition:smooth_stone_stairs", diff --git a/src/main/generated/data/vanilla-addition/loot_table/blocks/light_beacon_base.json b/src/main/generated/data/vanilla-addition/loot_table/blocks/light_beacon_base.json new file mode 100644 index 0000000..fa3eb19 --- /dev/null +++ b/src/main/generated/data/vanilla-addition/loot_table/blocks/light_beacon_base.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "vanilla-addition:light_beacon_base" + } + ], + "rolls": 1.0 + } + ] +} \ No newline at end of file diff --git a/src/main/generated/data/vanilla-addition/loot_table/blocks/portable_beacon_base.json b/src/main/generated/data/vanilla-addition/loot_table/blocks/portable_beacon_base.json new file mode 100644 index 0000000..95516ca --- /dev/null +++ b/src/main/generated/data/vanilla-addition/loot_table/blocks/portable_beacon_base.json @@ -0,0 +1,32 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "predicates": { + "minecraft:enchantments": [ + { + "enchantments": "minecraft:silk_touch", + "levels": { + "min": 1 + } + } + ] + } + } + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "minecraft:beacon" + } + ], + "rolls": 1.0 + } + ] +} \ No newline at end of file diff --git a/src/main/java/com/yipkei/vanilladdition/VanillaAddition.java b/src/main/java/com/yipkei/vanilladdition/VanillaAddition.java index 16c3774..a826015 100644 --- a/src/main/java/com/yipkei/vanilladdition/VanillaAddition.java +++ b/src/main/java/com/yipkei/vanilladdition/VanillaAddition.java @@ -1,6 +1,7 @@ package com.yipkei.vanilladdition; import com.yipkei.vanilladdition.custom.ModDispenserBehavior; +import com.yipkei.vanilladdition.init.ModBlockEntityType; import com.yipkei.vanilladdition.init.ModBlocks; import com.yipkei.vanilladdition.init.ModItemGroups; import com.yipkei.vanilladdition.init.ModItems; @@ -33,6 +34,7 @@ public void onInitialize() { ModBlocks.registerModBlocks(); ModItemGroups.registerModItemGroup(); ModVillagers.registerModVillagers(); + ModBlockEntityType.registerBlockEntities(); ModLootTableModifiers.modifierLootTables(); VanillaTradeModifiers.registerVanillaVillageTrades(); diff --git a/src/main/java/com/yipkei/vanilladdition/block/EnderTntBlock.java b/src/main/java/com/yipkei/vanilladdition/block/EnderTntBlock.java new file mode 100644 index 0000000..51e6de0 --- /dev/null +++ b/src/main/java/com/yipkei/vanilladdition/block/EnderTntBlock.java @@ -0,0 +1,141 @@ +package com.yipkei.vanilladdition.block; + +import com.mojang.serialization.MapCodec; +import com.yipkei.vanilladdition.entity.EnderTntEntity; +import net.minecraft.block.*; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.projectile.ProjectileEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemPlacementContext; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.registry.tag.ItemTags; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.stat.Stats; +import net.minecraft.state.StateManager; +import net.minecraft.state.property.BooleanProperty; +import net.minecraft.state.property.Properties; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; +import net.minecraft.util.Hand; +import net.minecraft.util.ItemActionResult; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.World; +import net.minecraft.world.event.GameEvent; +import net.minecraft.world.explosion.Explosion; +import org.jetbrains.annotations.Nullable; + +public class EnderTntBlock extends FacingBlock { + public static final MapCodec CODEC = EnderTntBlock.createCodec(EnderTntBlock::new); + public static final BooleanProperty UNSTABLE = Properties.UNSTABLE; + + @Override + protected MapCodec getCodec() { return CODEC; } + + public EnderTntBlock(Settings settings) { + super(settings); + this.setDefaultState(this.stateManager.getDefaultState().with(FACING, Direction.SOUTH).with(UNSTABLE,false)); + } + + @Override + protected void appendProperties(StateManager.Builder builder){ + builder.add(FACING, UNSTABLE); + } + + @Override + protected BlockState rotate(BlockState state, BlockRotation rotation) { + return state.with(FACING, rotation.rotate(state.get(FACING))); + } + + @Override + protected BlockState mirror(BlockState state, BlockMirror mirror) { + return state.rotate(mirror.getRotation(state.get(FACING))); + } + + @Override + public BlockState getPlacementState(ItemPlacementContext ctx) { + return this.getDefaultState().with(FACING, ctx.getPlayerLookDirection().getOpposite().getOpposite()); + } + + @Override + protected void onBlockAdded(BlockState state, World world, BlockPos pos, BlockState oldState, boolean notify) { + if (oldState.isOf(state.getBlock())) { + return; + } + if (world.isReceivingRedstonePower(pos)) { + primeEnderTNT(world, pos, state.get(FACING)); + world.removeBlock(pos, false); + } + } + + + @Override + protected void neighborUpdate(BlockState state, World world, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify){ + if (world.isReceivingRedstonePower(pos)) { + primeEnderTNT(world, pos, state.get(FACING)); + world.removeBlock(pos, false); + } + } + + @Override + public BlockState onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player) { + if (!world.isClient() && !player.isCreative() && state.get(UNSTABLE)) { + primeEnderTNT(world, pos, state.get(FACING)); + } + return super.onBreak(world, pos, state, player); + } + + public static void primeEnderTNT(World world, BlockPos pos, Direction facing){ + primeEnderTNT(world, pos, facing, null); + } + + private static void primeEnderTNT(World world, BlockPos pos, Direction facing, @Nullable LivingEntity igniter){ + if (world.isClient) { + return; + } + EnderTntEntity enderTntEntity = new EnderTntEntity(world, pos.getX()+0.5, pos.getY(), pos.getZ()+0.5, igniter, facing); + world.spawnEntity(enderTntEntity); + world.playSound(null, enderTntEntity.getX(), enderTntEntity.getY(), enderTntEntity.getZ(), SoundEvents.ENTITY_TNT_PRIMED, SoundCategory.BLOCKS, 1.0f, 1.0f); + world.emitGameEvent(igniter, GameEvent.PRIME_FUSE, pos); + } + + @Override + protected ItemActionResult onUseWithItem(ItemStack stack, BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit){ + if (!stack.isIn(ItemTags.CREEPER_IGNITERS)){ + return super.onUseWithItem(stack, state, world, pos, player, hand, hit); + } + primeEnderTNT(world, pos, state.get(FACING), player); + world.setBlockState(pos, Blocks.AIR.getDefaultState(), Block.NOTIFY_ALL_AND_REDRAW); + Item item = stack.getItem(); + if (stack.isIn(ItemTags.CREEPER_IGNITERS) && !stack.isOf(Items.FIRE_CHARGE)){ + stack.damage(1, player, LivingEntity.getSlotForHand(hand)); + }else { + stack.decrementUnlessCreative(1, player); + } + player.incrementStat(Stats.USED.getOrCreateStat(item)); + return ItemActionResult.success(world.isClient); + } + + @Override + protected void onProjectileHit(World world, BlockState state, BlockHitResult hit, ProjectileEntity projectile){ + if (!world.isClient) { + BlockPos blockPos = hit.getBlockPos(); + Entity entity = projectile.getOwner(); + if (projectile.isOnFire() && projectile.canModifyAt(world, blockPos)) { + primeEnderTNT(world, blockPos, state.get(FACING), entity instanceof LivingEntity ? (LivingEntity)entity : null); + world.removeBlock(blockPos, false); + } + } + } + + @Override + public boolean shouldDropItemsOnExplosion(Explosion explosion) { + return false; + } + +} diff --git a/src/main/java/com/yipkei/vanilladdition/block/SmitherBlock.java b/src/main/java/com/yipkei/vanilladdition/block/SmitherBlock.java new file mode 100644 index 0000000..9708e10 --- /dev/null +++ b/src/main/java/com/yipkei/vanilladdition/block/SmitherBlock.java @@ -0,0 +1,112 @@ +package com.yipkei.vanilladdition.block; + +import com.mojang.serialization.MapCodec; +import com.yipkei.vanilladdition.block.entity.SmitherBlockEntity; +import net.minecraft.block.AbstractBlock; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.BlockWithEntity; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.enums.Orientation; +import net.minecraft.entity.LivingEntity; +import net.minecraft.item.ItemPlacementContext; +import net.minecraft.item.ItemStack; +import net.minecraft.recipe.RecipeEntry; +import net.minecraft.recipe.SmithingRecipe; +import net.minecraft.recipe.input.SmithingRecipeInput; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.state.property.BooleanProperty; +import net.minecraft.state.property.EnumProperty; +import net.minecraft.state.property.Properties; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +public class SmitherBlock extends BlockWithEntity { + + public static final MapCodec CODEC = SmitherBlock.createCodec(SmitherBlock::new); + public static final BooleanProperty SMITHING = Properties.CRAFTING; + public static final BooleanProperty TRIGGERED = Properties.TRIGGERED; + private static final EnumProperty ORIENTATION = Properties.ORIENTATION; + + private static final int TRIGGER_DELAY = 4; + + public SmitherBlock(AbstractBlock.Settings settings) { + super(settings); + this.setDefaultState(this.stateManager.getDefaultState().with(ORIENTATION, Orientation.NORTH_UP).with(TRIGGERED, false).with(SMITHING, false)); + } + + protected MapCodec getCodec(){ return CODEC; } + + @Override + protected boolean hasComparatorOutput(BlockState state) { return true; } + + private void setTriggered(@Nullable BlockEntity blockEntity, boolean triggered) { + if (blockEntity instanceof SmitherBlockEntity smitherBlockEntity) { + smitherBlockEntity.setTriggered(triggered); + } + } + + @Override + public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { + SmitherBlockEntity smitherBlockEntity = new SmitherBlockEntity(pos, state); + smitherBlockEntity.setTriggered(state.contains(TRIGGERED) && state.get(TRIGGERED)); + return smitherBlockEntity; + } + + @Override + public BlockState getPlacementState(ItemPlacementContext ctx) { + Direction direction = ctx.getPlayerLookDirection().getOpposite(); + Direction direction2 = switch (direction) { + default -> throw new MatchException(null, null); + case UP -> ctx.getHorizontalPlayerFacing(); + case DOWN -> ctx.getHorizontalPlayerFacing().getOpposite(); + case EAST, SOUTH, WEST, NORTH -> Direction.UP; + }; + return this.getDefaultState().with(ORIENTATION, Orientation.byDirections(direction, direction2)).with(TRIGGERED, ctx.getWorld().isReceivingRedstonePower(ctx.getBlockPos())); + } + + @Override + public void onPlaced(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack itemStack) { + if (state.get(TRIGGERED)) { + world.scheduleBlockTick(pos, this, TRIGGER_DELAY); + } + } + + @Override + protected void neighborUpdate(BlockState state, World world, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) { + boolean bl = world.isReceivingRedstonePower(pos); + boolean bl2 = state.get(TRIGGERED); + BlockEntity blockEntity = world.getBlockEntity(pos); + if (bl && !bl2) { + world.scheduleBlockTick(pos, this, TRIGGER_DELAY); + world.setBlockState(pos, state.with(TRIGGERED, true), Block.NOTIFY_LISTENERS); + this.setTriggered(blockEntity, true); + } else if (!bl && bl2) { + while (world.setBlockState(pos, state.with(TRIGGERED, false).with(SMITHING, false), Block.NOTIFY_LISTENERS)); + this.setTriggered(blockEntity, false); + } + } + + @Override + protected void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random random){ + this.smith(state, world, pos); + } + + protected void smith(BlockState state, ServerWorld world, BlockPos pos) { + BlockEntity blockEntity = world.getBlockEntity(pos); + if (!(blockEntity instanceof SmitherBlockEntity smitherBlockEntity)) return; + SmithingRecipeInput smithingRecipeInput = new SmithingRecipeInput(((SmitherBlockEntity) blockEntity).getStack(0), ((SmitherBlockEntity) blockEntity).getStack(1), ((SmitherBlockEntity) blockEntity).getStack(2)); + Optional> optional = SmitherBlock.getSmithingRecipe(world, smithingRecipeInput); + } + + public static Optional> getSmithingRecipe(World world, SmithingRecipeInput input) { + if (input.isEmpty()) return Optional.empty(); + + return null; + } +} diff --git a/src/main/java/com/yipkei/vanilladdition/block/entity/SmitherBlockEntity.java b/src/main/java/com/yipkei/vanilladdition/block/entity/SmitherBlockEntity.java new file mode 100644 index 0000000..aac565a --- /dev/null +++ b/src/main/java/com/yipkei/vanilladdition/block/entity/SmitherBlockEntity.java @@ -0,0 +1,156 @@ +package com.yipkei.vanilladdition.block.entity; + +import com.yipkei.vanilladdition.block.SmitherBlock; +import com.yipkei.vanilladdition.block.screen.SmitherScreenHandler; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.block.entity.LootableContainerBlockEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventories; +import net.minecraft.inventory.Inventory; +import net.minecraft.inventory.RecipeInputInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.recipe.RecipeMatcher; +import net.minecraft.registry.RegistryWrapper; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.ScreenHandlerContext; +import net.minecraft.text.Text; +import net.minecraft.util.collection.DefaultedList; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class SmitherBlockEntity extends LootableContainerBlockEntity implements RecipeInputInventory { + public static final int GRID_SIZE = 3; + private DefaultedList inputStacks = DefaultedList.ofSize(3, ItemStack.EMPTY); + private int smithingTicksRemaining = 0; + private boolean triggered = false; + + public SmitherBlockEntity(BlockPos pos, BlockState state){ + super(BlockEntityType.CRAFTER, pos, state); + } + + protected Text getContainerName() { return Text.translatable("container.smither");} + + @Override + protected ScreenHandler createScreenHandler(int syncId, PlayerInventory playerInventory) { + return new SmitherScreenHandler(syncId, playerInventory, this, this.triggered, ScreenHandlerContext.create(world, pos)); + } + +// setSlotEnabled & isSlotDisabled 设置与读取禁用槽位 +// isValid 读取是否可用槽位,用于物品输入(通用) +// betterSlotExists 剩余槽位是否可用 + + @Override + protected void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) { + super.readNbt(nbt, registryLookup); + this.smithingTicksRemaining = nbt.getInt("smithing_ticks_remaining"); + this.inputStacks = DefaultedList.ofSize(this.size(), ItemStack.EMPTY); + if (!this.readLootTable(nbt)) { + Inventories.readNbt(nbt, this.inputStacks, registryLookup); + } + this.triggered = nbt.getBoolean("triggered"); + } + + @Override + protected void writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) { + super.writeNbt(nbt, registryLookup); + nbt.putInt("smithing_ticks_remaining", this.smithingTicksRemaining); + if (!this.writeLootTable(nbt)) { + Inventories.writeNbt(nbt, this.inputStacks, registryLookup); + } + nbt.putBoolean("triggered", this.triggered); + } + + @Override + public int size() { + return 3; + } + + @Override + public boolean isEmpty() { + for (ItemStack itemStack : this.inputStacks) { + if (itemStack.isEmpty()) continue; + return false; + } + return true; + } + + @Override + public ItemStack getStack(int slot) { + return this.inputStacks.get(slot); + } + +// setStack 无特殊操作,无需覆写 + + @Override + public boolean canPlayerUse(PlayerEntity player) { + return Inventory.canPlayerUse(this, player); + } + + @Override + public DefaultedList getHeldStacks() { + return this.inputStacks; + } + + @Override + protected void setHeldStacks(DefaultedList inventory) { + this.inputStacks = inventory; + } + + @Override + public int getWidth() { + return 3; + } + + @Override + public int getHeight() { + return 1; + } + + @Override + public void provideRecipeInputs(RecipeMatcher finder) { + for (ItemStack itemStack : this.inputStacks) { + finder.addUnenchantedInput(itemStack); + } + } + + + public void setTriggered(boolean triggered) { + this.triggered = triggered; + } + + public boolean isTriggered() { + return this.triggered; + } + + public static void tickSmithing(World world, BlockPos pos, BlockState state, SmitherBlockEntity blockEntity) { + int i = blockEntity.smithingTicksRemaining - 1; + if (i < 0) { + return; + } + blockEntity.smithingTicksRemaining = i; + if (i == 0) { + world.setBlockState(pos, state.with(SmitherBlock.SMITHING, false), Block.NOTIFY_ALL); + } + } + + public void setSmithingTicksRemaining(int smithingTicksRemaining) { + this.smithingTicksRemaining = smithingTicksRemaining; + } + + public int getComparatorOutput() { + int i = 0; + for (int j = 0; j < this.size(); ++j) { + ItemStack itemStack = this.getStack(j); + if (itemStack.isEmpty()) continue; + ++i; + } + return i; + } + + + +} diff --git a/src/main/java/com/yipkei/vanilladdition/block/screen/SmitherInputSlot.java b/src/main/java/com/yipkei/vanilladdition/block/screen/SmitherInputSlot.java new file mode 100644 index 0000000..0ff6cc7 --- /dev/null +++ b/src/main/java/com/yipkei/vanilladdition/block/screen/SmitherInputSlot.java @@ -0,0 +1,18 @@ +package com.yipkei.vanilladdition.block.screen; + +import net.minecraft.inventory.Inventory; +import net.minecraft.screen.slot.Slot; + +public class SmitherInputSlot extends Slot { + private final SmitherScreenHandler smitherScreenHandler; + public SmitherInputSlot(Inventory inventory, int index, int x, int y, SmitherScreenHandler smitherScreenHandler) { + super(inventory, index, x, y); + this.smitherScreenHandler = smitherScreenHandler; + } + + @Override + public void markDirty(){ + super.markDirty(); + this.smitherScreenHandler.onContentChanged(this.inventory); + } +} diff --git a/src/main/java/com/yipkei/vanilladdition/block/screen/SmitherScreen.java b/src/main/java/com/yipkei/vanilladdition/block/screen/SmitherScreen.java new file mode 100644 index 0000000..46e6643 --- /dev/null +++ b/src/main/java/com/yipkei/vanilladdition/block/screen/SmitherScreen.java @@ -0,0 +1,57 @@ +package com.yipkei.vanilladdition.block.screen; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.ingame.ForgingScreen; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +@Environment(value = EnvType.CLIENT) +public class SmitherScreen extends ForgingScreen { + private static final Identifier POWERED_REDSTONE_TEXTURE = Identifier.ofVanilla("container/crafter/powered_redstone"); + private static final Identifier UNPOWERED_REDSTONE_TEXTURE = Identifier.ofVanilla("container/crafter/unpowered_redstone"); + private static final Identifier TEXTURE = Identifier.ofVanilla("textures/gui/container/smithing_table.png"); + private static final Identifier ERROR_TEXTURE = Identifier.ofVanilla("container/smithing/error"); + + + + public SmitherScreen(SmitherScreenHandler handler, PlayerInventory playerInventory, Text title){ + super(handler, playerInventory, title,Identifier.ofVanilla("textures/gui/container/smithing.png")); + this.titleX = 44; + this.titleY = 15; + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + super.render(context, mouseX, mouseY, delta); + this.drawArrowTexture(context); + this.drawMouseoverTooltip(context, mouseX, mouseY); + } + + private void drawArrowTexture(DrawContext context) { + int i = this.width / 2 + 9; + int j = this.height /2 -48; + Identifier identifier = this.handler.isTriggered() ? POWERED_REDSTONE_TEXTURE : UNPOWERED_REDSTONE_TEXTURE; + context.drawGuiTexture(identifier, i, j, 16, 16); + } + + @Override + protected void drawBackground(DrawContext context, float delta, int mouseX, int mouseY) { + int i = (this.width - this.backgroundWidth) / 2; + int j = (this.height - this.backgroundHeight) / 2; + context.drawTexture(TEXTURE, i, j, 0, 0, this.backgroundWidth, this.backgroundHeight); + } + + @Override + protected void drawInvalidRecipeArrow(DrawContext context, int x, int y) { + if (this.hasInvalidRecipe()) { + context.drawGuiTexture(ERROR_TEXTURE, this.width /2 +9, this.height/2-48, 28, 21); + } + } + + private boolean hasInvalidRecipe(){ + return this.handler.getSlot(0).hasStack() && this.handler.getSlot(1).hasStack() && this.handler.getSlot(2).hasStack() && !this.handler.getSlot(3).hasStack(); + } +} diff --git a/src/main/java/com/yipkei/vanilladdition/block/screen/SmitherScreenHandler.java b/src/main/java/com/yipkei/vanilladdition/block/screen/SmitherScreenHandler.java new file mode 100644 index 0000000..411e2bb --- /dev/null +++ b/src/main/java/com/yipkei/vanilladdition/block/screen/SmitherScreenHandler.java @@ -0,0 +1,116 @@ +package com.yipkei.vanilladdition.block.screen; + +import com.yipkei.vanilladdition.init.ModBlocks; +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.inventory.SimpleInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.recipe.RecipeEntry; +import net.minecraft.recipe.RecipeType; +import net.minecraft.recipe.SmithingRecipe; +import net.minecraft.recipe.input.SmithingRecipeInput; +import net.minecraft.screen.*; +import net.minecraft.screen.slot.ForgingSlotsManager; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.world.World; + +import java.util.List; + +public class SmitherScreenHandler extends ForgingScreenHandler implements ScreenHandlerListener { + public static final int TEMPLATE_ID = 0; + public static final int EQUIPMENT_ID = 1; + public static final int MATERIAL_ID = 2; + public static final int OUTPUT_ID = 3; + public static final int TEMPLATE_X = 8; + public static final int EQUIPMENT_X = 26; + public static final int MATERIAL_X = 44; + private static final int OUTPUT_X = 98; + public static final int SLOT_Y = 48; + private final World world; + private RecipeEntry currentRecipe; + private final List> recipes; + protected static final int SIZE = 3; + private final boolean triggered; + + + public SmitherScreenHandler(int syncId, PlayerInventory playerInventory) { + this(syncId, playerInventory,new SimpleInventory(4), false, ScreenHandlerContext.EMPTY); + } + + public SmitherScreenHandler(int syncId, PlayerInventory playerInventory, Inventory inputInventory, boolean triggered, ScreenHandlerContext context) { + super(ScreenHandlerType.SMITHING, syncId, playerInventory, context); + this.world = playerInventory.player.getWorld(); + this.triggered = triggered; + this.addListener(this); + this.recipes = this.world.getRecipeManager().listAllOfType(RecipeType.SMITHING); + } + + @Override + protected ForgingSlotsManager getForgingSlotsManager(){ + return ForgingSlotsManager.create().input(0, 8, 48, stack -> !stack.isEmpty()).input(1, 26, 48, stack -> !stack.isEmpty()).input(2, 44, 48, stack -> !stack.isEmpty()).output(3, 98, 48).build(); + } + + public boolean isTriggered() { + return this.triggered; + } + + + @Override + protected boolean canTakeOutput(PlayerEntity player, boolean present) { + return false; + } + + @Override + protected void onTakeOutput(PlayerEntity player, ItemStack stack) { + + } + + @Override + protected boolean canUse(BlockState state) { + return state.isOf(ModBlocks.SMITHER); + } + + @Override + public boolean canUse(PlayerEntity player) { + return this.input.canPlayerUse(player); + } + + @Override + public void updateResult(){ + if (this.player instanceof ServerPlayerEntity serverPlayerEntity) { + World world = serverPlayerEntity.getWorld(); + SmithingRecipeInput smithingRecipeInput = this.createRecipeInput(); + List> list = world.getRecipeManager().getAllMatches(RecipeType.SMITHING, smithingRecipeInput, world); + if (list.isEmpty()) { + this.output.setStack(0, ItemStack.EMPTY); + } else { + RecipeEntry recipeEntry = list.getFirst(); + ItemStack stack = recipeEntry.value().craft(smithingRecipeInput, world.getRegistryManager()); + if (stack.isItemEnabled(world.getEnabledFeatures())){ + this.currentRecipe = recipeEntry; + this.output.setLastRecipe(recipeEntry); + this.output.setStack(0, stack); + } + } + } + } + + public Inventory getInputInventory() { + return this.input; + } + + @Override + public void onSlotUpdate(ScreenHandler handler, int slotId, ItemStack stack) { + this.updateResult(); + } + + @Override + public void onPropertyUpdate(ScreenHandler handler, int property, int value) { + } + + private SmithingRecipeInput createRecipeInput() { + return new SmithingRecipeInput(this.input.getStack(0), this.input.getStack(1), this.input.getStack(2)); + } +} diff --git a/src/main/java/com/yipkei/vanilladdition/data/generator/ModRecipesProvider.java b/src/main/java/com/yipkei/vanilladdition/data/generator/ModRecipesProvider.java index 713c1a6..ab8711a 100644 --- a/src/main/java/com/yipkei/vanilladdition/data/generator/ModRecipesProvider.java +++ b/src/main/java/com/yipkei/vanilladdition/data/generator/ModRecipesProvider.java @@ -131,6 +131,28 @@ public void generate(RecipeExporter exporter) { // 石英块拆解 offerHammerProcessing(exporter,ModTags.Items.QUARTZ_BLOCK,ModItems.DIAMOND_HAMMER, Items.QUARTZ, 3,"recycling"); + // 信标基座 + ShapedRecipeJsonBuilder.create(RecipeCategory.MISC, ModBlocks.LIGHT_BEACON_BASE, 8) + .pattern("#*#") + .pattern("*o*") + .pattern("#*#") + .input('#', ModBlocks.STEEL_BLOCK) + .input('*', Items.NETHERITE_SCRAP) + .input('o', Items.NETHER_STAR) + .criterion(hasItem(Items.NETHER_STAR), conditionsFromItem(Items.NETHER_STAR)) + .offerTo(exporter, Identifier.of(VanillaAddition.MOD_ID, getItemPath(ModBlocks.LIGHT_BEACON_BASE))); + + ShapedRecipeJsonBuilder.create(RecipeCategory.MISC, ModBlocks.PORTABLE_BEACON_BASE) + .pattern("ENE") + .pattern("GBG") + .pattern("III") + .input('E', Blocks.EMERALD_BLOCK) + .input('N', Items.NETHERITE_INGOT) + .input('G', Blocks.GOLD_BLOCK) + .input('B', Blocks.BEACON) + .input('I', Blocks.IRON_BLOCK) + .criterion(hasItem(Blocks.BEACON), conditionsFromItem(Blocks.BEACON)) + .offerTo(exporter, Identifier.of(VanillaAddition.MOD_ID, getItemPath(ModBlocks.PORTABLE_BEACON_BASE))); /* 锻造台配方 */ // 潮涌核心拆解 diff --git a/src/main/java/com/yipkei/vanilladdition/data/generator/loottable/ModBlockLootTablesProvider.java b/src/main/java/com/yipkei/vanilladdition/data/generator/loottable/ModBlockLootTablesProvider.java index 66aa4a8..05fca70 100644 --- a/src/main/java/com/yipkei/vanilladdition/data/generator/loottable/ModBlockLootTablesProvider.java +++ b/src/main/java/com/yipkei/vanilladdition/data/generator/loottable/ModBlockLootTablesProvider.java @@ -10,7 +10,6 @@ import net.minecraft.loot.LootTable; import net.minecraft.loot.condition.BlockStatePropertyLootCondition; import net.minecraft.loot.entry.ItemEntry; -import net.minecraft.loot.entry.LootPoolEntry; import net.minecraft.loot.function.LootFunction; import net.minecraft.loot.function.SetCountLootFunction; import net.minecraft.loot.provider.number.ConstantLootNumberProvider; @@ -29,6 +28,9 @@ public ModBlockLootTablesProvider(FabricDataOutput dataOutput, CompletableFuture public void generate() { addDrop(ModBlocks.STEEL_BLOCK); addDrop(ModBlocks.COMPRESS_WOOL); + addDrop(ModBlocks.LIGHT_BEACON_BASE); + + addDrop(ModBlocks.PORTABLE_BEACON_BASE, dropsWithSilkTouch(ModBlocks.BEACON)); addDrop(ModBlocks.STONE_WALL); addDrop(ModBlocks.POLISHED_GRANITE_WALL); @@ -243,6 +245,6 @@ public void generate() { } public LootTable.Builder slabDropsWithSilkTouch(Block block){ - return LootTable.builder().pool(LootPool.builder().conditionally(this.createSilkTouchCondition()).rolls(ConstantLootNumberProvider.create(1.0f)).with((LootPoolEntry.Builder)this.applyExplosionDecay(block, ItemEntry.builder(block).apply((LootFunction.Builder)((Object) SetCountLootFunction.builder(ConstantLootNumberProvider.create(2.0f)).conditionally(BlockStatePropertyLootCondition.builder(block).properties(StatePredicate.Builder.create().exactMatch(SlabBlock.TYPE, SlabType.DOUBLE)))))))); + return LootTable.builder().pool(LootPool.builder().conditionally(this.createSilkTouchCondition()).rolls(ConstantLootNumberProvider.create(1.0f)).with(this.applyExplosionDecay(block, ItemEntry.builder(block).apply((LootFunction.Builder)((Object) SetCountLootFunction.builder(ConstantLootNumberProvider.create(2.0f)).conditionally(BlockStatePropertyLootCondition.builder(block).properties(StatePredicate.Builder.create().exactMatch(SlabBlock.TYPE, SlabType.DOUBLE)))))))); } } diff --git a/src/main/java/com/yipkei/vanilladdition/data/generator/tag/ModBlockTagProvider.java b/src/main/java/com/yipkei/vanilladdition/data/generator/tag/ModBlockTagProvider.java index 0400f97..d1ad52d 100644 --- a/src/main/java/com/yipkei/vanilladdition/data/generator/tag/ModBlockTagProvider.java +++ b/src/main/java/com/yipkei/vanilladdition/data/generator/tag/ModBlockTagProvider.java @@ -41,6 +41,9 @@ protected void configure(RegistryWrapper.WrapperLookup arg) { .add(Blocks.GLASS_PANE , Blocks.WHITE_STAINED_GLASS_PANE, Blocks.LIGHT_GRAY_STAINED_GLASS_PANE, Blocks.GRAY_STAINED_GLASS_PANE, Blocks.BLACK_STAINED_GLASS_PANE, Blocks.BROWN_STAINED_GLASS_PANE, Blocks.RED_STAINED_GLASS_PANE, Blocks.ORANGE_STAINED_GLASS_PANE, Blocks.YELLOW_STAINED_GLASS_PANE, Blocks.LIME_STAINED_GLASS_PANE, Blocks.GREEN_STAINED_GLASS_PANE, Blocks.CYAN_STAINED_GLASS_PANE, Blocks.LIGHT_BLUE_STAINED_GLASS_PANE, Blocks.BLUE_STAINED_GLASS_PANE, Blocks.PURPLE_STAINED_GLASS_PANE, Blocks.MAGENTA_STAINED_GLASS_PANE, Blocks.PINK_STAINED_GLASS_PANE) .add(ModBlocks.STEEL_BLOCK) + + .add(ModBlocks.LIGHT_BEACON_BASE) + .add(ModBlocks.PORTABLE_BEACON_BASE) .add(ModBlocks.STONE_WALL) .add(ModBlocks.SMOOTH_STONE_WALL, ModBlocks.SMOOTH_STONE_STAIRS) .add(ModBlocks.CALCITE_WALL, ModBlocks.CALCITE_STAIRS, ModBlocks.CALCITE_SLAB) @@ -104,7 +107,8 @@ protected void configure(RegistryWrapper.WrapperLookup arg) { ; getOrCreateTagBuilder(BlockTags.BEACON_BASE_BLOCKS) - .add(ModBlocks.STEEL_BLOCK); + .add(ModBlocks.STEEL_BLOCK) + .add(ModBlocks.LIGHT_BEACON_BASE); getOrCreateTagBuilder(ModTags.Blocks.OBSIDIAN) .add(Blocks.OBSIDIAN, ModBlocks.OBSIDIAN_WALL, ModBlocks.OBSIDIAN_STAIRS, ModBlocks.OBSIDIAN_SLAB) diff --git a/src/main/java/com/yipkei/vanilladdition/entity/EnderTntEntity.java b/src/main/java/com/yipkei/vanilladdition/entity/EnderTntEntity.java new file mode 100644 index 0000000..7547b27 --- /dev/null +++ b/src/main/java/com/yipkei/vanilladdition/entity/EnderTntEntity.java @@ -0,0 +1,186 @@ +package com.yipkei.vanilladdition.entity; + +import com.yipkei.vanilladdition.init.ModBlocks; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.entity.*; +import net.minecraft.entity.data.DataTracker; +import net.minecraft.entity.data.TrackedData; +import net.minecraft.entity.data.TrackedDataHandlerRegistry; +import net.minecraft.fluid.FluidState; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.nbt.NbtHelper; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.BlockView; +import net.minecraft.world.TeleportTarget; +import net.minecraft.world.World; +import net.minecraft.world.explosion.Explosion; +import net.minecraft.world.explosion.ExplosionBehavior; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +public class EnderTntEntity extends Entity implements Ownable{ + + private static final TrackedData FUSE = DataTracker.registerData(EnderTntEntity.class, TrackedDataHandlerRegistry.INTEGER); + private static final TrackedData BLOCK_STATE = DataTracker.registerData(EnderTntEntity.class, TrackedDataHandlerRegistry.BLOCK_STATE); + private static final int DEFAULT_FUSE = 40; + public static final String FUSE_NBT_KEY = "fuse"; + private static final String BLOCK_STATE_NBT_KEY = "block_state"; + private static final ExplosionBehavior TELEPORTED_EXPLOSION_BEHAVIOR = new ExplosionBehavior() { + @Override + public boolean canDestroyBlock(Explosion explosion, BlockView world, BlockPos pos, BlockState state, float power) { + if (state.isOf(Blocks.NETHER_PORTAL)) { + return false; + } + return super.canDestroyBlock(explosion, world, pos, state, power); + } + + @Override + public Optional getBlastResistance(Explosion explosion, BlockView world, BlockPos pos, BlockState blockState, FluidState fluidState) { + if (blockState.isOf(Blocks.NETHER_PORTAL)) { + return Optional.empty(); + } + return super.getBlastResistance(explosion, world, pos, blockState, fluidState); + } + }; + + private LivingEntity causingEntity; + private boolean teleported; + private Direction facing; + + public EnderTntEntity(EntityType entityType, World world, Direction facing) { + super(entityType, world); + this.facing = facing; + } + + public EnderTntEntity(World world, double x, double y, double z, @Nullable LivingEntity igniter, Direction facing) { + this((EntityType)EntityType.TNT, world, facing); + this.setPosition(x, y, z); + this.setVelocity(0f, 0.2f, 0f); + this.setFuse(DEFAULT_FUSE); + this.prevX = x; + this.prevY = y; + this.prevZ = z; + this.causingEntity = igniter; + this.facing = facing; + } + + @Override + protected void initDataTracker(DataTracker.Builder builder){ + builder.add(FUSE, DEFAULT_FUSE); + builder.add(BLOCK_STATE, ModBlocks.ENDER_TNT.getDefaultState()); + } + + @Override + public void tick(){ + this.tickPortalTeleportation(); + this.applyGravity(); + this.move(MovementType.SELF, this.getVelocity()); + this.setVelocity(this.getVelocity().multiply(0.98)); + if (this.isOnGround()) { + this.setVelocity(this.getVelocity().multiply(0.7, -0.5, 0.7)); + } + int i = this.getFuse() - 1; + this.setFuse(i); + if (i <= 0) { + this.discard(); + if (!this.getWorld().isClient) { + this.explode(); + } + } else { + this.updateWaterState(); + if (this.getWorld().isClient) { + this.getWorld().addParticle(ParticleTypes.SMOKE, this.getX(), this.getY() + 0.5, this.getZ(), 0.0, 0.0, 0.0); + } + } + } + + private void explode() { + BlockPos pos = this.getBlockPos(); + World world = this.getWorld(); + if (world.getBlockState(pos).isAir()){ + pos = pos.offset(this.facing,1); + } + float destroyPower = 10000f; + for (int i=10; i>0; i--){ + float resistance = world.getBlockState(pos).getBlock().getBlastResistance(); + destroyPower = destroyPower / ((resistance == 0F) ? 1 : resistance); + if (destroyPower > 10000) destroyPower = 10000f; + world.removeBlock(pos, false); + pos = pos.offset(this.facing,1); + if (destroyPower < 1.0F) break; + } + float power = 4.0f; + this.getWorld().createExplosion(this, Explosion.createDamageSource(this.getWorld(), this), this.teleported ? TELEPORTED_EXPLOSION_BEHAVIOR : null, this.getX(), this.getBodyY(0.0625), this.getZ(), power, false, World.ExplosionSourceType.TNT); + } + + @Override + protected void writeCustomDataToNbt(NbtCompound nbt) { + nbt.putShort(FUSE_NBT_KEY, (short)this.getFuse()); + nbt.put(BLOCK_STATE_NBT_KEY, NbtHelper.fromBlockState(this.getBlockState())); + } + + @Override + protected void readCustomDataFromNbt(NbtCompound nbt) { + this.setFuse(nbt.getShort(FUSE_NBT_KEY)); + if (nbt.contains(BLOCK_STATE_NBT_KEY, NbtElement.COMPOUND_TYPE)) { + this.setBlockState(NbtHelper.toBlockState(this.getWorld().createCommandRegistryWrapper(RegistryKeys.BLOCK), nbt.getCompound(BLOCK_STATE_NBT_KEY))); + } + } + + @Override + @Nullable + public LivingEntity getOwner() { + return this.causingEntity; + } + + @Override + public void copyFrom(Entity original) { + super.copyFrom(original); + if (original instanceof TntEntity) { + EnderTntEntity enderTntEntity = (EnderTntEntity)original; + this.causingEntity = enderTntEntity.causingEntity; + } + } + + private void setTeleported(boolean teleported) { + this.teleported = teleported; + } + + public void setFuse(int fuse) { + this.dataTracker.set(FUSE, fuse); + } + + public int getFuse() { + return this.dataTracker.get(FUSE); + } + + public void setBlockState(BlockState state) { + this.dataTracker.set(BLOCK_STATE, state); + } + + public BlockState getBlockState() { + return this.dataTracker.get(BLOCK_STATE); + } + + @Override + protected double getGravity() { + return 0.04; + } + + @Override + @Nullable + public Entity teleportTo(TeleportTarget teleportTarget) { + Entity entity = super.teleportTo(teleportTarget); + if (entity instanceof TntEntity) { + EnderTntEntity enderTntEntity = (EnderTntEntity)entity; + enderTntEntity.setTeleported(true); + } + return entity; + } +} diff --git a/src/main/java/com/yipkei/vanilladdition/handler/BeaconHandler.java b/src/main/java/com/yipkei/vanilladdition/handler/BeaconHandler.java new file mode 100644 index 0000000..1c484ca --- /dev/null +++ b/src/main/java/com/yipkei/vanilladdition/handler/BeaconHandler.java @@ -0,0 +1,5 @@ +package com.yipkei.vanilladdition.handler; + +public class BeaconHandler { + public static final ThreadLocal SHOULD_CHECK_MIDDLE = new ThreadLocal<>(); +} diff --git a/src/main/java/com/yipkei/vanilladdition/init/ModBlockEntityType.java b/src/main/java/com/yipkei/vanilladdition/init/ModBlockEntityType.java new file mode 100644 index 0000000..a4d242e --- /dev/null +++ b/src/main/java/com/yipkei/vanilladdition/init/ModBlockEntityType.java @@ -0,0 +1,20 @@ +package com.yipkei.vanilladdition.init; + +import com.yipkei.vanilladdition.VanillaAddition; +import com.yipkei.vanilladdition.block.entity.SmitherBlockEntity; +import net.minecraft.block.Block; +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.registry.Registries; +import net.minecraft.registry.Registry; +import net.minecraft.util.Identifier; + +public class ModBlockEntityType{ + public static final BlockEntityType SMITHER = (BlockEntityType) registerBlockEntities("smither", SmitherBlockEntity::new, ModBlocks.SMITHER); + + + private static BlockEntityType registerBlockEntities(String id, BlockEntityType.BlockEntityFactory factory, Block block){ + return Registry.register(Registries.BLOCK_ENTITY_TYPE, Identifier.of(VanillaAddition.MOD_ID, id), BlockEntityType.Builder.create(factory, block).build()); + } + + public static void registerBlockEntities(){} +} diff --git a/src/main/java/com/yipkei/vanilladdition/init/ModBlocks.java b/src/main/java/com/yipkei/vanilladdition/init/ModBlocks.java index 310ee7e..910f28d 100644 --- a/src/main/java/com/yipkei/vanilladdition/init/ModBlocks.java +++ b/src/main/java/com/yipkei/vanilladdition/init/ModBlocks.java @@ -1,11 +1,9 @@ package com.yipkei.vanilladdition.init; import com.yipkei.vanilladdition.VanillaAddition; -import com.yipkei.vanilladdition.block.BlindBox; -import com.yipkei.vanilladdition.block.TranslucentSlab; -import com.yipkei.vanilladdition.block.TranslucentStairs; -import com.yipkei.vanilladdition.block.TranslucentWall; +import com.yipkei.vanilladdition.block.*; import net.minecraft.block.*; +import net.minecraft.block.piston.PistonBehavior; import net.minecraft.item.BlockItem; import net.minecraft.item.Item; import net.minecraft.registry.Registries; @@ -15,6 +13,13 @@ public class ModBlocks extends Blocks{ public static final Block STEEL_BLOCK = registerBlocks("steel_block",new Block(AbstractBlock.Settings.copy(IRON_BLOCK))); public static final Block COMPRESS_WOOL = registerBlocks("compress_wool", new Block(AbstractBlock.Settings.copy(WHITE_WOOL))); + public static final Block ENDER_TNT = registerBlocks("ender_tnt", new EnderTntBlock (AbstractBlock.Settings.copy(TNT).pistonBehavior(PistonBehavior.DESTROY))); + + public static final Block SMITHER = registerBlocks("smither",(Block) new SmitherBlock(AbstractBlock.Settings.create().strength(1.5f, 3.5f))); + + public static final Block PORTABLE_BEACON_BASE = registerBlocks("portable_beacon_base", new Block(AbstractBlock.Settings.copy(NETHERITE_BLOCK).pistonBehavior(PistonBehavior.BLOCK))); + + public static final Block LIGHT_BEACON_BASE = registerBlocks("light_beacon_base", new Block(AbstractBlock.Settings.copy(IRON_BLOCK).hardness(0.5F).pistonBehavior(PistonBehavior.BLOCK))); public static final Block STONE_BLIND_BOX = registerBlocks("stone_blind_box", new BlindBox(ModLootTables.STONE_BLIND_BOX, Blocks.STONE)); public static final Block COAL_BLIND_BOX = registerBlocks("coal_blind_box", new BlindBox(ModLootTables.COAL_BLIND_BOX, Blocks.COAL_BLOCK)); @@ -261,6 +266,13 @@ public class ModBlocks extends Blocks{ public static final Block QUARTZ_WALL = registerBlocks("quartz_wall", new WallBlock(AbstractBlock.Settings.copy(QUARTZ_BLOCK).solid())); +// private static Block createPortableBeacon(RegistryEntry primary, RegistryEntry secondary){ +// PortableBeacon block = new PortableBeacon(AbstractBlock.Settings.copy(Blocks.BEACON)); +// block.setPrimary(primary); +// block.setSecondary(secondary); +// return block; +// } + private static Block registerBlocks(String name,Block block){ registerBlockItems(name,block); return Registry.register(Registries.BLOCK, Identifier.of(VanillaAddition.MOD_ID,name),block); diff --git a/src/main/java/com/yipkei/vanilladdition/mixin/BeaconBlockEntityMixin.java b/src/main/java/com/yipkei/vanilladdition/mixin/BeaconBlockEntityMixin.java new file mode 100644 index 0000000..3c227c8 --- /dev/null +++ b/src/main/java/com/yipkei/vanilladdition/mixin/BeaconBlockEntityMixin.java @@ -0,0 +1,36 @@ +package com.yipkei.vanilladdition.mixin; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.yipkei.vanilladdition.handler.BeaconHandler; +import com.yipkei.vanilladdition.init.ModBlocks; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BeaconBlockEntity; +import net.minecraft.registry.tag.BlockTags; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(BeaconBlockEntity.class) +public class BeaconBlockEntityMixin { + @ModifyExpressionValue(method = "updateLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;getBlockState(Lnet/minecraft/util/math/BlockPos;)Lnet/minecraft/block/BlockState;")) + private static BlockState getLevel(BlockState state){ + BeaconHandler.SHOULD_CHECK_MIDDLE.set(false); + if (!state.isIn(BlockTags.BEACON_BASE_BLOCKS)) { + BeaconHandler.SHOULD_CHECK_MIDDLE.set(true); + } + return state; + } + + @Inject(method = "updateLevel", at = @At("RETURN"), cancellable = true) + private static void setReturnLevel(World world, int x, int y, int z, CallbackInfoReturnable cir){ + boolean bl = BeaconHandler.SHOULD_CHECK_MIDDLE.get(); + BeaconHandler.SHOULD_CHECK_MIDDLE.remove(); + if (bl && world.getBlockState(new BlockPos(x, y-1, z)).isOf(ModBlocks.PORTABLE_BEACON_BASE)) { + cir.setReturnValue(4); + } + } + +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 0809c01..62089f4 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -34,6 +34,7 @@ "java": ">=21", "fabric-api": "*" }, + "accessWidener": "vanilla-addition.accesswidener", "suggests": { "another-mod": "*" } diff --git a/src/main/resources/vanilla-addition.accesswidener b/src/main/resources/vanilla-addition.accesswidener new file mode 100644 index 0000000..1a8f0a8 --- /dev/null +++ b/src/main/resources/vanilla-addition.accesswidener @@ -0,0 +1,2 @@ +accessWidener v1 named +accessible method net/minecraft/block/entity/BeaconBlockEntity$BeamSegment increaseHeight ()V \ No newline at end of file diff --git a/src/main/resources/vanilla-addition.mixins.json b/src/main/resources/vanilla-addition.mixins.json index 103adef..7940912 100644 --- a/src/main/resources/vanilla-addition.mixins.json +++ b/src/main/resources/vanilla-addition.mixins.json @@ -3,6 +3,7 @@ "package": "com.yipkei.vanilladdition.mixin", "compatibilityLevel": "JAVA_21", "mixins": [ + "BeaconBlockEntityMixin", "BoggedEntityMixin", "BoneMealItemMixin", "CraftingResultSlotMixin",