Skip to content

Commit 9f6de67

Browse files
committed
Mark the inside of formed multiblocks as "dangerous" to prevent mobs like pets from teleporting inside #8085
1 parent 0351da9 commit 9f6de67

File tree

4 files changed

+82
-44
lines changed

4 files changed

+82
-44
lines changed

src/main/java/mekanism/common/block/attribute/Attributes.java

Lines changed: 18 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,18 @@
44
import java.util.function.ToIntBiFunction;
55
import mekanism.common.block.attribute.Attribute.TileAttribute;
66
import mekanism.common.block.states.BlockStateHelper;
7-
import mekanism.common.lib.multiblock.IInternalMultiblock;
8-
import mekanism.common.lib.multiblock.IMultiblock;
9-
import mekanism.common.lib.multiblock.IStructuralMultiblock;
10-
import mekanism.common.lib.multiblock.MultiblockData;
11-
import mekanism.common.lib.multiblock.Structure;
127
import mekanism.common.tile.base.TileEntityMekanism;
138
import mekanism.common.util.WorldUtils;
149
import net.minecraft.core.BlockPos;
1510
import net.minecraft.core.Direction;
1611
import net.minecraft.world.entity.EntityType;
17-
import net.minecraft.world.level.LevelReader;
18-
import net.minecraft.world.level.block.entity.BlockEntity;
12+
import net.minecraft.world.entity.Mob;
13+
import net.minecraft.world.level.BlockGetter;
1914
import net.minecraft.world.level.block.state.BlockBehaviour;
2015
import net.minecraft.world.level.block.state.BlockBehaviour.Properties;
2116
import net.minecraft.world.level.block.state.BlockBehaviour.StateArgumentPredicate;
17+
import net.minecraft.world.level.block.state.BlockState;
18+
import net.minecraft.world.level.pathfinder.PathType;
2219
import net.minecraft.world.level.storage.loot.functions.FunctionUserBuilder;
2320
import net.minecraft.world.level.storage.loot.predicates.ConditionUserBuilder;
2421
import org.jetbrains.annotations.NotNull;
@@ -100,41 +97,7 @@ public static class AttributeMobSpawn implements Attribute {
10097
public static final StateArgumentPredicate<EntityType<?>> NEVER_PREDICATE = (state, reader, pos, entityType) -> false;
10198
public static final AttributeMobSpawn NEVER = new AttributeMobSpawn(NEVER_PREDICATE);
10299
public static final AttributeMobSpawn WHEN_NOT_FORMED = new AttributeMobSpawn((state, reader, pos, entityType) -> {
103-
BlockEntity tile = WorldUtils.getTileEntity(reader, pos);
104-
if (tile instanceof IMultiblock<?> multiblockTile) {
105-
if (reader instanceof LevelReader levelReader && levelReader.isClientSide()) {
106-
//If we are on the client just check if we are formed as we don't sync structure information
107-
// to the client. This way the client is at least relatively accurate with what values
108-
// it returns for if mobs can spawn
109-
if (multiblockTile.getMultiblock().isFormed()) {
110-
return false;
111-
}
112-
} else if (multiblockTile.getMultiblock().isPositionInsideBounds(multiblockTile.getStructure(), pos.above())) {
113-
//If the multiblock is formed and the position above this block is inside the bounds of the multiblock
114-
// don't allow spawning on it.
115-
return false;
116-
}
117-
} else if (tile instanceof IStructuralMultiblock structuralMultiblock && structuralMultiblock.hasFormedMultiblock()) {
118-
//Note: This isn't actually used as all our structural multiblocks are transparent and vanilla tends to not let
119-
// mobs spawn on glass or stuff
120-
if (reader instanceof LevelReader levelReader && levelReader.isClientSide()) {
121-
//If we are on the client return we can't spawn if it is formed. This way the client is at least relatively
122-
// accurate with what values it returns for if mobs can spawn
123-
return false;
124-
} else {
125-
BlockPos above = pos.above();
126-
for (Structure structure : structuralMultiblock.getStructureMap().values()) {
127-
//Manually handle the getMultiblockData logic to avoid extra lookups
128-
MultiblockData data = structure.getMultiblockData();
129-
if (data != null && data.isFormed() && data.isPositionInsideBounds(structure, above)) {
130-
//If the multiblock is formed and the position above this block is inside the bounds of the multiblock
131-
// don't allow spawning on it.
132-
return false;
133-
}
134-
}
135-
}
136-
} else if (tile instanceof IInternalMultiblock internalMultiblock && internalMultiblock.hasFormedMultiblock()) {
137-
//If it is an internal multiblock don't allow spawning mobs on it if it is formed
100+
if (WorldUtils.isInsideFormedMultiblock(reader, pos, null)) {
138101
return false;
139102
}
140103
//Super implementation
@@ -153,6 +116,19 @@ public void adjustProperties(Properties props) {
153116
}
154117
}
155118

119+
@FunctionalInterface
120+
public interface PathCheck {
121+
122+
@Nullable
123+
PathType getBlockPathType(@NotNull BlockState state, @NotNull BlockGetter level, @NotNull BlockPos pos, @Nullable Mob mob);
124+
}
125+
126+
public record AttributeCustomPathType(Attributes.PathCheck pathCheck) implements Attribute {
127+
128+
public static final AttributeCustomPathType WHEN_NOT_FORMED = new AttributeCustomPathType((state, level, pos, mob) ->
129+
WorldUtils.isInsideFormedMultiblock(level, pos, mob) ? PathType.DAMAGE_OTHER : null);
130+
}
131+
156132
/** If a block can emit redstone. */
157133
public static class AttributeRedstoneEmitter<TILE extends TileEntityMekanism> implements TileAttribute<TILE> {
158134

src/main/java/mekanism/common/block/prefab/BlockBase.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import mekanism.common.block.attribute.Attribute;
99
import mekanism.common.block.attribute.AttributeCustomShape;
1010
import mekanism.common.block.attribute.AttributeStateFacing;
11+
import mekanism.common.block.attribute.Attributes.AttributeCustomPathType;
1112
import mekanism.common.block.attribute.Attributes.AttributeCustomResistance;
1213
import mekanism.common.block.interfaces.IColoredBlock;
1314
import mekanism.common.block.interfaces.IHasDescription;
@@ -20,6 +21,7 @@
2021
import net.minecraft.network.chat.MutableComponent;
2122
import net.minecraft.world.InteractionHand;
2223
import net.minecraft.world.ItemInteractionResult;
24+
import net.minecraft.world.entity.Mob;
2325
import net.minecraft.world.entity.player.Player;
2426
import net.minecraft.world.item.ItemStack;
2527
import net.minecraft.world.level.BlockGetter;
@@ -29,10 +31,12 @@
2931
import net.minecraft.world.level.block.state.BlockState;
3032
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
3133
import net.minecraft.world.level.pathfinder.PathComputationType;
34+
import net.minecraft.world.level.pathfinder.PathType;
3235
import net.minecraft.world.phys.BlockHitResult;
3336
import net.minecraft.world.phys.shapes.CollisionContext;
3437
import net.minecraft.world.phys.shapes.VoxelShape;
3538
import org.jetbrains.annotations.NotNull;
39+
import org.jetbrains.annotations.Nullable;
3640

3741
public class BlockBase<TYPE extends BlockType> extends BlockMekanism implements IHasDescription, ITypeBlock {
3842

@@ -95,6 +99,19 @@ protected boolean isPathfindable(@NotNull BlockState state, @NotNull PathComputa
9599
return !type.has(AttributeCustomShape.class) && super.isPathfindable(state, pathType);
96100
}
97101

102+
@Nullable
103+
@Override
104+
public PathType getBlockPathType(@NotNull BlockState state, @NotNull BlockGetter level, @NotNull BlockPos pos, @Nullable Mob mob) {
105+
AttributeCustomPathType customPathType = type.get(AttributeCustomPathType.class);
106+
if (customPathType != null) {
107+
PathType pathType = customPathType.pathCheck().getBlockPathType(state, level, pos, mob);
108+
if (pathType != null) {
109+
return pathType;
110+
}
111+
}
112+
return super.getBlockPathType(state, level, pos, mob);
113+
}
114+
98115
@NotNull
99116
@Override
100117
protected VoxelShape getShape(@NotNull BlockState state, @NotNull BlockGetter world, @NotNull BlockPos pos, @NotNull CollisionContext context) {

src/main/java/mekanism/common/content/blocktype/BlockType.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import mekanism.common.block.attribute.AttributeMultiblock;
1313
import mekanism.common.block.attribute.AttributeSideConfig;
1414
import mekanism.common.block.attribute.Attributes.AttributeComputerIntegration;
15+
import mekanism.common.block.attribute.Attributes.AttributeCustomPathType;
1516
import mekanism.common.block.attribute.Attributes.AttributeLight;
1617
import mekanism.common.block.attribute.Attributes.AttributeMobSpawn;
1718
import mekanism.common.block.interfaces.ITypeBlock;
@@ -145,11 +146,11 @@ public T withComputerSupport(ITier tier, String name) {
145146
}
146147

147148
public final T externalMultiblock() {
148-
return with(AttributeMultiblock.EXTERNAL, AttributeMobSpawn.WHEN_NOT_FORMED);
149+
return with(AttributeMultiblock.EXTERNAL, AttributeMobSpawn.WHEN_NOT_FORMED, AttributeCustomPathType.WHEN_NOT_FORMED);
149150
}
150151

151152
public final T internalMultiblock() {
152-
return with(AttributeMultiblock.INTERNAL, AttributeMobSpawn.WHEN_NOT_FORMED);
153+
return with(AttributeMultiblock.INTERNAL, AttributeMobSpawn.WHEN_NOT_FORMED, AttributeCustomPathType.WHEN_NOT_FORMED);
153154
}
154155

155156
public BLOCK build() {

src/main/java/mekanism/common/util/WorldUtils.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
import java.util.Collection;
55
import java.util.Optional;
66
import mekanism.common.Mekanism;
7+
import mekanism.common.lib.multiblock.IInternalMultiblock;
8+
import mekanism.common.lib.multiblock.IMultiblock;
9+
import mekanism.common.lib.multiblock.IStructuralMultiblock;
10+
import mekanism.common.lib.multiblock.MultiblockData;
11+
import mekanism.common.lib.multiblock.Structure;
712
import net.minecraft.core.BlockPos;
813
import net.minecraft.core.BlockPos.MutableBlockPos;
914
import net.minecraft.core.Direction;
@@ -15,6 +20,7 @@
1520
import net.minecraft.sounds.SoundSource;
1621
import net.minecraft.util.Mth;
1722
import net.minecraft.world.entity.Entity;
23+
import net.minecraft.world.entity.Mob;
1824
import net.minecraft.world.entity.player.Player;
1925
import net.minecraft.world.item.ItemStack;
2026
import net.minecraft.world.item.context.BlockPlaceContext;
@@ -445,6 +451,44 @@ public static Direction sideDifference(BlockPos pos, BlockPos other) {
445451
return null;
446452
}
447453

454+
//TODO: Come up with a better method name, this is used for checking if a mob can spawn inside or if it is dangerous for mobs to say teleport inside of
455+
public static boolean isInsideFormedMultiblock(BlockGetter reader, BlockPos pos, @Nullable Mob mob) {
456+
BlockEntity tile = WorldUtils.getTileEntity(reader, pos);
457+
if (tile instanceof IMultiblock<?> multiblockTile) {
458+
if (reader instanceof LevelReader levelReader && levelReader.isClientSide() || mob != null && mob.level().isClientSide()) {
459+
//If we are on the client just check if we are formed as we don't sync structure information
460+
// to the client. This way the client is at least relatively accurate with what values
461+
// it returns for if mobs can spawn
462+
return multiblockTile.getMultiblock().isFormed();
463+
}
464+
//If the multiblock is formed and the position above this block is inside the bounds of the multiblock
465+
// don't allow spawning on it.
466+
return multiblockTile.getMultiblock().isPositionInsideBounds(multiblockTile.getStructure(), pos.above());
467+
} else if (tile instanceof IStructuralMultiblock structuralMultiblock && structuralMultiblock.hasFormedMultiblock()) {
468+
//Note: This isn't actually used as all our structural multiblocks are transparent and vanilla tends to not let
469+
// mobs spawn on glass or stuff
470+
if (reader instanceof LevelReader levelReader && levelReader.isClientSide() || mob != null && mob.level().isClientSide()) {
471+
//If we are on the client return we can't spawn if it is formed. This way the client is at least relatively
472+
// accurate with what values it returns for if mobs can spawn
473+
return true;
474+
} else {
475+
BlockPos above = pos.above();
476+
for (Structure structure : structuralMultiblock.getStructureMap().values()) {
477+
//Manually handle the getMultiblockData logic to avoid extra lookups
478+
MultiblockData data = structure.getMultiblockData();
479+
if (data != null && data.isFormed() && data.isPositionInsideBounds(structure, above)) {
480+
//If the multiblock is formed and the position above this block is inside the bounds of the multiblock
481+
// don't allow spawning on it.
482+
return true;
483+
}
484+
}
485+
}
486+
return false;
487+
}
488+
//If it is an internal multiblock don't allow spawning mobs on it if it is formed
489+
return tile instanceof IInternalMultiblock internalMultiblock && internalMultiblock.hasFormedMultiblock();
490+
}
491+
448492
/**
449493
* Whether the provided chunk is being vibrated by a Seismic Vibrator.
450494
*

0 commit comments

Comments
 (0)