diff --git a/src/main/generated/data/oritech/loot_table/blocks/small_storage_block.json b/src/main/generated/data/oritech/loot_table/blocks/small_storage_block.json new file mode 100644 index 000000000..b72a1f4f0 --- /dev/null +++ b/src/main/generated/data/oritech/loot_table/blocks/small_storage_block.json @@ -0,0 +1,25 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "functions": [ + { + "function": "oritech:nbt_block_loot_function" + } + ], + "name": "oritech:small_storage_block" + } + ], + "rolls": 1.0 + } + ] +} \ No newline at end of file diff --git a/src/main/generated/data/oritech/loot_table/blocks/small_tank_block.json b/src/main/generated/data/oritech/loot_table/blocks/small_tank_block.json new file mode 100644 index 000000000..bd662b46d --- /dev/null +++ b/src/main/generated/data/oritech/loot_table/blocks/small_tank_block.json @@ -0,0 +1,25 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "functions": [ + { + "function": "oritech:nbt_block_loot_function" + } + ], + "name": "oritech:small_tank_block" + } + ], + "rolls": 1.0 + } + ] +} \ No newline at end of file diff --git a/src/main/java/rearth/oritech/Oritech.java b/src/main/java/rearth/oritech/Oritech.java index 340d0c08e..e245cbca8 100644 --- a/src/main/java/rearth/oritech/Oritech.java +++ b/src/main/java/rearth/oritech/Oritech.java @@ -58,6 +58,7 @@ public void onInitialize() { NetworkContent.registerChannels(); ParticleContent.registerParticles(); FeatureContent.initialize(); + LootContent.init(); ServerLifecycleEvents.SERVER_STARTED.register(this::onServerStarted); PlayerBlockBreakEvents.BEFORE.register(PromethiumPickaxeItem::preMine); diff --git a/src/main/java/rearth/oritech/block/blocks/machines/storage/SmallFluidTank.java b/src/main/java/rearth/oritech/block/blocks/machines/storage/SmallFluidTank.java index b035fdd01..b3db53b93 100644 --- a/src/main/java/rearth/oritech/block/blocks/machines/storage/SmallFluidTank.java +++ b/src/main/java/rearth/oritech/block/blocks/machines/storage/SmallFluidTank.java @@ -11,10 +11,11 @@ import net.minecraft.block.entity.BlockEntityType; import net.minecraft.component.DataComponentTypes; import net.minecraft.component.type.NbtComponent; -import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; +import net.minecraft.loot.context.LootContextParameterSet; +import net.minecraft.loot.context.LootContextParameters; import net.minecraft.nbt.NbtCompound; import net.minecraft.text.Text; import net.minecraft.util.ActionResult; @@ -22,8 +23,12 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.WorldView; + +import java.util.List; + import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; + import rearth.oritech.block.entity.machines.storage.SmallFluidTankEntity; import rearth.oritech.init.BlockContent; @@ -65,30 +70,17 @@ public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEnt return ActionResult.SUCCESS; } - - @Override - public BlockState onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player) { - - if (!world.isClient) { - var stack = getStackWithData(world, pos); - var tankEntity = (SmallFluidTankEntity) world.getBlockEntity(pos); - - if (!player.isCreative()) - Block.dropStack(world, pos, stack); - - var stacks = tankEntity.inventory.heldStacks; - for (var heldStack : stacks) { - if (!heldStack.isEmpty()) { - var itemEntity = new ItemEntity(world, pos.getX(), pos.getY(), pos.getZ(), heldStack); - world.spawnEntity(itemEntity); - } - } - - } - - return super.onBreak(world, pos, state, player); + + protected List getDroppedStacks(BlockState state, LootContextParameterSet.Builder builder) { + var droppedStacks = super.getDroppedStacks(state, builder); + + var blockEntity = (BlockEntity)builder.getOptional(LootContextParameters.BLOCK_ENTITY); + if (blockEntity instanceof SmallFluidTankEntity tankEntity) + droppedStacks.addAll(tankEntity.inventory.getHeldStacks()); + + return droppedStacks; } - + @Override public ItemStack getPickStack(WorldView world, BlockPos pos, BlockState state) { return getStackWithData(world, pos); @@ -102,7 +94,6 @@ private static ItemStack getStackWithData(WorldView world, BlockPos pos) { if (tankEntity.getForDirectFluidAccess().amount > 0) { var nbt = new NbtCompound(); tankEntity.writeNbt(nbt, world.getRegistryManager()); - nbt.remove("Items"); stack.set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(nbt)); var fluidName = FluidVariantAttributes.getName(tankEntity.getForDirectFluidAccess().variant); stack.set(DataComponentTypes.CUSTOM_NAME, fluidName.copy().append(" ").append(Text.translatable("block.oritech.small_tank_block"))); diff --git a/src/main/java/rearth/oritech/block/blocks/machines/storage/SmallStorageBlock.java b/src/main/java/rearth/oritech/block/blocks/machines/storage/SmallStorageBlock.java index c2c442259..aa9beaf12 100644 --- a/src/main/java/rearth/oritech/block/blocks/machines/storage/SmallStorageBlock.java +++ b/src/main/java/rearth/oritech/block/blocks/machines/storage/SmallStorageBlock.java @@ -1,6 +1,7 @@ package rearth.oritech.block.blocks.machines.storage; import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory; +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariantAttributes; import net.minecraft.block.Block; import net.minecraft.block.BlockEntityProvider; import net.minecraft.block.BlockRenderType; @@ -10,13 +11,14 @@ import net.minecraft.block.entity.BlockEntityType; import net.minecraft.component.DataComponentTypes; import net.minecraft.component.type.NbtComponent; -import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemPlacementContext; import net.minecraft.item.ItemStack; import net.minecraft.item.tooltip.TooltipType; +import net.minecraft.loot.context.LootContextParameterSet; +import net.minecraft.loot.context.LootContextParameters; import net.minecraft.nbt.NbtCompound; import net.minecraft.state.StateManager; import net.minecraft.state.property.DirectionProperty; @@ -27,14 +29,19 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.world.World; +import net.minecraft.world.WorldView; + +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import rearth.oritech.block.base.entity.ExpandableEnergyStorageBlockEntity; +import rearth.oritech.block.entity.machines.storage.SmallFluidTankEntity; import rearth.oritech.block.entity.machines.storage.SmallStorageBlockEntity; import rearth.oritech.init.BlockContent; import rearth.oritech.util.MachineAddonController; import java.util.List; import java.util.Objects; +import java.util.UUID; import static rearth.oritech.util.TooltipHelper.addMachineTooltip; @@ -106,43 +113,34 @@ public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEnt return ActionResult.SUCCESS; } - + + protected List getDroppedStacks(BlockState state, LootContextParameterSet.Builder builder) { + var droppedStacks = super.getDroppedStacks(state, builder); + + var blockEntity = (BlockEntity)builder.getOptional(LootContextParameters.BLOCK_ENTITY); + if (blockEntity instanceof SmallStorageBlockEntity storageEntity) + droppedStacks.addAll(storageEntity.inventory.getHeldStacks()); + + return droppedStacks; + } + @Override - public BlockState onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player) { + public ItemStack getPickStack(WorldView world, BlockPos pos, BlockState state) { + return getStackWithData(world, pos); + } + + @NotNull + private static ItemStack getStackWithData(WorldView world, BlockPos pos) { + var stack = new ItemStack(BlockContent.SMALL_STORAGE_BLOCK.asItem()); + var storageEntity = (SmallStorageBlockEntity) world.getBlockEntity(pos); - if (!world.isClient()) { - - var entity = world.getBlockEntity(pos); - if (entity instanceof MachineAddonController machineEntity) { - machineEntity.resetAddons(); - } - - if (entity instanceof ExpandableEnergyStorageBlockEntity storageBlock) { - var stacks = storageBlock.inventory.heldStacks; - for (var heldStack : stacks) { - if (!heldStack.isEmpty()) { - var itemEntity = new ItemEntity(world, pos.getX(), pos.getY(), pos.getZ(), heldStack); - world.spawnEntity(itemEntity); - } - } - - // drop block with nbt - if (state.getBlock().equals(BlockContent.SMALL_STORAGE_BLOCK)) { - var stack = new ItemStack(BlockContent.SMALL_STORAGE_BLOCK.asItem()); - var storedAmount = storageBlock.getStorageForAddon().amount; - if (storedAmount > 0) { - var nbt = new NbtCompound(); - storageBlock.writeNbt(nbt, world.getRegistryManager()); - stack.set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(nbt)); - } - - if (!player.isCreative()) - Block.dropStack(world, pos, stack); - } - } + if (storageEntity.getStorage(null).getAmount() > 0) { + var nbt = new NbtCompound(); + storageEntity.writeNbt(nbt, world.getRegistryManager()); + stack.set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(nbt)); } - return super.onBreak(world, pos, state, player); + return stack; } @Override diff --git a/src/main/java/rearth/oritech/init/BlockContent.java b/src/main/java/rearth/oritech/init/BlockContent.java index 03d3947b2..399b2cebd 100644 --- a/src/main/java/rearth/oritech/init/BlockContent.java +++ b/src/main/java/rearth/oritech/init/BlockContent.java @@ -3,6 +3,8 @@ import io.wispforest.owo.registration.reflect.BlockRegistryContainer; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; import net.minecraft.block.*; +import net.minecraft.block.dispenser.BlockPlacementDispenserBehavior; +import net.minecraft.block.piston.PistonBehavior; import net.minecraft.fluid.FlowableFluid; import net.minecraft.item.BlockItem; import net.minecraft.item.Item; @@ -104,10 +106,12 @@ public class BlockContent implements BlockRegistryContainer { public static final Block DRONE_PORT_BLOCK = new DronePortBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque()); @NoAutoDrop - public static final Block SMALL_STORAGE_BLOCK = new SmallStorageBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque()); + @DispenserPlace + public static final Block SMALL_STORAGE_BLOCK = new SmallStorageBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque().pistonBehavior(PistonBehavior.DESTROY)); public static final Block LARGE_STORAGE_BLOCK = new LargeStorageBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque()); @NoAutoDrop - public static final Block SMALL_TANK_BLOCK = new SmallFluidTank(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque()); + @DispenserPlace + public static final Block SMALL_TANK_BLOCK = new SmallFluidTank(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque().pistonBehavior(PistonBehavior.DESTROY)); public static final Block PLACER_BLOCK = new PlacerBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque()); public static final Block DESTROYER_BLOCK = new DestroyerBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque()); @@ -241,6 +245,10 @@ public void postProcessField(String namespace, Block value, String identifier, F if (!field.isAnnotationPresent(NoAutoDrop.class)) { BlockLootGenerator.autoRegisteredDrops.add(value); } + + if (field.isAnnotationPresent(DispenserPlace.class)) { + DispenserBlock.registerBehavior(value, new BlockPlacementDispenserBehavior()); + } ItemGroups.add(targetGroup, value); } @@ -260,5 +268,10 @@ private BlockItem getGeoBlockItem(Block block, String identifier, float scale) { @Target({ElementType.FIELD}) public @interface NoAutoDrop { } + + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD}) + public @interface DispenserPlace { + } } diff --git a/src/main/java/rearth/oritech/init/LootContent.java b/src/main/java/rearth/oritech/init/LootContent.java new file mode 100644 index 000000000..dc899ac12 --- /dev/null +++ b/src/main/java/rearth/oritech/init/LootContent.java @@ -0,0 +1,15 @@ +package rearth.oritech.init; + +import net.minecraft.loot.function.LootFunctionType; +import net.minecraft.registry.Registries; +import net.minecraft.registry.Registry; +import rearth.oritech.Oritech; +import rearth.oritech.init.datagen.loot.NbtBlockLootFunction; + +public class LootContent { + public static final LootFunctionType NBT_BLOCK_LOOT_FUNCTION = new LootFunctionType<>(NbtBlockLootFunction.CODEC); + + public static void init() { + Registry.register(Registries.LOOT_FUNCTION_TYPE, Oritech.id("nbt_block_loot_function"), NBT_BLOCK_LOOT_FUNCTION); + } +} diff --git a/src/main/java/rearth/oritech/init/datagen/BlockLootGenerator.java b/src/main/java/rearth/oritech/init/datagen/BlockLootGenerator.java index b1f0b79a5..3cbea7e34 100644 --- a/src/main/java/rearth/oritech/init/datagen/BlockLootGenerator.java +++ b/src/main/java/rearth/oritech/init/datagen/BlockLootGenerator.java @@ -3,10 +3,18 @@ import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; import net.fabricmc.fabric.api.datagen.v1.provider.FabricBlockLootTableProvider; import net.minecraft.block.Block; +import net.minecraft.component.DataComponentTypes; import net.minecraft.item.Item; +import net.minecraft.loot.LootPool; +import net.minecraft.loot.LootTable; +import net.minecraft.loot.entry.ItemEntry; +import net.minecraft.loot.function.CopyComponentsLootFunction; +import net.minecraft.loot.function.CopyComponentsLootFunction.Source; +import net.minecraft.loot.provider.number.ConstantLootNumberProvider; import net.minecraft.registry.RegistryWrapper; import rearth.oritech.init.BlockContent; import rearth.oritech.init.ItemContent; +import rearth.oritech.init.datagen.loot.NbtBlockLootFunction; import java.util.HashSet; import java.util.Set; @@ -34,9 +42,20 @@ public void generate() { addDrop(BlockContent.ITEM_PIPE_CONNECTION, BlockContent.ITEM_PIPE); addDrop(BlockContent.FLUID_PIPE_CONNECTION, BlockContent.FLUID_PIPE); addDrop(BlockContent.ENERGY_PIPE_CONNECTION, BlockContent.ENERGY_PIPE); + + addCustomDataDrop(BlockContent.SMALL_TANK_BLOCK); + addCustomDataDrop(BlockContent.SMALL_STORAGE_BLOCK); } private void addOreDrop(Block block, Item item) { addDrop(block, oreDrops(block, item)); } + + private void addCustomDataDrop(Block block) { + // similar to shulkerBoxDrops + addDrop(block, LootTable.builder().pool( + (LootPool.Builder)this.addSurvivesExplosionCondition(block, LootPool.builder() + .rolls(ConstantLootNumberProvider.create(1.0F)) + .with(ItemEntry.builder(block).apply(NbtBlockLootFunction.builder()))))); + } } diff --git a/src/main/java/rearth/oritech/init/datagen/loot/NbtBlockLootFunction.java b/src/main/java/rearth/oritech/init/datagen/loot/NbtBlockLootFunction.java new file mode 100644 index 000000000..2b3f3a830 --- /dev/null +++ b/src/main/java/rearth/oritech/init/datagen/loot/NbtBlockLootFunction.java @@ -0,0 +1,71 @@ +package rearth.oritech.init.datagen.loot; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariantAttributes; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.NbtComponent; +import net.minecraft.item.ItemStack; +import net.minecraft.loot.condition.LootCondition; +import net.minecraft.loot.context.LootContext; +import net.minecraft.loot.context.LootContextParameters; +import net.minecraft.loot.function.ConditionalLootFunction; +import net.minecraft.loot.function.LootFunctionType; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.text.Text; +import rearth.oritech.block.entity.machines.storage.SmallFluidTankEntity; +import rearth.oritech.block.entity.machines.storage.SmallStorageBlockEntity; +import rearth.oritech.init.LootContent; + +import java.util.List; +import java.util.UUID; + +public class NbtBlockLootFunction extends ConditionalLootFunction { + public static final String NAME = "nbt_block_loot"; + + public NbtBlockLootFunction(List conditions) { + super(conditions); + } + + @Override + public ItemStack process(ItemStack stack, LootContext context) { + var blockEntity = context.get(LootContextParameters.BLOCK_ENTITY); + + var nbt = new NbtCompound(); + if (blockEntity instanceof SmallFluidTankEntity tankEntity) { + if (tankEntity.getForDirectFluidAccess().amount > 0) { + tankEntity.writeNbt(nbt, context.getWorld().getRegistryManager()); + var fluidName = FluidVariantAttributes.getName(tankEntity.getForDirectFluidAccess().variant); + stack.set(DataComponentTypes.CUSTOM_NAME, fluidName.copy().append(" ").append(Text.translatable("block.oritech.small_tank_block"))); + // make all non-empty tanks unstackable + nbt.putUuid("unstackable", UUID.randomUUID()); + } + } else if (blockEntity instanceof SmallStorageBlockEntity storageEntity) { + if (storageEntity.getStorage(null).getAmount() > 0) { + storageEntity.writeNbt(nbt, context.getWorld().getRegistryManager()); + // make all non-empty storage blocks unstackable + nbt.putUuid("unstackable", UUID.randomUUID()); + } + } + + // Any items contained in the block should be added to the drops in the Block's getDroppedStacks() method + // Removing it here so that the inventory items are not still stored in the dropped item's data + if (nbt.contains("Items")) + nbt.remove("Items"); + stack.set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(nbt)); + return stack; + } + + @Override + public LootFunctionType getType() { + return LootContent.NBT_BLOCK_LOOT_FUNCTION; + } + + public static ConditionalLootFunction.Builder builder() { + return ConditionalLootFunction.builder(NbtBlockLootFunction::new); + } + + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + instance -> ConditionalLootFunction.addConditionsField(instance).apply(instance, NbtBlockLootFunction::new)); +}