Skip to content

Commit

Permalink
create canAdd check that supports list of parts
Browse files Browse the repository at this point in the history
  • Loading branch information
MrTJP committed Mar 3, 2024
1 parent 9962c5e commit 8def3c5
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 37 deletions.
22 changes: 16 additions & 6 deletions src/main/java/codechicken/multipart/api/ItemMultipart.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
import net.minecraft.world.level.block.SoundType;
import org.jetbrains.annotations.Nullable;

import java.util.Collections;
import java.util.List;

/**
* Created by covers1624 on 1/1/21.
*/
Expand All @@ -24,6 +27,10 @@ public ItemMultipart(Properties properties) {
@Nullable
public abstract MultiPart newPart(MultipartPlaceContext context);

protected List<MultiPart> newParts(MultipartPlaceContext context) {
return Collections.singletonList(newPart(context));
}

@Override
public InteractionResult useOn(UseOnContext context) {

Expand All @@ -39,18 +46,21 @@ private boolean place(MultipartPlaceContext context) {
Level world = context.getLevel();
BlockPos pos = context.getClickedPos();

MultiPart part = newPart(context);
if (part == null || !TileMultipart.canPlacePart(context, part)) return false;
List<MultiPart> parts = newParts(context);
if (parts.isEmpty() || !TileMultipart.canPlaceParts(context, parts)) return false;

if (!world.isClientSide) {
TileMultipart.addPart(world, pos, part);
SoundType sound = part.getPlacementSound(context);
if (sound != null) {
for (MultiPart part : parts) {
TileMultipart.addPart(world, pos, part);

SoundType sound = part.getPlacementSound(context);
if (sound == null) continue;

world.playSound(null, pos, sound.getPlaceSound(),
SoundSource.BLOCKS, (sound.getVolume() + 1.0F) / 2.0F, sound.getPitch() * 0.8F);
}
}
if (!context.getPlayer().getAbilities().instabuild) {
if (!context.getPlayer().isCreative()) {
context.getItemInHand().shrink(1);
}
return true;
Expand Down
38 changes: 29 additions & 9 deletions src/main/java/codechicken/multipart/block/TileMultipart.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import codechicken.multipart.network.MultiPartSPH;
import codechicken.multipart.util.*;
import com.google.common.base.Preconditions;
import net.covers1624.quack.collection.ColUtils;
import net.covers1624.quack.collection.FastStream;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
Expand Down Expand Up @@ -46,6 +45,7 @@

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
Expand Down Expand Up @@ -234,8 +234,15 @@ public void writeDesc(MCDataOutput packet) {

//region *** Adding/Removing parts ***

public boolean canAddPart(MultiPart part) {
return !partList.contains(part) && occlusionTest(partList, part);
public final boolean canAddPart(MultiPart part) {
return canAddParts(Collections.singletonList(part));
}

public boolean canAddParts(Iterable<MultiPart> parts) {
for (MultiPart part : parts) {
if (partList.contains(part)) return false;
}
return occlusionTest(partList, parts);
}

/**
Expand All @@ -251,11 +258,18 @@ public boolean canReplacePart(MultiPart oPart, MultiPart nPart) {
if (oPart != nPart && partList.contains(nPart)) {
return false;
}
return occlusionTest(FastStream.of(partList).filter(e -> e != oPart), nPart);
return occlusionTest(FastStream.of(partList).filter(e -> e != oPart), Collections.singletonList(nPart));
}

public boolean occlusionTest(Iterable<MultiPart> parts, MultiPart nPart) {
return ColUtils.allMatch(parts, part -> part.occlusionTest(nPart) && nPart.occlusionTest(part));
public boolean occlusionTest(Iterable<MultiPart> parts, Iterable<MultiPart> newParts) {
for (MultiPart oldPart : parts) {
for (MultiPart newPart : newParts) {
if (!oldPart.occlusionTest(newPart) || !newPart.occlusionTest(oldPart)) {
return false;
}
}
}
return true;
}

public void addPart_impl(MultiPart part) {
Expand Down Expand Up @@ -607,16 +621,22 @@ public CapabilityCache getCapCache() {
//endregion

public static boolean canPlacePart(UseOnContext context, MultiPart part) {
return canPlaceParts(context, Collections.singletonList(part));
}

public static boolean canPlaceParts(UseOnContext context, List<MultiPart> parts) {
Level level = context.getLevel();
BlockPos pos = context.getClickedPos();

if (!isUnobstructed(level, pos, part)) {
return false;
for (MultiPart p : parts) {
if (!isUnobstructed(level, pos, p)) {
return false;
}
}

TileMultipart tile = MultipartHelper.getOrConvertTile(level, pos);
if (tile != null) {
return tile.canAddPart(part);
return tile.canAddParts(parts);
}

if (!replaceable(level, pos, context)) return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@
import codechicken.multipart.api.part.MultiPart;
import codechicken.multipart.api.part.PartialOcclusionPart;
import codechicken.multipart.block.TileMultipart;
import net.covers1624.quack.collection.ColUtils;
import net.covers1624.quack.collection.FastStream;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.BooleanOp;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.jetbrains.annotations.Nullable;

import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
* Implementation for the partial occlusion test.
Expand All @@ -24,7 +26,7 @@ public class TPartialOcclusionTile extends TileMultipart {
@Nullable
private static TPartialOcclusionTile lastOcclusionTestedTile;
@Nullable
private static VoxelShape lastOcclusionTestedShape;
private static Set<VoxelShape> lastOcclusionTestedShape;
private static boolean lastOcclusionTestedResult;

public TPartialOcclusionTile(BlockPos pos, BlockState state) {
Expand All @@ -50,30 +52,31 @@ public void partRemoved(MultiPart remPart, int p) {
}

@Override
public boolean occlusionTest(Iterable<MultiPart> parts, MultiPart npart) {
if (npart instanceof PartialOcclusionPart newPart) {
VoxelShape newShape = newPart.getPartialOcclusionShape();
if (lastOcclusionTestedTile != this || lastOcclusionTestedShape != newShape) {
public boolean occlusionTest(Iterable<MultiPart> parts, Iterable<MultiPart> newParts) {

if (ColUtils.anyMatch(newParts, e -> e instanceof PartialOcclusionPart)) {
Set<VoxelShape> newPartialShapes = FastStream.of(newParts)
.filter(e -> e instanceof PartialOcclusionPart)
.map(e -> ((PartialOcclusionPart) e).getPartialOcclusionShape())
.toImmutableSet();
if (lastOcclusionTestedTile != this || newPartialShapes.equals(lastOcclusionTestedShape)) {
lastOcclusionTestedTile = this;
lastOcclusionTestedShape = newShape;
lastOcclusionTestedResult = partialOcclusionTest(parts, newPart);
lastOcclusionTestedShape = newPartialShapes;
lastOcclusionTestedResult = partialOcclusionTest(FastStream.concat(parts, newParts));
}
if (!lastOcclusionTestedResult) {
return false;
}
}

return super.occlusionTest(parts, npart);
}
return super.occlusionTest(parts, newParts); }

private static boolean partialOcclusionTest(Iterable<MultiPart> allParts, PartialOcclusionPart newPart) {
List<PartialOcclusionPart> parts = new LinkedList<>();
for (MultiPart part : allParts) {
if (part instanceof PartialOcclusionPart) {
parts.add((PartialOcclusionPart) part);
}
}
parts.add(newPart);
// Returns true if part list satisfies partial occlusion rules
private static boolean partialOcclusionTest(FastStream<MultiPart> allParts) {
List<PartialOcclusionPart> parts = allParts
.filter(e -> e instanceof PartialOcclusionPart)
.map(e -> ((PartialOcclusionPart) e))
.toList();

for (PartialOcclusionPart part1 : parts) {
if (part1.allowCompleteOcclusion()) {
Expand Down
10 changes: 6 additions & 4 deletions src/main/java/codechicken/multipart/trait/TSlottedTile.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,19 @@ public void partRemoved(MultiPart part, int p) {
}

@Override
public boolean canAddPart(MultiPart part) {
if (part instanceof SlottedPart) {
int mask = ((SlottedPart) part).getSlotMask();
public boolean canAddParts(Iterable<MultiPart> parts) {
for (var p : parts) {
if (!(p instanceof SlottedPart sp)) continue;

int mask = sp.getSlotMask();
for (int i = 0; i < v_partMap.length; i++) {
if ((mask & 1 << i) != 0 && getSlottedPart(i) != null) {
return false;
}
}
}

return super.canAddPart(part);
return super.canAddParts(parts);
}

@Override
Expand Down

0 comments on commit 8def3c5

Please sign in to comment.