Genericify grid

This commit is contained in:
DBotThePony 2021-09-15 18:38:26 +07:00
parent 44bb2c6c93
commit f8e0443b84
Signed by: DBot
GPG Key ID: DCC23B5715498507
14 changed files with 240 additions and 249 deletions

View File

@ -0,0 +1,152 @@
package ru.dbotthepony.mc.otm;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.SectionPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import ru.dbotthepony.mc.otm.capability.IStorageGridCell;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.storage.StorageGrid;
import javax.annotation.ParametersAreNonnullByDefault;
import java.security.Provider;
import java.util.HashSet;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
abstract public class AbstractGrid<T> {
protected final HashSet<T> cells = new HashSet<>();
public final Capability<T> capability;
protected AbstractGrid(Capability<T> capability) {
this.capability = capability;
}
public int size() {
return cells.size();
}
abstract protected void onAdded(T cell);
abstract protected void onRemoved(T cell);
public boolean add(LazyOptional<T> cell) {
if (!cell.isPresent())
return false;
var resolved = cell.resolve();
if (resolved.isPresent()) {
final var value = resolved.get();
if (add(value)) {
cell.addListener((lazy) -> remove(value));
return true;
}
}
return false;
}
public boolean add(T cell) {
if (cells.add(cell)) {
onAdded(cell);
return true;
}
return false;
}
public boolean remove(T cell) {
if (cells.remove(cell)) {
onRemoved(cell);
return true;
}
return false;
}
public void merge(AbstractGrid<T> other) {
if (other == this)
return;
if (size() < other.size()) {
var copy = List.copyOf(cells);
for (var cell : copy) {
remove(cell);
other.add(cell);
}
} else {
var copy = List.copyOf(other.cells);
for (var cell : copy) {
other.remove(cell);
add(cell);
}
}
}
public interface OnNeighbourFunction<T> {
void apply(Level level, BlockPos pos, Direction dir, T other, BlockEntity ent);
}
public static <T> boolean createOrConnectGrid(
T self,
Capability<T> capability,
Level level,
BlockPos pos,
boolean force,
Supplier<AbstractGrid<T>> factory,
Function<T, AbstractGrid<T>> getter,
OnNeighbourFunction<T> neighbour
) {
if (getter.apply(self) != null && !force)
return true;
boolean full_discovery = true;
for (Direction direction : Direction.values()) {
BlockPos offset = pos.offset(direction.getNormal());
// level.getBlockEntity can drink big cup of deadlocks
LevelChunk get_chunk = level.getChunkSource().getChunkNow(SectionPos.blockToSectionCoord(offset.getX()), SectionPos.blockToSectionCoord(offset.getZ()));
if (get_chunk == null) {
full_discovery = false;
continue;
}
BlockEntity get_entity = get_chunk.getBlockEntity(offset);
if (get_entity != null && get_entity.getCapability(capability, direction.getOpposite()).isPresent()) {
final var cell = get_entity.getCapability(capability, direction.getOpposite()).resolve().get();
final var grid = getter.apply(cell);
if (grid != null && grid != getter.apply(self)) {
if (getter.apply(self) == null) {
grid.add(self);
} else {
grid.merge(getter.apply(self));
}
}
neighbour.apply(level, pos, direction, cell, get_entity);
}
}
if (getter.apply(self) == null) {
factory.get().add(self);
}
return full_discovery;
}
}

View File

@ -201,6 +201,7 @@ public class BlockMatterCable extends Block implements EntityBlock {
// blocks
@Override
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState self, Level level, BlockPos position_self, Block block_notifier, BlockPos position_notifier, boolean unknown_flag) {
Direction normal = Direction.fromNormal(position_notifier.subtract(position_self));
boolean updated = false;

View File

@ -17,7 +17,6 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState;
import ru.dbotthepony.mc.otm.capability.*;
@ -131,7 +130,7 @@ public class BlockEntityMatterBottler extends BlockEntityMatteryPowered implemen
super.setLevel(p_155231_);
if (grid == null)
scheduleDiscoverNeighbours(getBlockPos(), p_155231_);
scheduleDiscoverNeighbours(p_155231_, getBlockPos());
}
private boolean valid = true;

View File

@ -72,8 +72,7 @@ public class BlockEntityMatterCable extends BlockEntity implements IMatterGridCe
}
@Override
public void onNeighbourMatterCell(BlockPos pos, Level level, Direction direction, IMatterGridCell cell) {
// OverdriveThatMatters.LOGGER.debug("Try to connect cable entity {} {} to {} {} ({})", this, pos, pos.offset(direction.getNormal()), direction, cell);
public void onNeighbourMatterCell(Level level, BlockPos pos, Direction direction, IMatterGridCell cell, BlockEntity entity) {
BlockState new_state = getBlockState().setValue(BlockMatterCable.MAPPING_CONNECTION_PROP[direction.ordinal()], true);
if (new_state != getBlockState())
@ -85,7 +84,7 @@ public class BlockEntityMatterCable extends BlockEntity implements IMatterGridCe
super.setRemoved();
if (grid != null)
grid.untrack(this);
grid.remove(this);
}
@Nullable

View File

@ -243,7 +243,7 @@ public class BlockEntityMatterCapacitorBank extends BlockEntityMattery implement
super.setRemoved();
if (grid != null)
grid.untrack(this);
grid.remove(this);
}
@Override

View File

@ -176,10 +176,10 @@ public class BlockEntityMatterDecomposer extends BlockEntityMatteryWorker implem
@Override
public void setRemoved() {
if (level != null && !level.isClientSide && grid != null)
grid.untrack(this);
super.setRemoved();
if (level != null && !level.isClientSide && grid != null)
grid.remove(this);
}
@Override

View File

@ -91,15 +91,15 @@ public class BlockEntityMatterPanel extends BlockEntityMattery implements IMatte
super.setLevel(p_155231_);
if (grid == null)
scheduleDiscoverNeighbours(getBlockPos(), p_155231_);
scheduleDiscoverNeighbours(p_155231_, getBlockPos());
}
@Override
public void setRemoved() {
if (level != null && !level.isClientSide && grid != null)
grid.untrack(this);
super.setRemoved();
if (level != null && !level.isClientSide && grid != null)
grid.remove(this);
}
@Nullable

View File

@ -103,10 +103,10 @@ public class BlockEntityMatterReplicator extends BlockEntityMatteryWorker implem
@Override
public void setRemoved() {
if (level != null && !level.isClientSide && grid != null)
grid.untrack(this);
super.setRemoved();
if (level != null && !level.isClientSide && grid != null)
grid.remove(this);
}
private static final double TICKS_PER_MTU = 20_000d;
@ -119,7 +119,7 @@ public class BlockEntityMatterReplicator extends BlockEntityMatteryWorker implem
super.setLevel(p_155231_);
if (grid == null)
scheduleDiscoverNeighbours(getBlockPos(), p_155231_);
scheduleDiscoverNeighbours(p_155231_, getBlockPos());
}
@Nullable

View File

@ -11,11 +11,11 @@ import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import ru.dbotthepony.mc.otm.block.entity.worker.BlockEntityMatteryWorker;
import ru.dbotthepony.mc.otm.block.entity.worker.MachineJob;
import ru.dbotthepony.mc.otm.block.entity.worker.MachineJobStatus;
@ -103,14 +103,14 @@ public class BlockEntityMatterScanner extends BlockEntityMatteryWorker implement
@Override
public void setRemoved() {
if (level != null && !level.isClientSide && grid != null)
grid.untrack(this);
super.setRemoved();
if (level != null && !level.isClientSide && grid != null)
grid.remove(this);
}
@Override
public void onNeighbourMatterCell(BlockPos pos, Level level, Direction direction, IMatterGridCell cell) {
public void onNeighbourMatterCell(Level level, BlockPos pos, Direction direction, IMatterGridCell cell, BlockEntity entity) {
is_idling = false;
}
@ -239,7 +239,7 @@ public class BlockEntityMatterScanner extends BlockEntityMatteryWorker implement
super.setLevel(p_155231_);
if (grid == null)
scheduleDiscoverNeighbours(getBlockPos(), p_155231_);
scheduleDiscoverNeighbours(p_155231_, getBlockPos());
}
@Nullable

View File

@ -210,10 +210,10 @@ public class BlockEntityPatternStorage extends BlockEntityMattery implements IMa
@Override
public void setRemoved() {
if (level != null && !level.isClientSide && grid != null)
grid.untrack(this);
super.setRemoved();
if (level != null && !level.isClientSide && grid != null)
grid.remove(this);
}
@Override

View File

@ -16,6 +16,8 @@ import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.List;
import static ru.dbotthepony.mc.otm.AbstractGrid.createOrConnectGrid;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public interface IStorageGridCell {
@ -76,50 +78,20 @@ public interface IStorageGridCell {
return connectOrCreateStorageGrid(level, pos, false);
}
default void onNeighbourStorageCell(Level level, BlockPos pos, Direction direction, IStorageGridCell cell) {
default void onNeighbourStorageCell(Level level, BlockPos pos, Direction direction, IStorageGridCell cell, BlockEntity entity) {
}
default boolean connectOrCreateStorageGrid(Level level, BlockPos pos, boolean force) {
if (getStorageGrid() != null && !force)
return true;
boolean full_discovery = true;
for (Direction direction : Direction.values()) {
BlockPos offset = pos.offset(direction.getNormal());
// level.getBlockEntity can drink big cup of deadlocks
LevelChunk get_chunk = level.getChunkSource().getChunkNow(SectionPos.blockToSectionCoord(offset.getX()), SectionPos.blockToSectionCoord(offset.getZ()));
if (get_chunk == null) {
full_discovery = false;
continue;
}
BlockEntity get_entity = get_chunk.getBlockEntity(offset);
if (get_entity != null && get_entity.getCapability(MatteryCapability.STORAGE_CELL, direction.getOpposite()).isPresent()) {
var cell = get_entity.getCapability(MatteryCapability.STORAGE_CELL, direction.getOpposite()).resolve().get();
var grid = cell.getStorageGrid();
if (grid != null && grid != getStorageGrid()) {
if (getStorageGrid() == null) {
grid.add(this);
} else {
grid.merge(getStorageGrid());
}
}
if (cell.isValidStorageCell())
onNeighbourStorageCell(level, pos, direction, cell);
}
}
if (getStorageGrid() == null) {
new StorageGrid().add(this);
}
return full_discovery;
return createOrConnectGrid(
this,
MatteryCapability.STORAGE_CELL,
level,
pos,
force,
StorageGrid::new,
IStorageGridCell::getStorageGrid,
this::onNeighbourStorageCell
);
}
}

View File

@ -3,16 +3,16 @@ package ru.dbotthepony.mc.otm.capability.matter;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.SectionPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.matter.MatterGrid;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import static ru.dbotthepony.mc.otm.AbstractGrid.createOrConnectGrid;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public interface IMatterGridCell extends IMatterGridListener {
@ -36,65 +36,30 @@ public interface IMatterGridCell extends IMatterGridListener {
boolean isValidMatterCell();
void setMatterGrid(MatterGrid grid);
void setMatterGrid(@Nullable MatterGrid grid);
default void scheduleDiscoverNeighbours(BlockPos pos, Level level) {
default void scheduleDiscoverNeighbours(Level level, BlockPos pos) {
MatterGrid.scheduleDiscoverNeighbours(this, pos, level);
}
default boolean connectOrCreateMatterGrid(BlockPos pos, Level level) {
default boolean connectOrCreateMatterGrid(Level level, BlockPos pos) {
return connectOrCreateMatterGrid(pos, level, false);
}
default void onNeighbourMatterCell(BlockPos pos, Level level, Direction direction, IMatterGridCell cell) {
default void onNeighbourMatterCell(Level level, BlockPos pos, Direction direction, IMatterGridCell cell, BlockEntity entity) {
}
default boolean connectOrCreateMatterGrid(BlockPos pos, Level level, boolean force) {
if (getMatterGrid() != null && !force)
return true;
boolean full_discovery = true;
for (Direction direction : Direction.values()) {
BlockPos offset = pos.offset(direction.getNormal());
// level.getBlockEntity can suck big cuks of deadlocks
LevelChunk get_chunk = level.getChunkSource().getChunkNow(SectionPos.blockToSectionCoord(offset.getX()), SectionPos.blockToSectionCoord(offset.getZ()));
if (get_chunk == null) {
full_discovery = false;
continue;
}
BlockEntity get_entity = get_chunk.getBlockEntity(offset);
if (get_entity != null) {
final var cap = get_entity.getCapability(MatteryCapability.MATTER_CELL).resolve();
if (cap.isPresent()) {
final var cell = cap.get();
MatterGrid grid = cell.getMatterGrid();
if (grid != null && grid != getMatterGrid()) {
if (getMatterGrid() == null) {
grid.track(this);
} else {
grid.mergeWith(getMatterGrid());
}
}
if (cell.isValidMatterCell())
onNeighbourMatterCell(pos, level, direction, cell);
}
}
}
if (getMatterGrid() == null) {
new MatterGrid().track(this);
}
return full_discovery;
return createOrConnectGrid(
this,
MatteryCapability.MATTER_CELL,
level,
pos,
force,
MatterGrid::new,
IMatterGridCell::getMatterGrid,
this::onNeighbourMatterCell
);
}
}

View File

@ -6,7 +6,9 @@ import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.Level;
import ru.dbotthepony.mc.otm.AbstractGrid;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.capability.matter.*;
import javax.annotation.Nullable;
@ -17,10 +19,7 @@ import java.util.function.Predicate;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public class MatterGrid implements IMatterGridListener {
public static final Set<MatterGrid> NETWORKS = new HashSet<>();
private final Set<IMatterGridCell> cells = new HashSet<>();
public class MatterGrid extends AbstractGrid<IMatterGridCell> implements IMatterGridListener {
private final Set<IMatterGridListener> listeners = new HashSet<>();
public static void scheduleDiscoverNeighbours(IMatterGridCell cell, BlockPos pos, Level level) {
@ -29,7 +28,7 @@ public class MatterGrid implements IMatterGridListener {
}
public MatterGrid() {
NETWORKS.add(this);
super(MatteryCapability.MATTER_CELL);
}
public BigDecimal getCapacity() {
@ -336,14 +335,11 @@ public class MatterGrid implements IMatterGridListener {
return false;
}
public void track(IMatterGridCell entity) {
if (cells.contains(entity))
return;
@Override
protected void onAdded(IMatterGridCell cell) {
cell.setMatterGrid(this);
cells.add(entity);
entity.setMatterGrid(this);
var tasks = entity.getTaskProvider();
var tasks = cell.getTaskProvider();
if (tasks != null) {
for (var task : tasks.getAllTasks()) {
@ -351,7 +347,7 @@ public class MatterGrid implements IMatterGridListener {
}
}
var patterns = entity.getPatternStorage();
var patterns = cell.getPatternStorage();
if (patterns != null) {
for (var pattern : patterns.getStoredPatterns()) {
@ -360,14 +356,11 @@ public class MatterGrid implements IMatterGridListener {
}
}
public void untrack(IMatterGridCell entity) {
if (!cells.contains(entity))
return;
@Override
protected void onRemoved(IMatterGridCell cell) {
cell.setMatterGrid(null);
cells.remove(entity);
entity.setMatterGrid(null);
var tasks = entity.getTaskProvider();
var tasks = cell.getTaskProvider();
if (tasks != null) {
for (var task : tasks.getAllTasks()) {
@ -375,16 +368,13 @@ public class MatterGrid implements IMatterGridListener {
}
}
var patterns = entity.getPatternStorage();
var patterns = cell.getPatternStorage();
if (patterns != null) {
for (var pattern : patterns.getStoredPatterns()) {
onPatternRemoved(pattern);
}
}
if (cells.size() == 0)
NETWORKS.remove(this);
}
public void attach(IMatterGridListener listener) {
@ -395,34 +385,6 @@ public class MatterGrid implements IMatterGridListener {
listeners.remove(listener);
}
public int networkSize() {
return cells.size();
}
public void mergeWith(MatterGrid other) {
if (other == this)
return;
MatterGrid a;
MatterGrid b;
if (networkSize() > other.networkSize()) {
a = this;
b = other;
} else {
a = other;
b = this;
}
b.validate();
for (IMatterGridCell entity : b.cells) {
a.track(entity);
}
NETWORKS.remove(b);
}
public void validate() {
ArrayList<IMatterGridCell> invalid = new ArrayList<>();
@ -434,13 +396,9 @@ public class MatterGrid implements IMatterGridListener {
if (invalid.size() != 0) {
for (IMatterGridCell entity : invalid) {
untrack(entity);
remove(entity);
}
}
if (cells.size() == 0) {
NETWORKS.remove(this);
}
}
@Override

View File

@ -4,20 +4,22 @@ import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraftforge.common.util.LazyOptional;
import ru.dbotthepony.mc.otm.AbstractGrid;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.capability.IStorageGridCell;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.*;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public class StorageGrid {
private final HashSet<IStorageGridCell> cells = new HashSet<>();
public class StorageGrid extends AbstractGrid<IStorageGridCell> {
private final HashMap<Class<? extends IStorageStack>, VirtualComponent<? extends IStorageStack>> virtual_components = new HashMap<>();
public StorageGrid() {}
public StorageGrid() {
super(MatteryCapability.STORAGE_CELL);
}
public <T extends IStorageStack> T insertObject(Class<T> type, T object, boolean simulate) {
return getVirtualComponent(type).insertStack(object, simulate);
@ -33,62 +35,30 @@ public class StorageGrid {
return (VirtualComponent<T>) virtual_components.computeIfAbsent(type, (k) -> new VirtualComponent<>(type));
}
public int size() {
return cells.size();
}
public <T extends IStorageStack> void add(IStorageIdentity<T> identity) {
getVirtualComponent(identity.storageIdentity()).add(identity);
}
public boolean add(LazyOptional<IStorageGridCell> cell) {
if (!cell.isPresent())
return false;
var resolved = cell.resolve();
if (resolved.isPresent()) {
final var value = resolved.get();
if (add(value)) {
cell.addListener((lazy) -> remove(value));
return true;
}
}
return false;
}
public boolean add(IStorageGridCell cell) {
if (cells.add(cell)) {
cell.setStorageGrid(this);
for (var identity : cell.getComponents()) {
add(identity);
}
return true;
}
return false;
}
public <T extends IStorageStack> void remove(IStorageIdentity<T> identity) {
getVirtualComponent(identity.storageIdentity()).remove(identity);
}
public boolean remove(IStorageGridCell cell) {
if (cells.remove(cell)) {
cell.setStorageGrid(null);
@Override
protected void onAdded(IStorageGridCell cell) {
cell.setStorageGrid(this);
for (var identity : cell.getComponents()) {
remove(identity);
}
return true;
for (var identity : cell.getComponents()) {
add(identity);
}
}
return false;
@Override
protected void onRemoved(IStorageGridCell cell) {
cell.setStorageGrid(null);
for (var identity : cell.getComponents()) {
remove(identity);
}
}
public void detach(IStorageGridCell cell) {
@ -107,31 +77,6 @@ public class StorageGrid {
}
}
public StorageGrid merge(StorageGrid other) {
if (other == this)
return this;
if (size() < other.size()) {
var copy = List.copyOf(cells);
for (var cell : copy) {
remove(cell);
other.add(cell);
}
return other;
} else {
var copy = List.copyOf(other.cells);
for (var cell : copy) {
other.remove(cell);
add(cell);
}
return this;
}
}
public static void scheduleDiscoverNeighbours(IStorageGridCell cell, Level level, BlockPos pos) {
OverdriveThatMatters.tickUntil(level, () -> !cell.isValidStorageCell() || cell.connectOrCreateStorageGrid(level, pos, true));
}