CreateMod/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorColumn.java
2023-05-24 07:59:45 -07:00

227 lines
5.8 KiB
Java

package com.simibubi.create.content.contraptions.elevator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Nullable;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.utility.BlockHelper;
import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.IntAttached;
import com.simibubi.create.foundation.utility.NBTHelper;
import com.simibubi.create.foundation.utility.WorldAttached;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.entity.BlockEntity;
public class ElevatorColumn {
public static WorldAttached<Map<ColumnCoords, ElevatorColumn>> LOADED_COLUMNS =
new WorldAttached<>($ -> new HashMap<>());
protected LevelAccessor level;
protected ColumnCoords coords;
protected List<Integer> contacts;
protected int targetedYLevel;
protected boolean isActive;
@Nullable
public static ElevatorColumn get(LevelAccessor level, ColumnCoords coords) {
return LOADED_COLUMNS.get(level)
.get(coords);
}
public static ElevatorColumn getOrCreate(LevelAccessor level, ColumnCoords coords) {
return LOADED_COLUMNS.get(level)
.computeIfAbsent(coords, c -> new ElevatorColumn(level, c));
}
public ElevatorColumn(LevelAccessor level, ColumnCoords coords) {
this.level = level;
this.coords = coords;
contacts = new ArrayList<>();
}
public void markDirty() {
for (BlockPos pos : getContacts()) {
BlockEntity blockEntity = level.getBlockEntity(pos);
if (blockEntity instanceof ElevatorContactBlockEntity ecbe)
ecbe.setChanged();
}
}
public void floorReached(LevelAccessor level, String name) {
getContacts().stream()
.forEach(p -> {
if (level.getBlockEntity(p) instanceof ElevatorContactBlockEntity ecbe)
ecbe.updateDisplayedFloor(name);
});
}
public int namesListVersion;
public List<IntAttached<Couple<String>>> compileNamesList() {
return getContacts().stream()
.map(p -> {
if (level.getBlockEntity(p) instanceof ElevatorContactBlockEntity ecbe)
return IntAttached.with(p.getY(), ecbe.getNames());
return null;
})
.filter(Objects::nonNull)
.toList();
}
public void namesChanged() {
namesListVersion++;
}
public Collection<BlockPos> getContacts() {
return contacts.stream()
.map(this::contactAt)
.toList();
}
public void gatherAll() {
BlockPos.betweenClosedStream(contactAt(level.getMinBuildHeight()), contactAt(level.getMaxBuildHeight()))
.filter(p -> coords.equals(ElevatorContactBlock.getColumnCoords(level, p)))
.forEach(p -> level.setBlock(p,
BlockHelper.copyProperties(level.getBlockState(p), AllBlocks.ELEVATOR_CONTACT.getDefaultState()), 3));
}
public BlockPos contactAt(int y) {
return new BlockPos(coords.x, y, coords.z);
}
public void setActive(boolean isActive) {
this.isActive = isActive;
markDirty();
checkEmpty();
}
public boolean isActive() {
return isActive;
}
public void target(int yLevel) {
targetedYLevel = yLevel;
}
public int getTargetedYLevel() {
return targetedYLevel;
}
public void initNames(Level level) {
Integer prevLevel = null;
for (int i = 0; i < contacts.size(); i++) {
Integer y = contacts.get(i);
BlockPos pos = contactAt(y);
if (!(level.getBlockEntity(pos) instanceof ElevatorContactBlockEntity ecbe))
continue;
Integer currentLevel = null;
if (!ecbe.shortName.isBlank()) {
Integer tryValueOf = tryValueOf(ecbe.shortName);
if (tryValueOf != null)
currentLevel = tryValueOf;
if (currentLevel == null)
continue;
}
if (prevLevel != null)
currentLevel = prevLevel + 1;
Integer nextLevel = null;
for (int peekI = i + 1; peekI < contacts.size(); peekI++) {
BlockPos peekPos = contactAt(contacts.get(peekI));
if (!(level.getBlockEntity(peekPos) instanceof ElevatorContactBlockEntity peekEcbe))
continue;
Integer tryValueOf = tryValueOf(peekEcbe.shortName);
if (tryValueOf == null)
continue;
if (currentLevel != null && currentLevel >= tryValueOf) {
peekEcbe.shortName = "";
break;
}
nextLevel = tryValueOf;
break;
}
if (currentLevel == null)
currentLevel = nextLevel != null ? nextLevel - 1 : 0;
ecbe.updateName(String.valueOf(currentLevel), ecbe.longName);
prevLevel = currentLevel;
}
}
private static Integer tryValueOf(String floorName) {
try {
return Integer.valueOf(floorName, 10);
} catch (NumberFormatException nfe) {
return null;
}
}
public void add(BlockPos contactPos) {
int coord = contactPos.getY();
if (contacts.contains(coord))
return;
int index = 0;
for (; index < contacts.size(); index++)
if (contacts.get(index) > coord)
break;
contacts.add(index, coord);
namesChanged();
}
public void remove(BlockPos contactPos) {
contacts.remove((Object) contactPos.getY());
checkEmpty();
namesChanged();
}
private void checkEmpty() {
if (contacts.isEmpty() && !isActive())
LOADED_COLUMNS.get(level)
.remove(coords);
}
public static record ColumnCoords(int x, int z, Direction side) {
public ColumnCoords relative(BlockPos anchor) {
return new ColumnCoords(x + anchor.getX(), z + anchor.getZ(), side);
}
public CompoundTag write() {
CompoundTag tag = new CompoundTag();
tag.putInt("X", x);
tag.putInt("Z", z);
NBTHelper.writeEnum(tag, "Side", side);
return tag;
}
public static ColumnCoords read(CompoundTag tag) {
int x = tag.getInt("X");
int z = tag.getInt("Z");
Direction side = NBTHelper.readEnum(tag, "Side", Direction.class);
return new ColumnCoords(x, z, side);
}
}
}