2025-11-24 22:52:51 +03:00

215 lines
7.8 KiB
Java

/*
* Decompiled with CFR 0.152.
*/
package net.minecraft.world.level.block;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.IntFunction;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.SideChainPart;
public interface SideChainPartBlock {
public SideChainPart getSideChainPart(BlockState var1);
public BlockState setSideChainPart(BlockState var1, SideChainPart var2);
public Direction getFacing(BlockState var1);
public boolean isConnectable(BlockState var1);
public int getMaxChainLength();
default public List<BlockPos> getAllBlocksConnectedTo(LevelAccessor level, BlockPos pos) {
BlockState state = level.getBlockState(pos);
if (!this.isConnectable(state)) {
return List.of();
}
Neighbors neighbors = this.getNeighbors(level, pos, this.getFacing(state));
LinkedList<BlockPos> results = new LinkedList<BlockPos>();
results.add(pos);
this.addBlocksConnectingTowards(neighbors::left, SideChainPart.LEFT, results::addFirst);
this.addBlocksConnectingTowards(neighbors::right, SideChainPart.RIGHT, results::addLast);
return results;
}
private void addBlocksConnectingTowards(IntFunction<Neighbor> getNeighbor, SideChainPart endPart, Consumer<BlockPos> accumulator) {
for (int steps = 1; steps < this.getMaxChainLength(); ++steps) {
Neighbor neighbor = getNeighbor.apply(steps);
if (neighbor.connectsTowards(endPart)) {
accumulator.accept(neighbor.pos());
}
if (neighbor.isUnconnectableOrChainEnd()) break;
}
}
default public void updateNeighborsAfterPoweringDown(LevelAccessor level, BlockPos pos, BlockState state) {
Neighbors neighbors = this.getNeighbors(level, pos, this.getFacing(state));
neighbors.left().disconnectFromRight();
neighbors.right().disconnectFromLeft();
}
default public void updateSelfAndNeighborsOnPoweringUp(LevelAccessor level, BlockPos pos, BlockState state, BlockState oldState) {
if (!this.isConnectable(state)) {
return;
}
if (this.isBeingUpdatedByNeighbor(state, oldState)) {
return;
}
Neighbors neighbors = this.getNeighbors(level, pos, this.getFacing(state));
SideChainPart newPartForSelf = SideChainPart.UNCONNECTED;
int existingChainOnTheLeft = neighbors.left().isConnectable() ? this.getAllBlocksConnectedTo(level, neighbors.left().pos()).size() : 0;
int existingChainOnTheRight = neighbors.right().isConnectable() ? this.getAllBlocksConnectedTo(level, neighbors.right().pos()).size() : 0;
int currentChainLength = 1;
if (this.canConnect(existingChainOnTheLeft, currentChainLength)) {
newPartForSelf = newPartForSelf.whenConnectedToTheLeft();
neighbors.left().connectToTheRight();
currentChainLength += existingChainOnTheLeft;
}
if (this.canConnect(existingChainOnTheRight, currentChainLength)) {
newPartForSelf = newPartForSelf.whenConnectedToTheRight();
neighbors.right().connectToTheLeft();
}
this.setPart(level, pos, newPartForSelf);
}
private boolean canConnect(int newBlocksToConnectTo, int currentChainLength) {
return newBlocksToConnectTo > 0 && currentChainLength + newBlocksToConnectTo <= this.getMaxChainLength();
}
private boolean isBeingUpdatedByNeighbor(BlockState state, BlockState oldState) {
boolean isGettingConnected = this.getSideChainPart(state).isConnected();
boolean hasBeenConnectedBefore = this.isConnectable(oldState) && this.getSideChainPart(oldState).isConnected();
return isGettingConnected || hasBeenConnectedBefore;
}
private Neighbors getNeighbors(LevelAccessor level, BlockPos center, Direction facing) {
return new Neighbors(this, level, facing, center, new HashMap<BlockPos, Neighbor>());
}
private void setPart(LevelAccessor level, BlockPos pos, SideChainPart newPart) {
BlockState state = level.getBlockState(pos);
if (this.getSideChainPart(state) != newPart) {
level.setBlock(pos, this.setSideChainPart(state, newPart), 3);
}
}
public record Neighbors(SideChainPartBlock block, LevelAccessor level, Direction facing, BlockPos center, Map<BlockPos, Neighbor> cache) {
private boolean isConnectableToThisBlock(BlockState neighbor) {
return this.block.isConnectable(neighbor) && this.block.getFacing(neighbor) == this.facing;
}
private Neighbor createNewNeighbor(BlockPos pos) {
BlockState neighbor = this.level.getBlockState(pos);
SideChainPart part = this.isConnectableToThisBlock(neighbor) ? this.block.getSideChainPart(neighbor) : null;
return part == null ? new EmptyNeighbor(pos) : new SideChainNeighbor(this.level, this.block, pos, part);
}
private Neighbor getOrCreateNeighbor(Direction dir, Integer steps) {
return this.cache.computeIfAbsent(this.center.relative(dir, (int)steps), this::createNewNeighbor);
}
public Neighbor left(int steps) {
return this.getOrCreateNeighbor(this.facing.getClockWise(), steps);
}
public Neighbor right(int steps) {
return this.getOrCreateNeighbor(this.facing.getCounterClockWise(), steps);
}
public Neighbor left() {
return this.left(1);
}
public Neighbor right() {
return this.right(1);
}
}
public static sealed interface Neighbor
permits EmptyNeighbor, SideChainNeighbor {
public BlockPos pos();
public boolean isConnectable();
public boolean isUnconnectableOrChainEnd();
public boolean connectsTowards(SideChainPart var1);
default public void connectToTheRight() {
}
default public void connectToTheLeft() {
}
default public void disconnectFromRight() {
}
default public void disconnectFromLeft() {
}
}
public record SideChainNeighbor(LevelAccessor level, SideChainPartBlock block, BlockPos pos, SideChainPart part) implements Neighbor
{
@Override
public boolean isConnectable() {
return true;
}
@Override
public boolean isUnconnectableOrChainEnd() {
return this.part.isChainEnd();
}
@Override
public boolean connectsTowards(SideChainPart endPart) {
return this.part.isConnectionTowards(endPart);
}
@Override
public void connectToTheRight() {
this.block.setPart(this.level, this.pos, this.part.whenConnectedToTheRight());
}
@Override
public void connectToTheLeft() {
this.block.setPart(this.level, this.pos, this.part.whenConnectedToTheLeft());
}
@Override
public void disconnectFromRight() {
this.block.setPart(this.level, this.pos, this.part.whenDisconnectedFromTheRight());
}
@Override
public void disconnectFromLeft() {
this.block.setPart(this.level, this.pos, this.part.whenDisconnectedFromTheLeft());
}
}
public record EmptyNeighbor(BlockPos pos) implements Neighbor
{
@Override
public boolean isConnectable() {
return false;
}
@Override
public boolean isUnconnectableOrChainEnd() {
return true;
}
@Override
public boolean connectsTowards(SideChainPart endPart) {
return false;
}
}
}