Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/main/java/codechicken/microblock/part/MicroblockPart.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.storage.loot.LootParams;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.api.distmarker.OnlyIn;

Expand Down Expand Up @@ -106,7 +107,7 @@ public void load(CompoundTag tag, HolderLookup.Provider registries) {
public abstract int getItemFactoryId();

@Override
public Iterable<ItemStack> getDrops() {
public Iterable<ItemStack> getDrops(LootParams.Builder builder) {
int size = getSize();
List<ItemStack> items = new LinkedList<>();
for (int s : new int[] { 4, 2, 1 }) {
Expand All @@ -120,14 +121,14 @@ public Iterable<ItemStack> getDrops() {
}

@Override
public ItemStack getCloneStack(PartRayTraceResult hit) {
public ItemStack getCloneStack(PartRayTraceResult hit, Player player) {
int size = getSize();
for (int s : new int[] { 4, 2, 1 }) {
if (size % s == 0 && size / s >= 1) {
return ItemMicroBlock.create(getItemFactoryId(), size, material);
}
}
return super.getCloneStack(hit);
return ItemStack.EMPTY;
}

public abstract Iterable<MaskedCuboid> getRenderCuboids(boolean isInventory);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package codechicken.multipart.api;

import codechicken.multipart.CBMultipart;
import codechicken.multipart.api.part.MultiPart;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.storage.loot.parameters.LootContextParam;

/**
* Created by covers1624 on 6/5/25.
*/
public class MultipartLootContextParams {

public static final LootContextParam<MultiPart> MULTI_PART = new LootContextParam<>(ResourceLocation.fromNamespaceAndPath(CBMultipart.MOD_ID, "multipart"));
}
65 changes: 59 additions & 6 deletions src/main/java/codechicken/multipart/api/part/MultiPart.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import codechicken.lib.data.MCDataOutput;
import codechicken.lib.vec.Cuboid6;
import codechicken.lib.vec.Vector3;
import codechicken.multipart.api.MultipartLootContextParams;
import codechicken.multipart.api.MultipartType;
import codechicken.multipart.api.PartConverter;
import codechicken.multipart.block.TileMultipart;
Expand All @@ -15,6 +16,7 @@
import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.ItemInteractionResult;
Expand All @@ -30,6 +32,9 @@
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.storage.loot.LootParams;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
Expand Down Expand Up @@ -245,12 +250,13 @@ default VoxelShape getVisualShape(CollisionContext context) {
* Harvest this part, removing it from the container {@link TileMultipart}
* and dropping any items if necessary.
*
* @param player The {@link Player} harvesting the part.
* @param hit The {@link PartRayTraceResult} hit result.
* @param player The {@link Player} harvesting the part.
* @param hit The {@link PartRayTraceResult} hit result.
* @param harvestTool The tool the player used to remove this part.
*/
default void harvest(Player player, PartRayTraceResult hit) {
default void harvest(Player player, PartRayTraceResult hit, ItemStack harvestTool) {
if (!player.getAbilities().instabuild) {
tile().dropItems(getDrops());
tile().dropItems(getDrops(lootBuilderForPart(this, player, harvestTool)));
}
tile().remPart(this);
}
Expand All @@ -260,14 +266,15 @@ default void harvest(Player player, PartRayTraceResult hit) {
*
* @return The {@link ItemStack}s.
*/
default Iterable<ItemStack> getDrops() {
default Iterable<ItemStack> getDrops(LootParams.Builder builder) {
return List.of();
}

/**
* Return the {@link ItemStack} for pick-block(usually middle click) function.
*
* @param hit The {@link PartRayTraceResult} hit result.
* @param hit The {@link PartRayTraceResult} hit result.
* @param player The player getting the clone stack.
* @return The {@link ItemStack} pick result.
*/
default ItemStack getCloneStack(PartRayTraceResult hit, Player player) {
Expand Down Expand Up @@ -564,4 +571,50 @@ default Cuboid6 getRenderBounds() {
default ModelData getModelData() {
return ModelData.EMPTY;
}

/**
* Build a new {@link LootParams.Builder} for harvesting this part.
*
* @param part The part being harvested.
* @param destroyer The destroyer.
* @param tool The tool the destroyer is using.
* @return The builder.
*/
static LootParams.Builder lootBuilderForPart(MultiPart part, @Nullable Entity destroyer, ItemStack tool) {
return new LootParams.Builder(((ServerLevel) part.level()))
.withParameter(MultipartLootContextParams.MULTI_PART, part)
.withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(part.pos()))
.withParameter(LootContextParams.TOOL, tool)
.withOptionalParameter(LootContextParams.THIS_ENTITY, destroyer);
}

/**
* Clone and adapt the given {@link LootParams.Builder} from a Block context to a MultiPart context.
*
* @param forBlock The builder we are adapting.
* @param part The part we are doing this for.
* @return The new builder.
*/
static LootParams.Builder lootBuilderForPart(LootParams.Builder forBlock, MultiPart part) {
return lootBuilderForPart(forBlock.getLevel(), forBlock, part);
}

/**
* Clone and adapt the given {@link LootParams.Builder} from a Block context to a MultiPart context.
*
* @param level The level.
* @param forBlock The builder we are adapting.
* @param part The part we are doing this for.
* @return The new builder.
*/
static LootParams.Builder lootBuilderForPart(ServerLevel level, LootParams.Builder forBlock, MultiPart part) {
LootParams.Builder builder = new LootParams.Builder(level);
builder.params.putAll(forBlock.params);
builder.dynamicDrops.putAll(forBlock.dynamicDrops);
// Parts don't get these as context.
builder.params.remove(LootContextParams.BLOCK_STATE);
builder.params.remove(LootContextParams.BLOCK_ENTITY);
builder.withParameter(MultipartLootContextParams.MULTI_PART, part);
return builder;
}
}
21 changes: 17 additions & 4 deletions src/main/java/codechicken/multipart/block/BlockMultipart.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@
*/
public class BlockMultipart extends Block implements EntityBlock {

//TODO, Temporary workaround whilst onDestroyedByPlayer doesn't have hand context.
private static final ThreadLocal<ItemStack> MAIN_HAND_ON_DESTROY = ThreadLocal.withInitial(() -> ItemStack.EMPTY);

public BlockMultipart() {
super(Block.Properties.of()
.mapColor(MapColor.STONE)
Expand Down Expand Up @@ -180,6 +183,12 @@ public float getDestroyProgress(BlockState state, Player player, BlockGetter wor
return 1 / 100F;
}

@Override
public boolean canHarvestBlock(BlockState state, BlockGetter level, BlockPos pos, Player player) {
MAIN_HAND_ON_DESTROY.set(player.getMainHandItem().copy());
return super.canHarvestBlock(state, level, pos, player);
}

@Override
public boolean onDestroyedByPlayer(BlockState state, Level level, BlockPos pos, Player player, boolean willHarvest, FluidState fluid) {
TileMultipart tile = getTile(level, pos);
Expand All @@ -196,15 +205,19 @@ public boolean onDestroyedByPlayer(BlockState state, Level level, BlockPos pos,
return true;
}

tile.harvestPart(hit, player);
// TODO PR to NeoForge to add this a context to onDestroyedByPlayer.
ItemStack hand = MAIN_HAND_ON_DESTROY.get();
MAIN_HAND_ON_DESTROY.set(ItemStack.EMPTY);

tile.harvestPart(hit, player, hand);
return level.getBlockEntity(pos) == null;
}

@Override
public List<ItemStack> getDrops(BlockState state, LootParams.Builder builder) {
TileMultipart tile = getTile(builder.getParameter(LootContextParams.BLOCK_ENTITY));//TODO
TileMultipart tile = getTile(builder.getParameter(LootContextParams.BLOCK_ENTITY));
if (tile != null) {
return tile.getDrops();
return tile.getDrops(builder);
}

return Collections.emptyList();
Expand Down Expand Up @@ -356,7 +369,7 @@ public boolean addRunningEffects(BlockState state, Level level, BlockPos pos, En
public static void dropAndDestroy(Level world, BlockPos pos) {
TileMultipart tile = getTile(world, pos);
if (tile != null && !world.isClientSide) {
tile.dropItems(tile.getDrops());
tile.dropItems(tile.getDrops(TileMultipart.lootBuilderForTile(tile)));
}

world.removeBlock(pos, false);
Expand Down
25 changes: 16 additions & 9 deletions src/main/java/codechicken/multipart/block/TileMultipart.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.storage.loot.LootParams;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.CollisionContext;
Expand All @@ -58,8 +60,6 @@
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import static java.util.Objects.requireNonNull;
import static net.minecraft.world.level.block.Block.*;
Expand Down Expand Up @@ -404,15 +404,14 @@ public DoubleList getCoords(Direction.Axis axis) {
};
}

public void harvestPart(PartRayTraceResult hit, Player player) {
hit.part.harvest(player, hit);
public void harvestPart(PartRayTraceResult hit, Player player, ItemStack harvestTool) {
hit.part.harvest(player, hit, harvestTool);
}

public List<ItemStack> getDrops() {
return partList.stream()
.map(MultiPart::getDrops)
.flatMap(e -> StreamSupport.stream(e.spliterator(), false))
.collect(Collectors.toList());
public List<ItemStack> getDrops(LootParams.Builder builder) {
return FastStream.of(partList)
.flatMap(e -> e.getDrops(MultiPart.lootBuilderForPart(builder, e)))
.toList();
}

public ItemStack getCloneStack(PartRayTraceResult hit, Player player) {
Expand Down Expand Up @@ -745,6 +744,14 @@ public static TileMultipart fromNBT(CompoundTag tag, BlockPos pos, HolderLookup.
return tile;
}

public static LootParams.Builder lootBuilderForTile(TileMultipart tile) {
return new LootParams.Builder((ServerLevel) tile.getLevel())
.withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(tile.getBlockPos()))
.withParameter(LootContextParams.TOOL, ItemStack.EMPTY)
.withOptionalParameter(LootContextParams.BLOCK_STATE, tile.getBlockState())
.withOptionalParameter(LootContextParams.BLOCK_ENTITY, tile);
}

public static void dropItem(ItemStack stack, Level level, Vector3 pos) {
ItemEntity item = new ItemEntity(level, pos.x, pos.y, pos.z, stack);
item.setDeltaMovement(level.random.nextGaussian() * 0.05, level.random.nextGaussian() * 0.05 + 0.2, level.random.nextGaussian() * 0.05);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.storage.loot.LootParams;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.neoforged.api.distmarker.Dist;
Expand All @@ -44,12 +45,12 @@ public McStatePart(BlockState state) {
public abstract ItemStack getDropStack();

@Override
public Iterable<ItemStack> getDrops() {
public Iterable<ItemStack> getDrops(LootParams.Builder builder) {
return Collections.singletonList(getDropStack());
}

@Override
public ItemStack getCloneStack(PartRayTraceResult hit) {
public ItemStack getCloneStack(PartRayTraceResult hit, Player player) {
return getDropStack();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ public VoxelShape getOcclusionShape() {
@Nullable
@Override
public MultiPart setStateOnPlacement(BlockPlaceContext context) {

Level world = context.getLevel();
BlockPos pos = context.getClickedPos();
Direction face = context.getClickedFace();
Expand Down
Loading