The Eternal Offset

- Fixed Drills not leaving water sources when breaking ice blocks
- Fixed Ploughs not able to break track blocks
- Fixed Harvester replanting crops in invalid locations
- Fixed Train Relocation not always triggering when targeting long bends
- Display boards no longer predict trains behind wait conditions other than "timed delay"
- Fixed scoreboard and deathcount display sources cropping entries before sorting
- /create dumpRailways -> /create trains
- Pipe flows are no longer stopped if the blocking state is considered #fan_transparent (-> fixes 1.19 mangrove root)
- Fixed contraption interaction not firing when it happens far away from the contraptions origin
- Fixed inaccurate contact point motion for collisions with oriented contraptions
This commit is contained in:
simibubi 2022-09-17 20:52:15 +02:00
parent aeee9f8793
commit bf06e59938
13 changed files with 137 additions and 73 deletions

View file

@ -3,23 +3,19 @@ package com.simibubi.create.content.contraptions.components.actors;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.foundation.utility.BlockHelper;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.NbtUtils;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundSource; import net.minecraft.sounds.SoundSource;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.GameRules; import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.block.AirBlock; import net.minecraft.world.level.block.AirBlock;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
public abstract class BlockBreakingKineticTileEntity extends KineticTileEntity { public abstract class BlockBreakingKineticTileEntity extends KineticTileEntity {
@ -40,7 +36,7 @@ public abstract class BlockBreakingKineticTileEntity extends KineticTileEntity {
if (destroyProgress == -1) if (destroyProgress == -1)
destroyNextTick(); destroyNextTick();
} }
@Override @Override
public void lazyTick() { public void lazyTick() {
super.lazyTick(); super.lazyTick();
@ -93,9 +89,9 @@ public abstract class BlockBreakingKineticTileEntity extends KineticTileEntity {
return; return;
if (getSpeed() == 0) if (getSpeed() == 0)
return; return;
breakingPos = getBreakingPos(); breakingPos = getBreakingPos();
if (ticksUntilNextProgress < 0) if (ticksUntilNextProgress < 0)
return; return;
if (ticksUntilNextProgress-- > 0) if (ticksUntilNextProgress-- > 0)
@ -114,7 +110,8 @@ public abstract class BlockBreakingKineticTileEntity extends KineticTileEntity {
float breakSpeed = getBreakSpeed(); float breakSpeed = getBreakSpeed();
destroyProgress += Mth.clamp((int) (breakSpeed / blockHardness), 1, 10 - destroyProgress); destroyProgress += Mth.clamp((int) (breakSpeed / blockHardness), 1, 10 - destroyProgress);
level.playSound(null, worldPosition, stateToBreak.getSoundType().getHitSound(), SoundSource.NEUTRAL, .25f, 1); level.playSound(null, worldPosition, stateToBreak.getSoundType()
.getHitSound(), SoundSource.NEUTRAL, .25f, 1);
if (destroyProgress >= 10) { if (destroyProgress >= 10) {
onBlockBroken(stateToBreak); onBlockBroken(stateToBreak);
@ -133,28 +130,26 @@ public abstract class BlockBreakingKineticTileEntity extends KineticTileEntity {
} }
public static boolean isBreakable(BlockState stateToBreak, float blockHardness) { public static boolean isBreakable(BlockState stateToBreak, float blockHardness) {
return !(stateToBreak.getMaterial().isLiquid() || stateToBreak.getBlock() instanceof AirBlock return !(stateToBreak.getMaterial()
|| blockHardness == -1); .isLiquid() || stateToBreak.getBlock() instanceof AirBlock || blockHardness == -1);
} }
public void onBlockBroken(BlockState stateToBreak) { public void onBlockBroken(BlockState stateToBreak) {
FluidState FluidState = level.getFluidState(breakingPos);
level.levelEvent(2001, breakingPos, Block.getId(stateToBreak));
BlockEntity tileentity = stateToBreak.hasBlockEntity() ? level.getBlockEntity(breakingPos) : null;
Vec3 vec = VecHelper.offsetRandomly(VecHelper.getCenterOf(breakingPos), level.random, .125f); Vec3 vec = VecHelper.offsetRandomly(VecHelper.getCenterOf(breakingPos), level.random, .125f);
BlockHelper.destroyBlock(level, breakingPos, 1f, (stack) -> {
Block.getDrops(stateToBreak, (ServerLevel) level, breakingPos, tileentity).forEach((stack) -> { if (stack.isEmpty())
if (!stack.isEmpty() && level.getGameRules().getBoolean(GameRules.RULE_DOBLOCKDROPS) return;
&& !level.restoringBlockSnapshots) { if (!level.getGameRules()
ItemEntity itementity = new ItemEntity(level, vec.x, vec.y, vec.z, stack); .getBoolean(GameRules.RULE_DOBLOCKDROPS))
itementity.setDefaultPickUpDelay(); return;
itementity.setDeltaMovement(Vec3.ZERO); if (level.restoringBlockSnapshots)
level.addFreshEntity(itementity); return;
}
ItemEntity itementity = new ItemEntity(level, vec.x, vec.y, vec.z, stack);
itementity.setDefaultPickUpDelay();
itementity.setDeltaMovement(Vec3.ZERO);
level.addFreshEntity(itementity);
}); });
if (level instanceof ServerLevel)
stateToBreak.spawnAfterBreak((ServerLevel) level, breakingPos, ItemStack.EMPTY);
level.setBlock(breakingPos, FluidState.createLegacyBlock(), 3);
} }
protected float getBreakSpeed() { protected float getBreakSpeed() {

View file

@ -104,7 +104,8 @@ public class HarvesterMovementBehaviour implements MovementBehaviour {
dropItem(context, stack); dropItem(context, stack);
}); });
world.setBlockAndUpdate(pos, cutCrop(world, pos, stateVisited)); BlockState cutCrop = cutCrop(world, pos, stateVisited);
world.setBlockAndUpdate(pos, cutCrop.canSurvive(world, pos) ? cutCrop : Blocks.AIR.defaultBlockState());
} }
public boolean isValidCrop(Level world, BlockPos pos, BlockState state) { public boolean isValidCrop(Level world, BlockPos pos, BlockState state) {

View file

@ -2,6 +2,7 @@ package com.simibubi.create.content.contraptions.components.actors;
import com.simibubi.create.content.contraptions.components.actors.PloughBlock.PloughFakePlayer; import com.simibubi.create.content.contraptions.components.actors.PloughBlock.PloughFakePlayer;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
import com.simibubi.create.content.logistics.trains.ITrackBlock;
import com.simibubi.create.content.logistics.trains.track.FakeTrackBlock; import com.simibubi.create.content.logistics.trains.track.FakeTrackBlock;
import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.advancement.AllAdvancements;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
@ -105,6 +106,8 @@ public class PloughMovementBehaviour extends BlockBreakingMovementBehaviour {
return false; return false;
if (state.getBlock() instanceof NetherPortalBlock) if (state.getBlock() instanceof NetherPortalBlock)
return false; return false;
if (state.getBlock() instanceof ITrackBlock)
return true;
if (state.getBlock() instanceof FakeTrackBlock) if (state.getBlock() instanceof FakeTrackBlock)
return false; return false;
return state.getCollisionShape(world, breakingPos) return state.getCollisionShape(world, breakingPos)

View file

@ -304,13 +304,13 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
localVec = localVec.subtract(rotationOffset); localVec = localVec.subtract(rotationOffset);
localVec = applyRotation(localVec, partialTicks); localVec = applyRotation(localVec, partialTicks);
localVec = localVec.add(rotationOffset) localVec = localVec.add(rotationOffset)
.add(getAnchorVec()); .add(getPrevAnchorVec());
return localVec; return localVec;
} }
public Vec3 toLocalVector(Vec3 globalVec, float partialTicks) { public Vec3 toLocalVector(Vec3 globalVec, float partialTicks) {
Vec3 rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO); Vec3 rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO);
globalVec = globalVec.subtract(getAnchorVec()) globalVec = globalVec.subtract(getPrevAnchorVec())
.subtract(rotationOffset); .subtract(rotationOffset);
globalVec = reverseRotation(globalVec, partialTicks); globalVec = reverseRotation(globalVec, partialTicks);
globalVec = globalVec.add(rotationOffset); globalVec = globalVec.add(rotationOffset);
@ -519,6 +519,10 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
public Vec3 getAnchorVec() { public Vec3 getAnchorVec() {
return position(); return position();
} }
public Vec3 getPrevAnchorVec() {
return getPrevPositionVec();
}
public float getYawOffset() { public float getYawOffset() {
return 0; return 0;
@ -792,9 +796,11 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
public Vec3 getContactPointMotion(Vec3 globalContactPoint) { public Vec3 getContactPointMotion(Vec3 globalContactPoint) {
if (prevPosInvalid) if (prevPosInvalid)
return Vec3.ZERO; return Vec3.ZERO;
Vec3 contactPoint = toGlobalVector(toLocalVector(globalContactPoint, 0), 1); Vec3 contactPoint = toGlobalVector(toLocalVector(globalContactPoint, 0), 1);
return contactPoint.subtract(globalContactPoint) Vec3 contraptionLocalMovement = contactPoint.subtract(globalContactPoint);
.add(position().subtract(getPrevPositionVec())); Vec3 contraptionAnchorMovement = position().subtract(getPrevPositionVec());
return contraptionLocalMovement.add(contraptionAnchorMovement);
} }
public boolean canCollideWith(Entity e) { public boolean canCollideWith(Entity e) {

View file

@ -1,6 +1,7 @@
package com.simibubi.create.content.contraptions.components.structureMovement; package com.simibubi.create.content.contraptions.components.structureMovement;
import java.util.List; import java.lang.ref.WeakReference;
import java.util.Collection;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -86,10 +87,19 @@ public class ContraptionHandlerClient {
Vec3 origin = rayInputs.getFirst(); Vec3 origin = rayInputs.getFirst();
Vec3 target = rayInputs.getSecond(); Vec3 target = rayInputs.getSecond();
AABB aabb = new AABB(origin, target).inflate(16); AABB aabb = new AABB(origin, target).inflate(16);
List<AbstractContraptionEntity> intersectingContraptions =
mc.level.getEntitiesOfClass(AbstractContraptionEntity.class, aabb);
for (AbstractContraptionEntity contraptionEntity : intersectingContraptions) { Collection<WeakReference<AbstractContraptionEntity>> contraptions =
ContraptionHandler.loadedContraptions.get(mc.level)
.values();
for (WeakReference<AbstractContraptionEntity> ref : contraptions) {
AbstractContraptionEntity contraptionEntity = ref.get();
if (contraptionEntity == null)
continue;
if (!contraptionEntity.getBoundingBox()
.intersects(aabb))
continue;
BlockHitResult rayTraceResult = rayTraceContraption(origin, target, contraptionEntity); BlockHitResult rayTraceResult = rayTraceContraption(origin, target, contraptionEntity);
if (rayTraceResult == null) if (rayTraceResult == null)
continue; continue;

View file

@ -493,7 +493,14 @@ public class OrientedContraptionEntity extends AbstractContraptionEntity {
@Override @Override
public Vec3 getAnchorVec() { public Vec3 getAnchorVec() {
return new Vec3(getX() - .5, getY(), getZ() - .5); Vec3 anchorVec = super.getAnchorVec();
return anchorVec.subtract(.5, 0, .5);
}
@Override
public Vec3 getPrevAnchorVec() {
Vec3 prevAnchorVec = super.getPrevAnchorVec();
return prevAnchorVec.subtract(.5, 0, .5);
} }
@Override @Override

View file

@ -11,6 +11,7 @@ import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.AABB;
import net.minecraftforge.common.ForgeMod; import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.network.NetworkEvent.Context; import net.minecraftforge.network.NetworkEvent.Context;
@ -54,7 +55,9 @@ public class ContraptionInteractionPacket extends SimplePacketBase {
if (!(entityByID instanceof AbstractContraptionEntity)) if (!(entityByID instanceof AbstractContraptionEntity))
return; return;
AbstractContraptionEntity contraptionEntity = (AbstractContraptionEntity) entityByID; AbstractContraptionEntity contraptionEntity = (AbstractContraptionEntity) entityByID;
double d = sender.getAttribute(ForgeMod.REACH_DISTANCE.get()).getValue() + 10; AABB bb = contraptionEntity.getBoundingBox();
double boundsExtra = Math.max(bb.getXsize(), bb.getYsize());
double d = sender.getAttribute(ForgeMod.REACH_DISTANCE.get()).getValue() + 10 + boundsExtra;
if (!sender.hasLineOfSight(entityByID)) if (!sender.hasLineOfSight(entityByID))
d -= 3; d -= 3;
d *= d; d *= d;

View file

@ -8,6 +8,7 @@ import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTags.AllBlockTags;
import com.simibubi.create.content.contraptions.fluids.PipeConnection.Flow; import com.simibubi.create.content.contraptions.fluids.PipeConnection.Flow;
import com.simibubi.create.content.contraptions.fluids.pipes.AxisPipeBlock; import com.simibubi.create.content.contraptions.fluids.pipes.AxisPipeBlock;
import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock; import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock;
@ -173,7 +174,8 @@ public class FluidPropagator {
return false; return false;
if (VanillaFluidTargets.shouldPipesConnectTo(connectedState)) if (VanillaFluidTargets.shouldPipesConnectTo(connectedState))
return true; return true;
if (BlockHelper.hasBlockSolidSide(connectedState, reader, connectedPos, side.getOpposite())) if (BlockHelper.hasBlockSolidSide(connectedState, reader, connectedPos, side.getOpposite())
&& !AllBlockTags.FAN_TRANSPARENT.matches(connectedState))
return false; return false;
if (hasFluidCapability(reader, connectedPos, side.getOpposite())) if (hasFluidCapability(reader, connectedPos, side.getOpposite()))
return false; return false;

View file

@ -40,9 +40,10 @@ public class ScoreboardDisplaySource extends ValueListDisplaySource {
return sLevel.getScoreboard() return sLevel.getScoreboard()
.getPlayerScores(objective) .getPlayerScores(objective)
.stream() .stream()
.limit(maxRows) .map(score -> IntAttached.with(score.getScore(), Components.literal(score.getOwner())
.map(score -> IntAttached.with(score.getScore(), Components.literal(score.getOwner()).copy())) .copy()))
.sorted(IntAttached.comparator()); .sorted(IntAttached.comparator())
.limit(maxRows);
} }
private ImmutableList<IntAttached<MutableComponent>> notFound(String objective) { private ImmutableList<IntAttached<MutableComponent>> notFound(String objective) {

View file

@ -84,12 +84,12 @@ public class TrainRelocationPacket extends SimplePacketBase {
return; return;
if (!sender.position() if (!sender.position()
.closerThan(Vec3.atCenterOf(pos), 26)) { .closerThan(Vec3.atCenterOf(pos), 64)) {
Create.LOGGER.warn(messagePrefix + train.name.getString() + ": player too far from clicked pos"); Create.LOGGER.warn(messagePrefix + train.name.getString() + ": player too far from clicked pos");
return; return;
} }
if (!sender.position() if (!sender.position()
.closerThan(cce.position(), 26 + cce.getBoundingBox() .closerThan(cce.position(), 64 + cce.getBoundingBox()
.getXsize() / 2)) { .getXsize() / 2)) {
Create.LOGGER.warn(messagePrefix + train.name.getString() + ": player too far from carriage entity"); Create.LOGGER.warn(messagePrefix + train.name.getString() + ": player too far from carriage entity");
return; return;

View file

@ -29,6 +29,9 @@ import net.minecraft.world.level.Level;
public class ScheduleRuntime { public class ScheduleRuntime {
private static final int TBD = -1;
private static final int INVALID = -2;
public enum State { public enum State {
PRE_TRANSIT, IN_TRANSIT, POST_TRANSIT PRE_TRANSIT, IN_TRANSIT, POST_TRANSIT
} }
@ -129,7 +132,7 @@ public class ScheduleRuntime {
destinationReached(); destinationReached();
return; return;
} }
if (train.navigation.startNavigation(nextStation, Double.MAX_VALUE, false) != -1) { if (train.navigation.startNavigation(nextStation, Double.MAX_VALUE, false) != TBD) {
state = State.IN_TRANSIT; state = State.IN_TRANSIT;
ticksInTransit = 0; ticksInTransit = 0;
} }
@ -231,7 +234,7 @@ public class ScheduleRuntime {
isAutoSchedule = auto; isAutoSchedule = auto;
train.status.newSchedule(); train.status.newSchedule();
predictionTicks = new ArrayList<>(); predictionTicks = new ArrayList<>();
schedule.entries.forEach($ -> predictionTicks.add(-1)); schedule.entries.forEach($ -> predictionTicks.add(TBD));
displayLinkUpdateRequested = true; displayLinkUpdateRequested = true;
} }
@ -269,8 +272,10 @@ public class ScheduleRuntime {
if (currentStation != null) if (currentStation != null)
predictions.add(createPrediction(current, currentStation.name, currentTitle, 0)); predictions.add(createPrediction(current, currentStation.name, currentTitle, 0));
int departureTime = estimateStayDuration(current); int departureTime = estimateStayDuration(current);
if (departureTime == -1) if (departureTime == INVALID)
accumulatedTime = -1; accumulatedTime = INVALID;
else
accumulatedTime += departureTime;
} else { } else {
GlobalStation destination = train.navigation.destination; GlobalStation destination = train.navigation.destination;
@ -292,10 +297,10 @@ public class ScheduleRuntime {
predictions.add(createPrediction(current, destination.name, currentTitle, accumulatedTime)); predictions.add(createPrediction(current, destination.name, currentTitle, accumulatedTime));
int departureTime = estimateStayDuration(current); int departureTime = estimateStayDuration(current);
if (departureTime != -1) if (departureTime != INVALID)
accumulatedTime += departureTime; accumulatedTime += departureTime;
if (departureTime == -1) else
accumulatedTime = -1; accumulatedTime = INVALID;
} else } else
predictForEntry(current, currentTitle, accumulatedTime, predictions); predictForEntry(current, currentTitle, accumulatedTime, predictions);
@ -327,47 +332,56 @@ public class ScheduleRuntime {
return accumulatedTime; return accumulatedTime;
if (predictionTicks.size() <= currentEntry) if (predictionTicks.size() <= currentEntry)
return accumulatedTime; return accumulatedTime;
if (accumulatedTime == -1) {
int departureTime = estimateStayDuration(index);
if (accumulatedTime < 0) {
predictions.add(createPrediction(index, filter.getFilter(), currentTitle, accumulatedTime)); predictions.add(createPrediction(index, filter.getFilter(), currentTitle, accumulatedTime));
return -1; return Math.min(accumulatedTime, departureTime);
} }
int predictedTime = predictionTicks.get(index); int predictedTime = predictionTicks.get(index);
int departureTime = estimateStayDuration(index); accumulatedTime += predictedTime;
if (predictedTime == -1) if (predictedTime == TBD)
accumulatedTime = -1; accumulatedTime = TBD;
else {
accumulatedTime += predictedTime;
if (departureTime != -1)
accumulatedTime += departureTime;
}
predictions.add(createPrediction(index, filter.getFilter(), currentTitle, accumulatedTime)); predictions.add(createPrediction(index, filter.getFilter(), currentTitle, accumulatedTime));
if (departureTime == -1) if (accumulatedTime != TBD)
return -1; accumulatedTime += departureTime;
if (departureTime == INVALID)
accumulatedTime = INVALID;
return accumulatedTime; return accumulatedTime;
} }
private int estimateStayDuration(int index) { private int estimateStayDuration(int index) {
if (index >= schedule.entries.size()) { if (index >= schedule.entries.size()) {
if (!schedule.cyclic) if (!schedule.cyclic)
return 100000; return INVALID;
index = 0; index = 0;
} }
ScheduleEntry scheduleEntry = schedule.entries.get(index); ScheduleEntry scheduleEntry = schedule.entries.get(index);
for (List<ScheduleWaitCondition> list : scheduleEntry.conditions) Columns: for (List<ScheduleWaitCondition> list : scheduleEntry.conditions) {
for (ScheduleWaitCondition condition : list) int total = 0;
if (condition instanceof ScheduledDelay wait) for (ScheduleWaitCondition condition : list) {
return wait.totalWaitTicks(); if (!(condition instanceof ScheduledDelay wait))
continue Columns;
total += wait.totalWaitTicks();
}
return total;
}
return 5; // TODO properly ask conditions for time prediction return INVALID;
} }
private TrainDeparturePrediction createPrediction(int index, String destination, String currentTitle, int time) { private TrainDeparturePrediction createPrediction(int index, String destination, String currentTitle, int time) {
if (time == INVALID)
return null;
int size = schedule.entries.size(); int size = schedule.entries.size();
if (index >= size) { if (index >= size) {
if (!schedule.cyclic) if (!schedule.cyclic)
@ -422,7 +436,7 @@ public class ScheduleRuntime {
int[] readTransits = tag.getIntArray("TransitTimes"); int[] readTransits = tag.getIntArray("TransitTimes");
if (schedule != null) { if (schedule != null) {
schedule.entries.forEach($ -> predictionTicks.add(-1)); schedule.entries.forEach($ -> predictionTicks.add(TBD));
if (readTransits.length == schedule.entries.size()) if (readTransits.length == schedule.entries.size())
for (int i = 0; i < readTransits.length; i++) for (int i = 0; i < readTransits.length; i++)
predictionTicks.set(i, readTransits[i]); predictionTicks.set(i, readTransits[i]);

View file

@ -31,7 +31,7 @@ import net.minecraft.world.phys.Vec3;
public class DumpRailwaysCommand { public class DumpRailwaysCommand {
static ArgumentBuilder<CommandSourceStack, ?> register() { static ArgumentBuilder<CommandSourceStack, ?> register() {
return Commands.literal("dumpRailways") return Commands.literal("trains")
.requires(cs -> cs.hasPermission(2)) .requires(cs -> cs.hasPermission(2))
.executes(ctx -> { .executes(ctx -> {
CommandSourceStack source = ctx.getSource(); CommandSourceStack source = ctx.getSource();
@ -52,7 +52,7 @@ public class DumpRailwaysCommand {
int orange = 0xFFAD60; int orange = 0xFFAD60;
chat.accept("", white); chat.accept("", white);
chat.accept("-+------<< Railways Summary: >>------+-", white); chat.accept("-+------<< Train Summary: >>------+-", white);
int graphCount = railways.trackNetworks.size(); int graphCount = railways.trackNetworks.size();
chat.accept("Track Networks: " + graphCount, blue); chat.accept("Track Networks: " + graphCount, blue);
chat.accept("Signal Groups: " + railways.signalEdgeGroups.size(), blue); chat.accept("Signal Groups: " + railways.signalEdgeGroups.size(), blue);

View file

@ -24,6 +24,8 @@ import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items; import net.minecraft.world.item.Items;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.item.enchantment.Enchantments;
import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.GameRules; import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
@ -31,6 +33,7 @@ import net.minecraft.world.level.block.BaseRailBlock;
import net.minecraft.world.level.block.BedBlock; import net.minecraft.world.level.block.BedBlock;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.IceBlock;
import net.minecraft.world.level.block.SlimeBlock; import net.minecraft.world.level.block.SlimeBlock;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
@ -40,6 +43,7 @@ import net.minecraft.world.level.block.state.properties.SlabType;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Material;
import net.minecraftforge.common.IPlantable; import net.minecraftforge.common.IPlantable;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.world.BlockEvent; import net.minecraftforge.event.world.BlockEvent;
@ -155,9 +159,11 @@ public class BlockHelper {
float effectChance, Consumer<ItemStack> droppedItemCallback) { float effectChance, Consumer<ItemStack> droppedItemCallback) {
FluidState fluidState = world.getFluidState(pos); FluidState fluidState = world.getFluidState(pos);
BlockState state = world.getBlockState(pos); BlockState state = world.getBlockState(pos);
if (world.random.nextFloat() < effectChance) if (world.random.nextFloat() < effectChance)
world.levelEvent(2001, pos, Block.getId(state)); world.levelEvent(2001, pos, Block.getId(state));
BlockEntity tileentity = state.hasBlockEntity() ? world.getBlockEntity(pos) : null; BlockEntity tileentity = state.hasBlockEntity() ? world.getBlockEntity(pos) : null;
if (player != null) { if (player != null) {
BlockEvent.BreakEvent event = new BlockEvent.BreakEvent(world, pos, state, player); BlockEvent.BreakEvent event = new BlockEvent.BreakEvent(world, pos, state, player);
MinecraftForge.EVENT_BUS.post(event); MinecraftForge.EVENT_BUS.post(event);
@ -177,9 +183,25 @@ public class BlockHelper {
&& (player == null || !player.isCreative())) { && (player == null || !player.isCreative())) {
for (ItemStack itemStack : Block.getDrops(state, (ServerLevel) world, pos, tileentity, player, usedTool)) for (ItemStack itemStack : Block.getDrops(state, (ServerLevel) world, pos, tileentity, player, usedTool))
droppedItemCallback.accept(itemStack); droppedItemCallback.accept(itemStack);
// Simulating IceBlock#playerDestroy. Not calling method directly as it would drop item
// entities as a side-effect
if (state.getBlock() instanceof IceBlock
&& EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, usedTool) == 0) {
if (world.dimensionType()
.ultraWarm())
return;
Material material = world.getBlockState(pos.below())
.getMaterial();
if (material.blocksMotion() || material.isLiquid())
world.setBlockAndUpdate(pos, Blocks.WATER.defaultBlockState());
return;
}
state.spawnAfterBreak((ServerLevel) world, pos, ItemStack.EMPTY); state.spawnAfterBreak((ServerLevel) world, pos, ItemStack.EMPTY);
} }
world.setBlockAndUpdate(pos, fluidState.createLegacyBlock()); world.setBlockAndUpdate(pos, fluidState.createLegacyBlock());
} }