New graph system, Matter interaction system rewrite

Port more code to Kotlin
Update Fraction to crunch down numbers with GCDs
This commit is contained in:
DBotThePony 2021-12-31 13:10:31 +07:00
parent b86f71b910
commit 994863b9bc
Signed by: DBot
GPG Key ID: DCC23B5715498507
41 changed files with 3063 additions and 2724 deletions

1
.gitignore vendored
View File

@ -23,6 +23,7 @@ run
design/
libs/
logs/
# Files from Forge MDK
forge*changelog.txt

View File

@ -28,7 +28,6 @@ import ru.dbotthepony.mc.otm.capability.drive.DrivePool;
import ru.dbotthepony.mc.otm.client.AndroidGui;
import ru.dbotthepony.mc.otm.client.EventHandler;
import ru.dbotthepony.mc.otm.item.ItemPortableCondensationDrive;
import ru.dbotthepony.mc.otm.matter.MatterGrid;
import ru.dbotthepony.mc.otm.matter.MatterRegistry;
import ru.dbotthepony.mc.otm.network.MatteryNetworking;
import ru.dbotthepony.mc.otm.storage.ItemStackWrapper;
@ -129,7 +128,6 @@ public class OverdriveThatMatters {
MinecraftForge.EVENT_BUS.register(this);
MinecraftForge.EVENT_BUS.register(AndroidCapabilityPlayer.class);
MinecraftForge.EVENT_BUS.register(AndroidCapability.class);
MinecraftForge.EVENT_BUS.register(MatterGrid.class);
MinecraftForge.EVENT_BUS.register(MatterRegistry.class);
MinecraftForge.EVENT_BUS.register(BlockEntityBlackHole.BlackHoleExplosionQueue.class);

View File

@ -19,7 +19,6 @@ import net.minecraft.world.phys.shapes.BooleanOp;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import ru.dbotthepony.mc.otm.capability.matter.IMatterGridCell;
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterCable;
import javax.annotation.Nullable;
@ -172,62 +171,6 @@ public class BlockMatterCable extends Block implements EntityBlock {
return true;
}
// doesn't work at all
/*
@Nullable
@Override
public BlockState getStateForPlacement(BlockPlaceContext p_49820_) {
Level level = p_49820_.getLevel();
if (level.isClientSide)
return this.defaultBlockState();
BlockState state = this.defaultBlockState();
for (int i = 0; i < MAPPING_CONNECTION_PROP.length; i++) {
OverdriveThatMatters.LOGGER.info("{} {} {}", Direction.values()[i], p_49820_.getClickedPos().offset(Direction.values()[i].getNormal()), level.getBlockEntity(p_49820_.getClickedPos().offset(p_49820_.getClickedFace().getNormal()).offset(Direction.values()[i].getNormal())));
if (
level.getBlockEntity(p_49820_.getClickedPos().offset(Direction.values()[i].getNormal())) instanceof IMatterGridCell cell && cell.isValidMatterCell()// ||
//level.getBlockState(p_49820_.getClickedPos().offset(p_49820_.getClickedFace().getNormal()).offset(Direction.values()[i].getNormal())).getBlock() instanceof BlockMatterCable
) {
state.setValue(MAPPING_CONNECTION_PROP[i], true);
}
}
return state;
}
*/
// 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;
BlockEntity get_entity = level.getBlockEntity(position_notifier);
if (!self.getValue(MAPPING_CONNECTION_PROP[normal.ordinal()]) && get_entity instanceof IMatterGridCell cell && cell.isValidMatterCell()) {
self = self.setValue(MAPPING_CONNECTION_PROP[normal.ordinal()], true);
updated = true;
} else if (self.getValue(MAPPING_CONNECTION_PROP[normal.ordinal()]) && (get_entity == null || get_entity instanceof IMatterGridCell cell && !cell.isValidMatterCell())) {
self = self.setValue(MAPPING_CONNECTION_PROP[normal.ordinal()], false);
updated = true;
}
if (updated) {
level.setBlock(position_self, self, UPDATE_CLIENTS);
}
super.neighborChanged(self, level, position_self, block_notifier, position_notifier, unknown_flag);
}
// tiles
/*@Override
public void onNeighborChange(BlockState state, LevelReader world, BlockPos pos, BlockPos neighbor) {
super.onNeighborChange(state, world, pos, neighbor);
}*/
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(CONNECTION_SOUTH,

View File

@ -1,111 +0,0 @@
package ru.dbotthepony.mc.otm.block.entity;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
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 ru.dbotthepony.mc.otm.capability.matter.IMatterGridCell;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.matter.MatterGrid;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.block.BlockMatterCable;
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler;
import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public class BlockEntityMatterCable extends BlockEntity implements IMatterGridCell {
public BlockEntityMatterCable(BlockPos p_155229_, BlockState p_155230_) {
super(Registry.BlockEntities.MATTER_CABLE, p_155229_, p_155230_);
// OverdriveThatMatters.LOGGER.debug("create cable block entity {} {} {}", this, p_155229_, p_155230_);
}
private MatterGrid grid;
private LazyOptional<IMatterGridCell> resolver_grid = LazyOptional.of(() -> this);
private boolean valid = true;
@Override
public void invalidateCaps() {
super.invalidateCaps();
valid = false;
resolver_grid.invalidate();
}
@Override
public void reviveCaps() {
super.reviveCaps();
valid = true;
resolver_grid = LazyOptional.of(() -> this);
}
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
if (valid && cap == MatteryCapability.MATTER_CELL)
return resolver_grid.cast();
return super.getCapability(cap, side);
}
@Override
public void setLevel(Level p_155231_) {
super.setLevel(p_155231_);
if (grid == null)
MatterGrid.scheduleDiscoverNeighbours(this, getBlockPos(), p_155231_);
}
@Nullable
@Override
public IPatternStorage getPatternStorage() {
return null;
}
@Override
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())
level.setBlock(getBlockPos(), new_state, Block.UPDATE_CLIENTS);
}
@Override
public void setRemoved() {
super.setRemoved();
if (grid != null)
grid.remove(this);
}
@Nullable
@Override
public MatterGrid getMatterGrid() {
return grid;
}
@Nullable
@Override
public IMatterHandler getMatterHandler() {
return null;
}
@Override
public boolean isValidMatterCell() {
return valid;
}
@Override
public void setMatterGrid(MatterGrid grid) {
this.grid = grid;
}
}

View File

@ -1,221 +0,0 @@
package ru.dbotthepony.mc.otm.block.entity;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.world.entity.player.Inventory;
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.*;
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;
import ru.dbotthepony.mc.otm.capability.*;
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler;
import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage;
import ru.dbotthepony.mc.otm.capability.matter.MatterHandlerCapability;
import ru.dbotthepony.mc.otm.container.MatteryContainer;
import ru.dbotthepony.mc.otm.capability.matter.IMatterGridCell;
import ru.dbotthepony.mc.otm.core.Fraction;
import ru.dbotthepony.mc.otm.matter.MatterGrid;
import ru.dbotthepony.mc.otm.matter.MatterRegistry;
import ru.dbotthepony.mc.otm.menu.MatterDecomposerMenu;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.math.BigDecimal;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public class BlockEntityMatterDecomposer extends BlockEntityMatteryWorker implements IMatterGridCell {
private static final TranslatableComponent MACHINE_NAME = new TranslatableComponent("block.overdrive_that_matters.matter_decomposer");
private boolean valid = true;
public final MatterHandlerCapability matter = new MatterHandlerCapability(this::setChanged, IMatterHandler.MatterDirection.EXTRACT, new Fraction("20"));
private LazyOptional<IMatterHandler> matter_resolver = LazyOptional.of(() -> matter);
// вход, выход
public final MatteryContainer item_container = new MatteryContainer(this::setChanged, 2);
private final LazyOptional<IItemHandler> handler_resolver = LazyOptional.of(() -> item_container.handler(
(slot, stack) -> slot == 0 && MatterRegistry.canDecompose(stack),
(slot, amount, stack) -> slot == 1
));
public BlockEntityMatterDecomposer(BlockPos p_155229_, BlockState p_155230_) {
super(Registry.BlockEntities.MATTER_DECOMPOSER, p_155229_, p_155230_);
energy = new MatteryMachineEnergyStorage(this, MatteryMachineEnergyStorage.MachineType.WORKER, new Fraction(400_000), new Fraction(2000), new Fraction(2000));
}
@Override
protected Component getDefaultDisplayName() {
return MACHINE_NAME;
}
@Nullable
@Override
public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply) {
return new MatterDecomposerMenu(containerID, inventory, this);
}
@Nullable
@Override
public IPatternStorage getPatternStorage() {
return null;
}
@Override
public void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
nbt.put("work_slots", item_container.serializeNBT());
nbt.put("matter_capability", matter.serializeNBT());
}
@Override
public void load(CompoundTag nbt) {
super.load(nbt);
if (nbt.contains("matter_capability") && nbt.get("matter_capability") instanceof CompoundTag tag)
matter.deserializeNBT(tag);
item_container.deserializeNBT(nbt.get("work_slots"));
}
@Override
public void reviveCaps() {
valid = true;
super.reviveCaps();
matter_resolver = LazyOptional.of(() -> matter);
resolver_grid = LazyOptional.of(() -> this);
}
@Override
public void invalidateCaps() {
valid = false;
super.invalidateCaps();
matter_resolver.invalidate();
resolver_grid.invalidate();
}
private LazyOptional<IMatterGridCell> resolver_grid = LazyOptional.of(() -> this);
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
if (valid) {
if (cap == MatteryCapability.MATTER)
return matter_resolver.cast();
if (cap == MatteryCapability.MATTER_CELL)
return resolver_grid.cast();
if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
return handler_resolver.cast();
}
return super.getCapability(cap, side);
}
@Nonnull
@Override
protected MachineJobStatus onJobFinish(MachineJob job) {
var matter_value = MatterRegistry.getMatterValue(job.stack());
matter.receiveMatterInner(matter_value, false);
return new MachineJobStatus();
}
@Nullable
@Override
protected MachineJob getNextJob() {
ItemStack stack = item_container.getItem(0);
if (!stack.isEmpty()) {
ItemStack copy = stack.copy();
copy.setCount(1);
if (MatterRegistry.canDecompose(copy)) {
var matter_value = MatterRegistry.getMatterValue(copy);
if (!matter_value.equals(Fraction.ZERO) && matter.canReceiveAll(matter_value)) {
stack.shrink(1);
return new MachineJob(copy, matter_value.toDouble() * 12_500d);
}
}
}
return null;
}
public static <T extends BlockEntity> void tick(Level level, BlockPos blockPos, BlockState blockState, T t) {
if (t instanceof BlockEntityMatterDecomposer tile) {
tile.batteryChargeLoop();
tile.workerLoop();
if (tile.matter.getStoredMatter().compareTo(Fraction.ZERO) > 0 && tile.grid != null) {
var diff = tile.matter.extractMatterInner(tile.matter.getStoredMatter(), true);
var diff2 = tile.grid.softPushMatter(diff, true);
tile.matter.extractMatterInner(diff2, false);
tile.grid.softPushMatter(diff2, false);
}
}
}
private MatterGrid grid;
@Override
public void setRemoved() {
super.setRemoved();
if (level != null && !level.isClientSide && grid != null)
grid.remove(this);
}
@Override
public void setLevel(Level p_155231_) {
super.setLevel(p_155231_);
if (!p_155231_.isClientSide)
MatterGrid.scheduleDiscoverNeighbours(this, getBlockPos(), p_155231_);
}
@Nullable
@Override
public MatterGrid getMatterGrid() {
return grid;
}
@Nullable
@Override
public IMatterHandler getMatterHandler() {
return valid ? matter : null;
}
@Override
public boolean isValidMatterCell() {
return valid;
}
@Override
public void setMatterGrid(MatterGrid grid) {
this.grid = grid;
}
private static final Fraction BASE_CONSUMPTION = new Fraction(240);
@Override
protected Fraction getBaseConsumption() {
return BASE_CONSUMPTION;
}
}

View File

@ -4,13 +4,12 @@ import net.minecraftforge.common.capabilities.*;
import net.minecraftforge.energy.IEnergyStorage;
import ru.dbotthepony.mc.otm.capability.android.IAndroidCapability;
import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive;
import ru.dbotthepony.mc.otm.capability.matter.IMatterGridCell;
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler;
import ru.dbotthepony.mc.otm.capability.matter.IMatterTaskProvider;
import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage;
import ru.dbotthepony.mc.otm.core.Fraction;
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
@ -18,7 +17,7 @@ public class MatteryCapability {
public static final Capability<IMatteryEnergyStorage> ENERGY = CapabilityManager.get(new CapabilityToken<>() {});
public static final Capability<IAndroidCapability> ANDROID = CapabilityManager.get(new CapabilityToken<>() {});
public static final Capability<IMatterHandler> MATTER = CapabilityManager.get(new CapabilityToken<>() {});
public static final Capability<IMatterGridCell> MATTER_CELL = CapabilityManager.get(new CapabilityToken<>() {});
public static final Capability<IMatterGraphNode> MATTER_CELL = CapabilityManager.get(new CapabilityToken<>() {});
public static final Capability<IPatternStorage> PATTERN = CapabilityManager.get(new CapabilityToken<>() {});
public static final Capability<IMatterTaskProvider> TASK = CapabilityManager.get(new CapabilityToken<>() {});
public static final Capability<IMatteryDrive> DRIVE = CapabilityManager.get(new CapabilityToken<>() {});
@ -29,11 +28,11 @@ public class MatteryCapability {
event.register(IMatteryEnergyStorage.class);
event.register(IAndroidCapability.class);
event.register(IMatterHandler.class);
event.register(IMatterGridCell.class);
event.register(IPatternStorage.class);
event.register(IMatterTaskProvider.class);
event.register(IMatteryDrive.class);
event.register(IStorageGridCell.class);
event.register(IMatterGraphNode.class);
}
public static final MathContext ROUND_RULES = new MathContext(32, RoundingMode.HALF_DOWN);

View File

@ -1,65 +0,0 @@
package ru.dbotthepony.mc.otm.capability.matter;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
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 {
@Nullable
MatterGrid getMatterGrid();
@Nullable
default IMatterHandler getMatterHandler() {
return null;
}
@Nullable
default IPatternStorage getPatternStorage() {
return null;
}
@Nullable
default IMatterTaskProvider getTaskProvider() {
return null;
}
boolean isValidMatterCell();
void setMatterGrid(@Nullable MatterGrid grid);
default void scheduleDiscoverNeighbours(Level level, BlockPos pos) {
MatterGrid.scheduleDiscoverNeighbours(this, pos, level);
}
default boolean connectOrCreateMatterGrid(Level level, BlockPos pos) {
return connectOrCreateMatterGrid(pos, level, false);
}
default void onNeighbourMatterCell(Level level, BlockPos pos, Direction direction, IMatterGridCell cell, BlockEntity entity) {
}
default boolean connectOrCreateMatterGrid(BlockPos pos, Level level, boolean force) {
return createOrConnectGrid(
this,
MatteryCapability.MATTER_CELL,
level,
pos,
force,
MatterGrid::new,
IMatterGridCell::getMatterGrid,
this::onNeighbourMatterCell
);
}
}

View File

@ -1,18 +0,0 @@
package ru.dbotthepony.mc.otm.capability.matter;
import net.minecraft.MethodsReturnNonnullByDefault;
import javax.annotation.ParametersAreNonnullByDefault;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public interface IMatterGridListener {
default void onPatternAdded(PatternState state) { }
default void onPatternRemoved(PatternState state) { }
default void onPatternUpdated(PatternState new_state, PatternState old_state) { }
default void onMatterTaskCreated(MatterTask task) { }
default void onMatterTaskUpdated(MatterTask new_state, MatterTask old_state) { }
default void onMatterTaskFinished(MatterTask state) { }
default void onMatterTaskRemoved(MatterTask state) { }
}

View File

@ -1,453 +0,0 @@
package ru.dbotthepony.mc.otm.matter;
import com.google.common.collect.ImmutableList;
import net.minecraft.MethodsReturnNonnullByDefault;
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 ru.dbotthepony.mc.otm.core.Fraction;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Predicate;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
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) {
if (level instanceof ServerLevel)
OverdriveThatMatters.tickUntil(level, () -> !cell.isValidMatterCell() || cell.connectOrCreateMatterGrid(pos, level, true));
}
public MatterGrid() {
super(MatteryCapability.MATTER_CELL);
}
public Fraction getCapacity() {
Fraction summ = Fraction.ZERO;
for (IMatterGridCell cell : cells) {
IMatterHandler handler = cell.getMatterHandler();
if (handler != null && handler.getDirection() == IMatterHandler.MatterDirection.BIDIRECTIONAL) {
summ = summ.plus(handler.getMaxStoredMatter());
}
}
return summ;
}
public Fraction getPotentialCapacity() {
Fraction summ = Fraction.ZERO;
for (IMatterGridCell cell : cells) {
IMatterHandler handler = cell.getMatterHandler();
if (handler != null && handler.getDirection() != IMatterHandler.MatterDirection.RECEIVE) {
summ = summ.plus(handler.getMaxStoredMatter());
}
}
return summ;
}
public Fraction getStored() {
Fraction summ = Fraction.ZERO;
for (IMatterGridCell cell : cells) {
IMatterHandler handler = cell.getMatterHandler();
if (handler != null && handler.getDirection() == IMatterHandler.MatterDirection.BIDIRECTIONAL) {
summ = summ.plus(handler.getStoredMatter());
}
}
return summ;
}
public Fraction getPotentialStored() {
Fraction summ = Fraction.ZERO;
for (IMatterGridCell cell : cells) {
IMatterHandler handler = cell.getMatterHandler();
if (handler != null && handler.getDirection() != IMatterHandler.MatterDirection.RECEIVE) {
summ = summ.plus(handler.getStoredMatter());
}
}
return summ;
}
public Fraction extractMatter(Fraction howMuch, boolean simulate) {
if (howMuch.compareTo(Fraction.ZERO) <= 0)
return Fraction.ZERO;
validate();
Fraction extracted = Fraction.ZERO;
for (IMatterGridCell cell : cells) {
IMatterHandler handler = cell.getMatterHandler();
if (handler != null && handler.getDirection() != IMatterHandler.MatterDirection.RECEIVE) {
var drain = handler.extractMatterOuter(howMuch, simulate);
if (!drain.equalsCompact(Fraction.ZERO)) {
extracted = extracted.plus(drain);
howMuch = howMuch.minus(drain);
if (howMuch.compareTo(Fraction.ZERO) <= 0) {
break;
}
}
}
}
return extracted;
}
public Fraction softPushMatter(Fraction howMuch, boolean simulate) {
if (howMuch.compareTo(Fraction.ZERO) <= 0)
return Fraction.ZERO;
validate();
Fraction received = Fraction.ZERO;
for (IMatterGridCell cell : cells) {
IMatterHandler handler = cell.getMatterHandler();
if (handler != null && handler.getDirection() == IMatterHandler.MatterDirection.BIDIRECTIONAL) {
var receive = handler.receiveMatterOuter(howMuch, simulate);
if (!receive.equalsCompact(Fraction.ZERO)) {
received = received.plus(receive);
howMuch = howMuch.minus(receive);
if (howMuch.compareTo(Fraction.ZERO) <= 0) {
break;
}
}
}
}
return received;
}
public Fraction pushMatter(Fraction howMuch, boolean simulate) {
if (howMuch.compareTo(Fraction.ZERO) <= 0)
return Fraction.ZERO;
validate();
Fraction received = Fraction.ZERO;
for (IMatterGridCell cell : cells) {
IMatterHandler handler = cell.getMatterHandler();
if (handler != null && handler.getDirection() != IMatterHandler.MatterDirection.EXTRACT) {
var receive = handler.receiveMatterOuter(howMuch, simulate);
if (!receive.equalsCompact(Fraction.ZERO)) {
received = received.plus(receive);
howMuch = howMuch.minus(receive);
if (howMuch.compareTo(Fraction.ZERO) <= 0) {
break;
}
}
}
}
return received;
}
public PatternInsertStatus insertPattern(PatternState state, boolean only_update, boolean simulate) {
validate();
for (IMatterGridCell cell : cells) {
IPatternStorage storage = cell.getPatternStorage();
if (storage != null) {
var status = storage.insertPattern(state, true, simulate);
if (status.status() != PatternInsertStatus.Status.FAIL) {
return status;
}
}
}
if (only_update)
return new PatternInsertStatus();
for (IMatterGridCell cell : cells) {
IPatternStorage storage = cell.getPatternStorage();
if (storage != null) {
var status = storage.insertPattern(state, false, simulate);
if (status.status() != PatternInsertStatus.Status.FAIL) {
return status;
}
}
}
return new PatternInsertStatus();
}
public Collection<PatternState> getStoredPatterns() {
validate();
ArrayList<PatternState> list = new ArrayList<>();
for (IMatterGridCell cell : cells) {
IPatternStorage storage = cell.getPatternStorage();
if (storage != null) {
list.addAll(storage.getStoredPatterns());
}
}
return ImmutableList.copyOf(list);
}
public long getStoredPatternCount() {
validate();
long value = 0;
for (IMatterGridCell cell : cells) {
IPatternStorage storage = cell.getPatternStorage();
if (storage != null) {
value += storage.getStored();
}
}
return value;
}
public long getPatternCapacity() {
validate();
long value = 0;
for (IMatterGridCell cell : cells) {
IPatternStorage storage = cell.getPatternStorage();
if (storage != null) {
value += storage.getCapacity();
}
}
return value;
}
public Collection<PatternState> findPatterns(Item item) {
return findPatterns((patternState -> item == patternState.item()));
}
public Collection<PatternState> findPatterns(Predicate<PatternState> item) {
validate();
ArrayList<PatternState> list = new ArrayList<>();
for (IMatterGridCell cell : cells) {
IPatternStorage storage = cell.getPatternStorage();
if (storage != null) {
list.addAll(storage.findPatterns(item));
}
}
return ImmutableList.copyOf(list);
}
@Nullable
public PatternState getPattern(PatternState state) {
return getPattern(state.id());
}
@Nullable
public PatternState getPattern(UUID id) {
validate();
for (IMatterGridCell cell : cells) {
IPatternStorage storage = cell.getPatternStorage();
if (storage != null) {
var get = storage.getPattern(id);
if (get != null) {
return get;
}
}
}
return null;
}
public boolean hasPattern(UUID id) {
return getPattern(id) != null;
}
@Nullable
public MatterTaskAllocation allocateTask(boolean simulate) {
validate();
for (IMatterGridCell cell : cells) {
IMatterTaskProvider tasks = cell.getTaskProvider();
if (tasks != null) {
MatterTaskAllocation allocated = tasks.allocateTask(simulate);
if (allocated != null) {
return allocated;
}
}
}
return null;
}
public boolean notifyTaskCompletion(MatterTask task) {
validate();
for (IMatterGridCell cell : cells) {
IMatterTaskProvider tasks = cell.getTaskProvider();
if (tasks != null) {
if (tasks.notifyTaskCompletion(task)) {
return true;
}
}
}
return false;
}
@Override
protected void onAdded(IMatterGridCell cell) {
cell.setMatterGrid(this);
var tasks = cell.getTaskProvider();
if (tasks != null) {
for (var task : tasks.getAllTasks()) {
onMatterTaskCreated(task);
}
}
var patterns = cell.getPatternStorage();
if (patterns != null) {
for (var pattern : patterns.getStoredPatterns()) {
onPatternAdded(pattern);
}
}
}
@Override
protected void onRemoved(IMatterGridCell cell) {
cell.setMatterGrid(null);
var tasks = cell.getTaskProvider();
if (tasks != null) {
for (var task : tasks.getAllTasks()) {
onMatterTaskRemoved(task);
}
}
var patterns = cell.getPatternStorage();
if (patterns != null) {
for (var pattern : patterns.getStoredPatterns()) {
onPatternRemoved(pattern);
}
}
}
public void attach(IMatterGridListener listener) {
listeners.add(listener);
}
public void detach(IMatterGridListener listener) {
listeners.remove(listener);
}
public void validate() {
ArrayList<IMatterGridCell> invalid = new ArrayList<>();
for (IMatterGridCell entity : cells) {
if (!entity.isValidMatterCell()) {
invalid.add(entity);
}
}
if (invalid.size() != 0) {
for (IMatterGridCell entity : invalid) {
remove(entity);
}
}
}
@Override
public void onPatternAdded(PatternState state) {
// validate();
cells.forEach(cell -> cell.onPatternAdded(state));
listeners.forEach(cell -> cell.onPatternAdded(state));
}
@Override
public void onPatternRemoved(PatternState state) {
// validate();
cells.forEach(cell -> cell.onPatternRemoved(state));
listeners.forEach(cell -> cell.onPatternRemoved(state));
}
@Override
public void onPatternUpdated(PatternState new_state, PatternState old_state) {
// validate();
cells.forEach(cell -> cell.onPatternUpdated(new_state, old_state));
listeners.forEach(cell -> cell.onPatternUpdated(new_state, old_state));
}
@Override
public void onMatterTaskCreated(MatterTask task) {
// validate();
cells.forEach(cell -> cell.onMatterTaskCreated(task));
listeners.forEach(cell -> cell.onMatterTaskCreated(task));
}
@Override
public void onMatterTaskUpdated(MatterTask new_state, MatterTask old_state) {
// validate();
cells.forEach(cell -> cell.onMatterTaskUpdated(new_state, old_state));
listeners.forEach(cell -> cell.onMatterTaskUpdated(new_state, old_state));
}
@Override
public void onMatterTaskFinished(MatterTask state) {
// validate();
cells.forEach(cell -> cell.onMatterTaskFinished(state));
listeners.forEach(cell -> cell.onMatterTaskFinished(state));
}
@Override
public void onMatterTaskRemoved(MatterTask state) {
// validate();
cells.forEach(cell -> cell.onMatterTaskRemoved(state));
listeners.forEach(cell -> cell.onMatterTaskRemoved(state));
}
}

View File

@ -27,7 +27,7 @@ public class MatterDecomposerMenu extends PoweredMatteryMenu {
public MatterDecomposerMenu(int containerID, Inventory inventory, @Nullable BlockEntityMatterDecomposer tile) {
super(Registry.Menus.MATTER_DECOMPOSER, containerID, inventory, tile);
Container container = tile != null ? tile.item_container : new SimpleContainer(2);
Container container = tile != null ? tile.itemContainer : new SimpleContainer(2);
// Вход
input = new MatterySlot(container, 0, 61, 36) {

View File

@ -21,7 +21,7 @@ public class MatterReplicatorMenu extends PoweredMatteryMenu {
public MatterReplicatorMenu(int p_38852_, Inventory inventory, BlockEntityMatterReplicator tile) {
super(Registry.Menus.MATTER_REPLICATOR, p_38852_, inventory, tile);
Container container = tile != null ? tile.regular_slots : new SimpleContainer(3);
Container container = tile != null ? tile.regularSlots : new SimpleContainer(3);
for (int i = 0; i < container.getContainerSize(); i++) {
output_slots[i] = new MachineOutputSlot(container, i, 64 + 18 * i, 38, true);

View File

@ -10,14 +10,16 @@ import ru.dbotthepony.mc.otm.capability.matter.MatterTask;
import ru.dbotthepony.mc.otm.menu.MatterPanelMenu;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
import java.util.function.Supplier;
@ParametersAreNonnullByDefault
public record MatterTaskPacket(boolean action, MatterTask...state) {
public record MatterTaskPacket(boolean action, Collection<MatterTask> state) {
public void write(FriendlyByteBuf buffer) {
buffer.writeBoolean(action);
buffer.writeInt(state.length);
buffer.writeInt(state.size());
for (var state1 : state)
state1.write(buffer);
@ -42,10 +44,10 @@ public record MatterTaskPacket(boolean action, MatterTask...state) {
public static MatterTaskPacket read(FriendlyByteBuf buffer) {
boolean action = buffer.readBoolean();
int amount = buffer.readInt();
var list = new MatterTask[amount];
var list = new ArrayList<MatterTask>(amount);
for (int i = 0; i < amount; i++)
list[i] = Objects.requireNonNull(MatterTask.read(buffer));
list.add(Objects.requireNonNull(MatterTask.read(buffer)));
return new MatterTaskPacket(action, list);
}

View File

@ -44,11 +44,17 @@ public class NetworkHelper {
}
public static byte[] shortsToBytes(short[] input) {
byte[] values = new byte[input.length * 2];
return shortsToBytes(input, 0);
}
for (int i = 0; i < input.length; i++) {
values[i * 2] = (byte) (input[i] & 0xFF);
values[i * 2 + 1] = (byte) ((input[i] & 0xFF00) >> 8);
public static byte[] shortsToBytes(short[] input, int offset) {
byte[] values = new byte[(input.length - offset) * 2];
for (int i = offset; i < input.length; i++) {
int realI = i - offset;
values[realI * 2] = (byte) (input[i] & 0xFF);
values[realI * 2 + 1] = (byte) ((input[i] & 0xFF00) >> 8);
}
return values;

View File

@ -10,14 +10,16 @@ import ru.dbotthepony.mc.otm.capability.matter.PatternState;
import ru.dbotthepony.mc.otm.menu.MatterPanelMenu;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
import java.util.function.Supplier;
@ParametersAreNonnullByDefault
public record PatternGridPacket(boolean action, PatternState ...state) {
public record PatternGridPacket(boolean action, Collection<PatternState> state) {
public void write(FriendlyByteBuf buffer) {
buffer.writeBoolean(action);
buffer.writeInt(state.length);
buffer.writeInt(state.size());
for (var state1 : state)
state1.write(buffer);
@ -44,10 +46,10 @@ public record PatternGridPacket(boolean action, PatternState ...state) {
public static PatternGridPacket read(FriendlyByteBuf buffer) {
boolean action = buffer.readBoolean();
int amount = buffer.readInt();
var list = new PatternState[amount];
var list = new ArrayList<PatternState>(amount);
for (int i = 0; i < amount; i++)
list[i] = Objects.requireNonNull(PatternState.read(buffer));
list.add(Objects.requireNonNull(PatternState.read(buffer)));
return new PatternGridPacket(action, list);
}

View File

@ -44,3 +44,11 @@ fun CompoundTag.ifHas(s: String, type: Byte, consumer: (Tag) -> Unit) {
consumer(tag)
}
}
fun <T : Tag> CompoundTag.ifHas(s: String, type: Class<T>, consumer: (T) -> Unit) {
val tag = get(s)
if (tag != null && tag::class.java == type) {
consumer(tag as T)
}
}

View File

@ -1,40 +1,41 @@
package ru.dbotthepony.mc.otm.block;
package ru.dbotthepony.mc.otm.block
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterBottler;
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import net.minecraft.MethodsReturnNonnullByDefault
import javax.annotation.ParametersAreNonnullByDefault
import ru.dbotthepony.mc.otm.block.BlockMatteryRotatable
import net.minecraft.world.level.block.EntityBlock
import net.minecraft.core.BlockPos
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.entity.BlockEntity
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterBottler
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.entity.BlockEntityTicker
import net.minecraft.world.level.block.state.StateDefinition
import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public class BlockMatterBottler extends BlockMatteryRotatable implements EntityBlock {
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
return new BlockEntityMatterBottler(blockPos, blockState);
class BlockMatterBottler : BlockMatteryRotatable(), EntityBlock {
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity? {
return BlockEntityMatterBottler(blockPos, blockState)
}
@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level p_153212_, BlockState p_153213_, BlockEntityType<T> p_153214_) {
return p_153212_.isClientSide || p_153214_ != Registry.BlockEntities.MATTER_BOTTLER ? null : BlockEntityMatterBottler::tick;
override fun <T : BlockEntity?> getTicker(
p_153212_: Level,
p_153213_: BlockState,
p_153214_: BlockEntityType<T>
): BlockEntityTicker<T>? {
if (p_153212_.isClientSide || p_153214_ !== Registry.BlockEntities.MATTER_BOTTLER)
return null
return BlockEntityTicker {_, _, _, tile -> if (tile is BlockEntityMatterBottler) tile.tick()}
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(WorkerState.SEMI_WORKER_STATE);
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
super.createBlockStateDefinition(builder)
builder.add(WorkerState.SEMI_WORKER_STATE)
}
}
}

View File

@ -1,67 +1,69 @@
package ru.dbotthepony.mc.otm.block;
package ru.dbotthepony.mc.otm.block
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterDecomposer;
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState;
import ru.dbotthepony.mc.otm.shapes.BlockShapes;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.List;
import net.minecraft.MethodsReturnNonnullByDefault
import javax.annotation.ParametersAreNonnullByDefault
import ru.dbotthepony.mc.otm.block.BlockMatteryRotatable
import net.minecraft.world.level.block.EntityBlock
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.entity.BlockEntity
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterDecomposer
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.entity.BlockEntityTicker
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.VoxelShape
import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.block.BlockMatterDecomposer
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.shapes.BlockShapes
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public class BlockMatterDecomposer extends BlockMatteryRotatable implements EntityBlock {
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
return new BlockEntityMatterDecomposer(blockPos, blockState);
class BlockMatterDecomposer : BlockMatteryRotatable(), EntityBlock {
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity? {
return BlockEntityMatterDecomposer(blockPos, blockState)
}
@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level p_153212_, BlockState p_153213_, BlockEntityType<T> p_153214_) {
return p_153212_.isClientSide || p_153214_ != Registry.BlockEntities.MATTER_DECOMPOSER ? null : BlockEntityMatterDecomposer::tick;
override fun <T : BlockEntity?> getTicker(
p_153212_: Level,
p_153213_: BlockState,
p_153214_: BlockEntityType<T>
): BlockEntityTicker<T>? {
if (p_153212_.isClientSide || p_153214_ !== Registry.BlockEntities.MATTER_DECOMPOSER)
return null
return BlockEntityTicker {_, _, _, t -> if (t is BlockEntityMatterDecomposer) t.tick()}
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(WorkerState.WORKER_STATE);
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
super.createBlockStateDefinition(builder)
builder.add(WorkerState.WORKER_STATE)
}
private static final List<VoxelShape> SHAPES;
override fun getShape(
p_60555_: BlockState,
p_60556_: BlockGetter,
p_60557_: BlockPos,
p_60558_: CollisionContext
): VoxelShape {
return SHAPES[p_60555_.getValue(FACING).ordinal]
}
static {
var def = BlockShapes.MATTER_DECOMPOSER.computeShape();
companion object {
private val def = BlockShapes.MATTER_DECOMPOSER.computeShape()
SHAPES = List.of(
private val SHAPES: List<VoxelShape> = listOf(
def,
def,
def,
BlockShapes.MATTER_DECOMPOSER.rotate(Direction.NORTH).computeShape(),
BlockShapes.MATTER_DECOMPOSER.rotate(Direction.WEST).computeShape(),
BlockShapes.MATTER_DECOMPOSER.rotate(Direction.EAST).computeShape()
);
)
}
@Override
@SuppressWarnings("deprecation")
public VoxelShape getShape(BlockState p_60555_, BlockGetter p_60556_, BlockPos p_60557_, CollisionContext p_60558_) {
return SHAPES.get(p_60555_.getValue(FACING).ordinal());
}
}
}

View File

@ -43,7 +43,7 @@ class BlockEntityChemicalGenerator(pos: BlockPos, state: BlockState) : BlockEnti
private var valid = true
private var resolver = LazyOptional.of {energy}
override fun <T : Any?> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
if (valid && (cap == MatteryCapability.ENERGY || cap == CapabilityEnergy.ENERGY) && side != blockState.getValue(BlockMatteryRotatable.FACING))
return resolver.cast()

View File

@ -1,366 +1,329 @@
package ru.dbotthepony.mc.otm.block.entity;
package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.world.entity.player.Inventory;
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.Block;
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 ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState;
import ru.dbotthepony.mc.otm.capability.*;
import ru.dbotthepony.mc.otm.capability.matter.IMatterGridCell;
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler;
import ru.dbotthepony.mc.otm.capability.matter.MatterHandlerCapability;
import ru.dbotthepony.mc.otm.container.MatteryContainer;
import ru.dbotthepony.mc.otm.container.MatteryContainerHandler;
import ru.dbotthepony.mc.otm.core.Fraction;
import ru.dbotthepony.mc.otm.matter.MatterGrid;
import ru.dbotthepony.mc.otm.menu.MatterBottlerMenu;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.math.BigDecimal;
import net.minecraft.MethodsReturnNonnullByDefault
import javax.annotation.ParametersAreNonnullByDefault
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.container.MatteryContainer
import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.matter.MatterHandlerCapability
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler.MatterDirection
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.items.CapabilityItemHandler
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import ru.dbotthepony.mc.otm.menu.MatterBottlerMenu
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component
import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage
import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraftforge.common.capabilities.Capability
import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.set
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public class BlockEntityMatterBottler extends BlockEntityMatteryPowered implements IMatterGridCell {
public BlockEntityMatterBottler(BlockPos p_155229_, BlockState p_155230_) {
super(Registry.BlockEntities.MATTER_BOTTLER, p_155229_, p_155230_);
energy = new MatteryMachineEnergyStorage(this, MatteryMachineEnergyStorage.MachineType.WORKER);
}
class BlockEntityMatterBottler(p_155229_: BlockPos, p_155230_: BlockState) :
BlockEntityMatteryPowered(Registry.BlockEntities.MATTER_BOTTLER, p_155229_, p_155230_), IMatterGraphNode {
private static final TranslatableComponent MACHINE_NAME = new TranslatableComponent("block.overdrive_that_matters.matter_bottler");
private val node = Graph6Node<IMatterGraphNode>(this)
private val resolverNode = LazyOptional.of { this }
public boolean getWorkFlow() {
return work_flow;
}
public void setWorkFlow(boolean work_flow) {
this.work_flow = work_flow;
this.setChanged();
}
public void switchWorkFlow() {
setWorkFlow(!work_flow);
override fun getAsMatterNode(): Graph6Node<IMatterGraphNode> {
return node
}
// true - bottling
// false - unbottling
protected boolean work_flow = true;
var workFlow: Boolean = true
set(value) {
field = value
this.setChangedLight()
}
fun switchWorkFlow() {
workFlow = !workFlow
}
// TODO: оно должно что то делать
// true - continue even if empty when bottling / if full while unbottling
// false - spit into output slot
protected boolean work_behavior = true;
//private var work_behavior = true
public final MatteryContainer work_slots = new MatteryContainer(this::setChanged, 6) {
@Override
public int getMaxStackSize(int slot) {
return 1;
@JvmField
val container: MatteryContainer = object : MatteryContainer(this::setChangedLight, 6) {
override fun getMaxStackSize(slot: Int): Int {
return 1
}
};
}
public final MatteryContainerHandler work_slots_handler = work_slots.handler((slot, stack) -> {
if (work_flow) {
return slot < 3 && stack.getCapability(MatteryCapability.MATTER).isPresent();
val itemHandler = container.handler({ slot: Int, stack: ItemStack ->
if (this.workFlow) {
return@handler slot < 3 && stack.getCapability(MatteryCapability.MATTER).isPresent
}
slot >= 3 && stack.getCapability(MatteryCapability.MATTER).isPresent
}, { slot: Int, amount: Int, stack: ItemStack? ->
if (this.workFlow) {
return@handler slot >= 3
}
slot < 3
})
@JvmField
val matter: MatterHandlerCapability =
object : MatterHandlerCapability(this::setChangedLight, MatterDirection.BIDIRECTIONAL, Fraction(4)) {
override fun getDirection(): MatterDirection {
return if (this@BlockEntityMatterBottler.workFlow) MatterDirection.RECEIVE else MatterDirection.EXTRACT
}
}
return slot >= 3 && stack.getCapability(MatteryCapability.MATTER).isPresent();
}, (slot, amount, stack) -> {
if (work_flow) {
return slot >= 3;
}
private var initialCapacity: Fraction? = null
private var lastWorkStack: ItemStack? = null
return slot < 3;
});
public final MatterHandlerCapability matter = new MatterHandlerCapability(this::setChanged, IMatterHandler.MatterDirection.BIDIRECTIONAL, new Fraction(4)) {
@Nonnull
@Override
public MatterDirection getDirection() {
return work_flow ? MatterDirection.RECEIVE : MatterDirection.EXTRACT;
}
};
private static final Fraction MATTER_EXCHANGE_RATE = new Fraction("0.04");
private static final Fraction ENERGY_CONSUMPTION = new Fraction(20);
private LazyOptional<IMatterGridCell> cell_resolver = LazyOptional.of(() -> this);
protected Fraction initial_capacity;
protected ItemStack last_work_stack;
private MatterGrid grid;
@Nullable
@Override
public MatterGrid getMatterGrid() {
return grid;
override fun getMatterHandler(): IMatterHandler {
return matter
}
@Override
public boolean isValidMatterCell() {
return valid;
override fun setLevel(p_155231_: Level) {
super.setLevel(p_155231_)
if (p_155231_ is ServerLevel)
MatterNetworkGraph.discoverFull(this, node)
}
@Override
public void setMatterGrid(MatterGrid grid) {
this.grid = grid;
private var valid = true
override fun invalidateCaps() {
super.invalidateCaps()
valid = false
itemHandler.invalidate()
matter.invalidate()
}
@Nullable
@Override
public IMatterHandler getMatterHandler() {
return matter;
override fun reviveCaps() {
super.reviveCaps()
valid = true
itemHandler.revive()
matter.revive()
}
@Override
public void setLevel(Level p_155231_) {
super.setLevel(p_155231_);
if (grid == null)
scheduleDiscoverNeighbours(p_155231_, getBlockPos());
}
private boolean valid = true;
@Override
public void invalidateCaps() {
super.invalidateCaps();
valid = false;
work_slots_handler.invalidate();
matter.invalidate();
cell_resolver.invalidate();
}
@Override
public void reviveCaps() {
super.reviveCaps();
valid = true;
work_slots_handler.revive();
matter.revive();
cell_resolver = LazyOptional.of(() -> this);
}
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
if (valid) {
if (cap == MatteryCapability.MATTER) {
return matter.get().cast();
if (cap === MatteryCapability.MATTER) {
return matter.get().cast()
}
if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
return work_slots_handler.get().cast();
if (cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
return itemHandler.get().cast()
}
if (cap == MatteryCapability.MATTER_CELL) {
return cell_resolver.cast();
if (cap === MatteryCapability.MATTER_CELL) {
return resolverNode.cast()
}
}
return super.getCapability(cap, side);
return super.getCapability(cap, side)
}
@Override
protected Component getDefaultDisplayName() {
return MACHINE_NAME;
override fun getDefaultDisplayName(): Component {
return MACHINE_NAME
}
@Nullable
@Override
public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply) {
return new MatterBottlerMenu(containerID, inventory, this);
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
return MatterBottlerMenu(containerID, inventory, this)
}
@Override
public void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
nbt.put("work_slots", work_slots.serializeNBT());
nbt.putBoolean("work_flow", work_flow);
nbt.put("matter_capability", matter.serializeNBT());
override fun saveAdditional(nbt: CompoundTag) {
super.saveAdditional(nbt)
nbt["work_slots"] = container.serializeNBT()
nbt["work_flow"] = this.workFlow
nbt["matter_capability"] = matter.serializeNBT()
}
@Override
public void load(CompoundTag nbt) {
super.load(nbt);
work_slots.deserializeNBT(nbt.get("work_slots"));
work_flow = nbt.getBoolean("work_flow");
override fun load(nbt: CompoundTag) {
super.load(nbt)
container.deserializeNBT(nbt["work_slots"])
workFlow = nbt.getBoolean("work_flow")
if (nbt.get("matter_capability") instanceof CompoundTag _matter)
matter.deserializeNBT(_matter);
nbt.ifHas("matter_capability", CompoundTag::class.java) {
matter.deserializeNBT(it)
}
}
private static final Fraction EXTRACTION_TICKS = new Fraction(200);
init {
energy = MatteryMachineEnergyStorage(this, MatteryMachineEnergyStorage.MachineType.WORKER)
}
public float getWorkProgress() {
if (last_work_stack == null) {
return 0;
fun getWorkProgress(): Float {
if (lastWorkStack == null) {
return 0f
}
var cap = last_work_stack.getCapability(MatteryCapability.MATTER).resolve();
val resolver = lastWorkStack!!.getCapability(MatteryCapability.MATTER).resolve()
if (cap.isEmpty()) {
return 0;
if (resolver.isEmpty) {
return 0f
}
if (work_flow) {
if (cap.get().getMaxStoredMatter().minus(initial_capacity).compareTo(Fraction.ZERO) <= 0) {
return 0;
val cap = resolver.get()
if (this.workFlow) {
if (cap.maxStoredMatter - initialCapacity!! <= Fraction.ZERO) {
return 0f
}
return cap.get().getStoredMatter().minus(initial_capacity).div(cap.get().getMaxStoredMatter().minus(initial_capacity)).toFloat();
return ((cap.storedMatter - initialCapacity!!) / (cap.maxStoredMatter - initialCapacity!!)).toFloat()
}
if (initial_capacity.compareTo(Fraction.ZERO) <= 0) {
return 0;
if (initialCapacity!! <= Fraction.ZERO) {
return 0f
}
return Fraction.ONE.minus(cap.get().getStoredMatter().div(initial_capacity)).toFloat();
return (Fraction.ONE - cap.storedMatter / initialCapacity!!).toFloat()
}
public static <T extends BlockEntity> void tick(Level level, BlockPos blockPos, BlockState blockState, T t) {
if (t instanceof BlockEntityMatterBottler tile) {
tile.batteryChargeLoop();
fun tick() {
batteryChargeLoop()
if (tile.isBlockedByRedstone()) {
if (tile.getBlockState().getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.IDLE) {
level.setBlock(tile.getBlockPos(), tile.getBlockState().setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS);
}
return;
if (isBlockedByRedstone) {
if (blockState.getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.IDLE) {
level!!.setBlock(
blockPos,
blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE),
Block.UPDATE_CLIENTS
)
}
ItemStack work_stack = null;
IMatterHandler capability = null;
int align = tile.work_flow ? 0 : 3;
int work_slot = -1;
return
}
for (int i = align; i < align + 3; i++) {
var get = tile.work_slots.getItem(i);
var work_stack: ItemStack? = null
var capability: IMatterHandler? = null
val align = if (workFlow) 0 else 3
var work_slot = -1
val unexpectedDirection = if (workFlow) MatterDirection.EXTRACT else MatterDirection.RECEIVE
if (!get.isEmpty()) {
var cap = get.getCapability(MatteryCapability.MATTER).resolve();
for (i in align until align + 3) {
val itemStack = container.getItem(i)
if (cap.isPresent() && cap.get().getDirection() != (tile.work_flow ? IMatterHandler.MatterDirection.EXTRACT : IMatterHandler.MatterDirection.RECEIVE) && (tile.work_flow ? cap.get().getMissingMatter().compareTo(Fraction.ZERO) > 0 : cap.get().getStoredMatter().compareTo(Fraction.ZERO) > 0)) {
work_stack = get;
capability = cap.get();
work_slot = i;
break;
if (!itemStack.isEmpty) {
val cap = itemStack.getCapability(MatteryCapability.MATTER).resolve()
if (cap.isPresent && cap.get().direction != unexpectedDirection) {
if (this.workFlow && cap.get().missingMatter > Fraction.ZERO || !this.workFlow && cap.get().storedMatter > Fraction.ZERO) {
work_stack = itemStack
capability = cap.get()
work_slot = i
break
}
}
}
}
if (work_stack == null) {
tile.last_work_stack = null;
tile.initial_capacity = null;
} else if (work_stack != tile.last_work_stack) {
tile.last_work_stack = work_stack;
tile.initial_capacity = capability.getStoredMatter();
if (work_stack == null) {
lastWorkStack = null
initialCapacity = null
} else if (work_stack != lastWorkStack) {
lastWorkStack = work_stack
initialCapacity = capability!!.storedMatter
}
val graph = node.graph as MatterNetworkGraph?
if (capability != null) {
if (blockState.getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.WORKING) {
level!!.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.WORKING), Block.UPDATE_CLIENTS)
}
if (tile.work_flow) {
if (capability != null) {
if (tile.getBlockState().getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.WORKING) {
level.setBlock(tile.getBlockPos(), tile.getBlockState().setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.WORKING), Block.UPDATE_CLIENTS);
if (workFlow) {
if (matter.storedMatter < MATTER_EXCHANGE_RATE && graph != null) {
val extracted = graph.extractMatter(
matter.missingMatter.min(MATTER_EXCHANGE_RATE * EXTRACTION_TICKS, capability.missingMatter - matter.storedMatter), true
)
if (extracted > Fraction.ZERO) {
val received = matter.receiveMatterOuter(extracted, false)
graph.extractMatter(received, false)
}
}
if (tile.matter.getStoredMatter().compareTo(MATTER_EXCHANGE_RATE) < 0) {
if (tile.grid != null) {
var extracted = tile.grid.extractMatter(
tile.matter.getMissingMatter()
.min(MATTER_EXCHANGE_RATE.times(EXTRACTION_TICKS))
.min(capability.getMissingMatter().minus(tile.matter.getStoredMatter()))
, true);
if (matter.storedMatter > Fraction.ZERO) {
val energyExtracted = energy.extractEnergyInner(ENERGY_CONSUMPTION, true)
if (extracted.compareTo(Fraction.ZERO) > 0) {
var received = tile.matter.receiveMatterOuter(extracted, false);
tile.grid.extractMatter(received, false);
}
}
}
if (!energyExtracted.isZero()) {
val matter = capability.receiveMatterOuter(MATTER_EXCHANGE_RATE.min(matter.storedMatter) * (energyExtracted / ENERGY_CONSUMPTION), true)
if (tile.matter.getStoredMatter().compareTo(Fraction.ZERO) > 0) {
var energy = tile.energy.extractEnergyInner(ENERGY_CONSUMPTION, true);
if (!matter.isZero()) {
energy.extractEnergyInner(ENERGY_CONSUMPTION * matter / MATTER_EXCHANGE_RATE,false)
if (energy.compareTo(Fraction.ZERO) > 0) {
var matter = capability.receiveMatterOuter(MATTER_EXCHANGE_RATE.min(tile.matter.getStoredMatter()).times(energy.div(ENERGY_CONSUMPTION)), true);
capability.receiveMatterOuter(matter, false)
this.matter.extractMatterInner(matter, false)
if (matter.compareTo(Fraction.ZERO) > 0) {
tile.energy.extractEnergyInner(ENERGY_CONSUMPTION.times(matter.div(MATTER_EXCHANGE_RATE)), false);
capability.receiveMatterOuter(matter, false);
tile.matter.extractMatterInner(matter, false);
if (capability.getMissingMatter().compareTo(Fraction.ZERO) == 0) {
for (int i = 3; i < 6; i++) {
if (tile.work_slots.getItem(i).isEmpty()) {
tile.work_slots.setItem(work_slot, ItemStack.EMPTY);
tile.work_slots.setItem(i, work_stack);
break;
}
if (capability.missingMatter.isZero()) {
for (i in 3..5) {
if (container.getItem(i).isEmpty) {
container.setItem(work_slot, ItemStack.EMPTY)
container.setItem(i, work_stack!!)
break
}
}
}
}
}
} else {
if (tile.getBlockState().getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.IDLE) {
level.setBlock(tile.getBlockPos(), tile.getBlockState().setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS);
}
}
} else {
if (capability != null) {
if (tile.getBlockState().getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.WORKING) {
level.setBlock(tile.getBlockPos(), tile.getBlockState().setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.WORKING), Block.UPDATE_CLIENTS);
}
val energyExtracted = energy.extractEnergyInner(ENERGY_CONSUMPTION, true)
var energy = tile.energy.extractEnergyInner(ENERGY_CONSUMPTION, true);
if (!energyExtracted.isZero()) {
val matter = capability.extractMatterOuter(MATTER_EXCHANGE_RATE.min(matter.missingMatter) * energyExtracted / ENERGY_CONSUMPTION, true)
if (energy.compareTo(Fraction.ZERO) > 0) {
var matter = capability.extractMatterOuter(MATTER_EXCHANGE_RATE.min(tile.matter.getMissingMatter()).times(energy.div(ENERGY_CONSUMPTION)), true);
if (!matter.isZero()) {
this.energy.extractEnergyInner(ENERGY_CONSUMPTION * matter / MATTER_EXCHANGE_RATE,false)
if (matter.compareTo(Fraction.ZERO) > 0) {
tile.energy.extractEnergyInner(ENERGY_CONSUMPTION.times(matter.div(MATTER_EXCHANGE_RATE)), false);
capability.extractMatterOuter(matter, false);
tile.matter.receiveMatterInner(matter, false);
capability.extractMatterOuter(matter, false)
this.matter.receiveMatterInner(matter, false)
if (capability.getStoredMatter().compareTo(Fraction.ZERO) == 0) {
for (int i = 2; i >= 0; i--) {
if (tile.work_slots.getItem(i).isEmpty()) {
tile.work_slots.setItem(work_slot, ItemStack.EMPTY);
tile.work_slots.setItem(i, work_stack);
break;
}
if (capability.storedMatter.isZero()) {
for (i in 2 downTo 0) {
if (container.getItem(i).isEmpty) {
container.setItem(work_slot, ItemStack.EMPTY)
container.setItem(i, work_stack!!)
break
}
}
}
}
} else {
if (tile.getBlockState().getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.IDLE) {
level.setBlock(tile.getBlockPos(), tile.getBlockState().setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS);
}
}
if (tile.matter.getStoredMatter().compareTo(Fraction.ZERO) > 0 && tile.grid != null) {
var diff = tile.matter.extractMatterInner(tile.matter.getStoredMatter(), true);
var diff2 = tile.grid.softPushMatter(diff, true);
tile.matter.extractMatterInner(diff2, false);
tile.grid.softPushMatter(diff2, false);
}
}
} else {
level!!.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS)
}
if (!workFlow && !matter.storedMatter.isZero() && graph != null) {
val diff = matter.extractMatterInner(matter.storedMatter, true)
val diff2 = graph.receiveMatter(diff, true)
matter.extractMatterInner(diff2, false)
graph.receiveMatter(diff2, false)
}
}
}
companion object {
private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.matter_bottler")
private val MATTER_EXCHANGE_RATE = Fraction("0.04")
private val ENERGY_CONSUMPTION = Fraction(20)
private val EXTRACTION_TICKS = Fraction(200)
}
}

View File

@ -0,0 +1,71 @@
package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
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 ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.block.BlockMatterCable
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.GraphNodeListener
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
class BlockEntityMatterCable(p_155229_: BlockPos, p_155230_: BlockState) :
BlockEntity(Registry.BlockEntities.MATTER_CABLE, p_155229_, p_155230_), IMatterGraphNode, GraphNodeListener {
private var valid = true
private val node = Graph6Node<IMatterGraphNode>(this)
private val resolverNode = LazyOptional.of { this }
override fun getAsMatterNode(): Graph6Node<IMatterGraphNode> {
return node
}
override fun invalidateCaps() {
super.invalidateCaps()
valid = false
}
override fun reviveCaps() {
super.reviveCaps()
valid = true
}
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
if (valid) {
if (cap === MatteryCapability.MATTER_CELL)
return resolverNode.cast()
}
return super.getCapability(cap, side)
}
override fun setLevel(p_155231_: Level) {
super.setLevel(p_155231_)
if (p_155231_ is ServerLevel)
MatterNetworkGraph.discoverFull(this, node)
}
override fun onNeighbour(node: Graph6Node<*>, direction: Direction) {
val new_state = blockState.setValue(BlockMatterCable.MAPPING_CONNECTION_PROP[direction.ordinal], true)
if (new_state !== blockState) level!!.setBlock(blockPos, new_state, Block.UPDATE_CLIENTS)
}
override fun onUnNeighbour(node: Graph6Node<*>, direction: Direction) {
val new_state = blockState.setValue(BlockMatterCable.MAPPING_CONNECTION_PROP[direction.ordinal], false)
if (new_state !== blockState) level!!.setBlock(blockPos, new_state, Block.UPDATE_CLIENTS)
}
override fun setRemoved() {
super.setRemoved()
node.destroy(::MatterNetworkGraph)
}
}

View File

@ -1,279 +1,207 @@
package ru.dbotthepony.mc.otm.block.entity;
package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.world.entity.player.Inventory;
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.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import ru.dbotthepony.mc.otm.block.BlockBatteryBank;
import ru.dbotthepony.mc.otm.capability.matter.IMatterGridCell;
import ru.dbotthepony.mc.otm.core.Fraction;
import ru.dbotthepony.mc.otm.matter.MatterGrid;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler;
import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.container.MatteryContainer;
import ru.dbotthepony.mc.otm.menu.MatterCapacitorBankMenu;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.math.BigDecimal;
import java.util.Optional;
import net.minecraft.MethodsReturnNonnullByDefault
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.player.Inventory
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.Block
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.util.LazyOptional
import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.block.BlockBatteryBank
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler.MatterDirection
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.menu.MatterCapacitorBankMenu
import ru.dbotthepony.mc.otm.set
import javax.annotation.ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public class BlockEntityMatterCapacitorBank extends BlockEntityMattery implements IMatterGridCell {
public final IMatterHandler matter = new IMatterHandler() {
@Nonnull
@Override
public Fraction getStoredMatter() {
Fraction summ = Fraction.ZERO;
class BlockEntityMatterCapacitorBank(p_155229_: BlockPos, p_155230_: BlockState) :
BlockEntityMattery(Registry.BlockEntities.MATTER_CAPACITOR_BANK, p_155229_, p_155230_), IMatterGraphNode, IMatterHandler {
for (int i = 0; i < matter_container.getContainerSize(); i++) {
ItemStack stack = matter_container.getItem(i);
private val node = Graph6Node<IMatterGraphNode>(this)
private val resolverNode = LazyOptional.of { this }
if (!stack.isEmpty()) {
Optional<IMatterHandler> handler = stack.getCapability(MatteryCapability.MATTER).resolve();
override fun getAsMatterNode(): Graph6Node<IMatterGraphNode> {
return node
}
if (handler.isPresent()) {
summ = summ.plus(handler.get().getStoredMatter());
}
override fun getStoredMatter(): Fraction {
var summ = Fraction.ZERO
for (stack in matterContainer)
if (!stack.isEmpty)
stack.getCapability(MatteryCapability.MATTER).ifPresent {
summ += it.storedMatter
}
return summ
}
override fun getMaxStoredMatter(): Fraction {
var summ = Fraction.ZERO
for (stack in matterContainer)
if (!stack.isEmpty)
stack.getCapability(MatteryCapability.MATTER).ifPresent {
summ += it.maxStoredMatter
}
return summ
}
override fun receiveMatterOuter(howMuch: Fraction, simulate: Boolean): Fraction {
return receiveMatterInner(howMuch, simulate)
}
override fun receiveMatterInner(howMuch: Fraction, simulate: Boolean): Fraction {
var howMuch = howMuch
var summ = Fraction.ZERO
for (stack in matterContainer) {
if (!stack.isEmpty) {
stack.getCapability(MatteryCapability.MATTER).ifPresent {
val diff = it.receiveMatterOuter(howMuch, simulate)
summ += diff
howMuch -= diff
}
if (howMuch.isZero()) {
break
}
}
return summ;
}
@Nonnull
@Override
public Fraction getMaxStoredMatter() {
Fraction summ = Fraction.ZERO;
return summ
}
for (int i = 0; i < matter_container.getContainerSize(); i++) {
ItemStack stack = matter_container.getItem(i);
override fun extractMatterOuter(howMuch: Fraction, simulate: Boolean): Fraction {
return extractMatterInner(howMuch, simulate)
}
if (!stack.isEmpty()) {
Optional<IMatterHandler> handler = stack.getCapability(MatteryCapability.MATTER).resolve();
override fun extractMatterInner(howMuch: Fraction, simulate: Boolean): Fraction {
var howMuch = howMuch
var summ = Fraction.ZERO
if (handler.isPresent()) {
summ = summ.plus(handler.get().getMaxStoredMatter());
}
for (stack in matterContainer) {
if (!stack.isEmpty) {
stack.getCapability(MatteryCapability.MATTER).ifPresent {
val diff = it.extractMatterOuter(howMuch, simulate)
summ += diff
howMuch -= diff
}
if (howMuch.isZero()) {
break
}
}
return summ;
}
return summ
}
@Nonnull
@Override
public Fraction receiveMatterOuter(Fraction howMuch, boolean simulate) {
return receiveMatterInner(howMuch, simulate);
}
override fun getDirection(): MatterDirection {
return MatterDirection.BIDIRECTIONAL
}
@Nonnull
@Override
public Fraction receiveMatterInner(Fraction howMuch, boolean simulate) {
Fraction summ = Fraction.ZERO;
private var resolver = LazyOptional.of { this }
for (int i = 0; i < matter_container.getContainerSize(); i++) {
ItemStack stack = matter_container.getItem(i);
if (!stack.isEmpty()) {
Optional<IMatterHandler> handler = stack.getCapability(MatteryCapability.MATTER).resolve();
if (handler.isPresent()) {
var diff = handler.get().receiveMatterOuter(howMuch, simulate);
summ = summ.plus(diff);
howMuch = howMuch.minus(diff);
if (howMuch.compareTo(Fraction.ZERO) == 0) {
break;
}
}
}
}
return summ;
}
@Nonnull
@Override
public Fraction extractMatterOuter(Fraction howMuch, boolean simulate) {
return extractMatterInner(howMuch, simulate);
}
@Nonnull
@Override
public Fraction extractMatterInner(Fraction howMuch, boolean simulate) {
Fraction summ = Fraction.ZERO;
for (int i = 0; i < matter_container.getContainerSize(); i++) {
ItemStack stack = matter_container.getItem(i);
if (!stack.isEmpty()) {
Optional<IMatterHandler> handler = stack.getCapability(MatteryCapability.MATTER).resolve();
if (handler.isPresent()) {
var diff = handler.get().extractMatterOuter(howMuch, simulate);
summ = summ.plus(diff);
howMuch = howMuch.minus(diff);
if (howMuch.compareTo(Fraction.ZERO) == 0) {
break;
}
}
}
}
return summ;
}
@Nonnull
@Override
public MatterDirection getDirection() {
return MatterDirection.BIDIRECTIONAL;
}
};
private LazyOptional<IMatterHandler> resolver = LazyOptional.of(() -> matter);
public final MatteryContainer matter_container = new MatteryContainer(this::setChanged, 6 * 2) {
@Override
public void setChanged(int slot, ItemStack new_state, ItemStack old_state) {
super.setChanged(slot, new_state, old_state);
@JvmField
val matterContainer = object : MatteryContainer(this::setChangedLight, 6 * 2) {
override fun setChanged(slot: Int, new_state: ItemStack, old_state: ItemStack) {
super.setChanged(slot, new_state, old_state)
val level = level
if (level != null) {
var state = getBlockState();
var state = blockState
for (int i = 0; i < BlockBatteryBank.BATTERY_SLOTS_PROPS.length; i++) {
state = state.setValue(BlockBatteryBank.BATTERY_SLOTS_PROPS[i], getItem(i).getCapability(MatteryCapability.MATTER).isPresent());
for (i in BlockBatteryBank.BATTERY_SLOTS_PROPS.indices) {
state = state.setValue(
BlockBatteryBank.BATTERY_SLOTS_PROPS[i],
getItem(i).getCapability(MatteryCapability.MATTER).isPresent
)
}
if (state != getBlockState()) {
level.setBlock(getBlockPos(), state, Block.UPDATE_CLIENTS);
if (state !== blockState) {
level.setBlock(blockPos, state, Block.UPDATE_CLIENTS)
}
}
}
};
public BlockEntityMatterCapacitorBank(BlockPos p_155229_, BlockState p_155230_) {
super(Registry.BlockEntities.MATTER_CAPACITOR_BANK, p_155229_, p_155230_);
}
private final TranslatableComponent MACHINE_NAME = new TranslatableComponent("block.overdrive_that_matters.matter_capacitor_bank");
@Override
protected Component getDefaultDisplayName() {
return MACHINE_NAME;
companion object {
private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.matter_capacitor_bank")
}
@Override
public void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
nbt.put("matter_container", matter_container.serializeNBT());
override fun getDefaultDisplayName(): Component {
return MACHINE_NAME
}
@Override
public void load(CompoundTag nbt) {
matter_container.deserializeNBT(nbt.get("matter_container"));
super.load(nbt);
override fun saveAdditional(nbt: CompoundTag) {
super.saveAdditional(nbt)
nbt["matter_container"] = matterContainer.serializeNBT()
}
@Nullable
@Override
public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply) {
return new MatterCapacitorBankMenu(containerID, inventory, this);
override fun load(nbt: CompoundTag) {
matterContainer.deserializeNBT(nbt["matter_container"])
super.load(nbt)
}
private boolean valid = true;
@Override
public void invalidateCaps() {
super.invalidateCaps();
valid = false;
resolver.invalidate();
resolver_grid.invalidate();
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
return MatterCapacitorBankMenu(containerID, inventory, this)
}
@Override
public void reviveCaps() {
super.reviveCaps();
valid = true;
resolver = LazyOptional.of(() -> matter);
resolver_grid = LazyOptional.of(() -> this);
private var valid = true
override fun invalidateCaps() {
super.invalidateCaps()
valid = false
resolver.invalidate()
}
private LazyOptional<IMatterGridCell> resolver_grid = LazyOptional.of(() -> this);
override fun reviveCaps() {
super.reviveCaps()
valid = true
resolver = LazyOptional.of { this }
}
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
if (valid) {
if (cap == MatteryCapability.MATTER)
return resolver.cast();
if (cap == MatteryCapability.MATTER_CELL)
return resolver_grid.cast();
if (cap === MatteryCapability.MATTER) return resolver.cast()
if (cap === MatteryCapability.MATTER_CELL) return resolverNode.cast()
}
return super.getCapability(cap, side);
return super.getCapability(cap, side)
}
private MatterGrid grid;
@Nullable
@Override
public MatterGrid getMatterGrid() {
return grid;
override fun setRemoved() {
super.setRemoved()
node.destroy(::MatterNetworkGraph)
}
@Override
public void setRemoved() {
super.setRemoved();
override fun setLevel(p_155231_: Level) {
super.setLevel(p_155231_)
if (grid != null)
grid.remove(this);
if (p_155231_ is ServerLevel)
MatterNetworkGraph.discoverFull(this, node)
}
@Override
public void setLevel(Level p_155231_) {
super.setLevel(p_155231_);
if (!p_155231_.isClientSide)
MatterGrid.scheduleDiscoverNeighbours(this, getBlockPos(), p_155231_);
override fun getMatterHandler(): IMatterHandler {
return this
}
@Nullable
@Override
public IMatterHandler getMatterHandler() {
return valid ? matter : null;
}
@Nullable
@Override
public IPatternStorage getPatternStorage() {
return null;
}
@Override
public boolean isValidMatterCell() {
return valid;
}
@Override
public void setMatterGrid(MatterGrid grid) {
this.grid = grid;
}
}
}

View File

@ -0,0 +1,186 @@
package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.player.Inventory
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.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.BlockEntityMatteryWorker
import ru.dbotthepony.mc.otm.block.entity.worker.MachineJob
import ru.dbotthepony.mc.otm.block.entity.worker.MachineJobStatus
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler
import ru.dbotthepony.mc.otm.capability.matter.MatterHandlerCapability
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.matter.MatterRegistry
import ru.dbotthepony.mc.otm.menu.MatterDecomposerMenu
import ru.dbotthepony.mc.otm.set
class BlockEntityMatterDecomposer(pos: BlockPos, state: BlockState)
: BlockEntityMatteryWorker(Registry.BlockEntities.MATTER_DECOMPOSER, pos, state), IMatterGraphNode {
companion object {
private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.matter_decomposer")
private val BASE_CONSUMPTION = Fraction(240)
}
init {
energy = MatteryMachineEnergyStorage(
this,
MatteryMachineEnergyStorage.MachineType.WORKER,
Fraction(400000),
Fraction(2000),
Fraction(2000)
)
}
private var valid = true
private val node = Graph6Node<IMatterGraphNode>(this)
override fun getAsMatterNode(): Graph6Node<IMatterGraphNode> {
return node
}
@JvmField
val matter = MatterHandlerCapability(this::setChangedLight, IMatterHandler.MatterDirection.EXTRACT, Fraction("20"))
private var resolverMatter = LazyOptional.of { matter }
private var resolverNode = LazyOptional.of { this }
// вход, выход
@JvmField
val itemContainer = MatteryContainer(this::setChangedLight, 2)
private val itemHandler = LazyOptional.of<IItemHandler> {
itemContainer.handler(
{ slot: Int, stack: ItemStack? -> slot == 0 && MatterRegistry.canDecompose(stack) },
{ slot: Int, amount: Int, stack: ItemStack? -> slot == 1 })
}
override fun getDefaultDisplayName(): Component? {
return MACHINE_NAME
}
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
return MatterDecomposerMenu(containerID, inventory, this)
}
override fun saveAdditional(nbt: CompoundTag) {
super.saveAdditional(nbt)
nbt["work_slots"] = itemContainer.serializeNBT()
nbt["matter_capability"] = matter.serializeNBT()
}
override fun load(nbt: CompoundTag) {
super.load(nbt)
nbt.ifHas("matter_capability") {
if (it is CompoundTag)
matter.deserializeNBT(it)
}
nbt.ifHas("work_slots") {
itemContainer.deserializeNBT(it)
}
}
override fun reviveCaps() {
valid = true
super.reviveCaps()
resolverMatter = LazyOptional.of { matter }
}
override fun invalidateCaps() {
valid = false
super.invalidateCaps()
resolverMatter.invalidate()
}
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
if (valid) {
if (cap === MatteryCapability.MATTER) return resolverMatter.cast()
if (cap === MatteryCapability.MATTER_CELL) return resolverNode.cast()
if (cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return itemHandler.cast()
}
return super.getCapability(cap, side)
}
override fun onJobFinish(job: MachineJob): MachineJobStatus {
matter.receiveMatterInner(MatterRegistry.getMatterValue(job.stack()), false)
return MachineJobStatus()
}
override fun getNextJob(): MachineJob? {
val stack = itemContainer.getItem(0)
if (!stack.isEmpty) {
val copy = stack.copy()
copy.count = 1
if (MatterRegistry.canDecompose(copy)) {
val value = MatterRegistry.getMatterValue(copy)
if (value != Fraction.ZERO && matter.canReceiveAll(value)) {
stack.shrink(1)
return MachineJob(copy, value.toDouble() * 12500.0)
}
}
}
return null
}
override fun setRemoved() {
super.setRemoved()
node.destroy(::MatterNetworkGraph)
}
override fun setLevel(p_155231_: Level) {
super.setLevel(p_155231_)
if (p_155231_ is ServerLevel)
MatterNetworkGraph.discoverFull(this, node)
}
override fun getMatterHandler(): IMatterHandler {
return matter
}
override fun getBaseConsumption(): Fraction {
return BASE_CONSUMPTION
}
fun tick() {
batteryChargeLoop();
workerLoop();
val grid = node.graph as MatterNetworkGraph?
if (!matter.storedMatter.isZero() && grid != null) {
val diff = matter.extractMatterInner(matter.getStoredMatter(), true)
val diff2 = grid.receiveMatter(diff, true)
matter.extractMatterInner(diff2, false)
grid.receiveMatter(diff2, false)
}
}
}

View File

@ -1,276 +1,229 @@
package ru.dbotthepony.mc.otm.block.entity;
package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.capability.*;
import ru.dbotthepony.mc.otm.capability.matter.*;
import ru.dbotthepony.mc.otm.matter.MatterGrid;
import ru.dbotthepony.mc.otm.menu.MatterPanelMenu;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.*;
import java.util.stream.Collectors;
import net.minecraft.MethodsReturnNonnullByDefault
import javax.annotation.ParametersAreNonnullByDefault
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.capability.matter.IMatterTaskProvider
import ru.dbotthepony.mc.otm.menu.MatterPanelMenu
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraftforge.common.util.LazyOptional
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import java.util.HashMap
import java.util.UUID
import ru.dbotthepony.mc.otm.capability.matter.MatterTask
import java.util.stream.Collectors
import ru.dbotthepony.mc.otm.capability.matter.MatterTaskAllocation
import ru.dbotthepony.mc.otm.capability.matter.PatternState
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.Tag
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.level.Level
import net.minecraftforge.common.capabilities.Capability
import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import java.util.ArrayList
import java.util.List
import java.util.function.Consumer
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public class BlockEntityMatterPanel extends BlockEntityMattery implements IMatterGridCell, IMatterTaskProvider {
public BlockEntityMatterPanel(BlockPos p_155229_, BlockState p_155230_) {
super(Registry.BlockEntities.MATTER_PANEL, p_155229_, p_155230_);
class BlockEntityMatterPanel(p_155229_: BlockPos, p_155230_: BlockState) :
BlockEntityMattery(Registry.BlockEntities.MATTER_PANEL, p_155229_, p_155230_), IMatterGraphNode, IMatterTaskProvider {
private val listeners = ArrayList<MatterPanelMenu>()
private val node = Graph6Node<IMatterGraphNode>(this)
override fun getAsMatterNode(): Graph6Node<IMatterGraphNode> {
return node
}
private static final TranslatableComponent NAME = new TranslatableComponent("block.overdrive_that_matters.matter_panel");
private final ArrayList<MatterPanelMenu> listeners = new ArrayList<>();
public void attachMenu(MatterPanelMenu menu) {
listeners.add(menu);
fun attachMenu(menu: MatterPanelMenu) {
listeners.add(menu)
}
public void deatachMenu(MatterPanelMenu menu) {
listeners.remove(menu);
fun deatachMenu(menu: MatterPanelMenu) {
listeners.remove(menu)
}
@Override
protected Component getDefaultDisplayName() {
return NAME;
override fun getDefaultDisplayName(): Component {
return NAME
}
@Nullable
@Override
public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply) {
return new MatterPanelMenu(containerID, inventory, this);
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
return MatterPanelMenu(containerID, inventory, this)
}
private boolean valid = true;
private var valid = true
@Override
public void invalidateCaps() {
super.invalidateCaps();
valid = false;
resolver.invalidate();
override fun invalidateCaps() {
super.invalidateCaps()
valid = false
resolver.invalidate()
}
@Override
public void reviveCaps() {
super.reviveCaps();
valid = true;
resolver = LazyOptional.of(() -> this);
override fun reviveCaps() {
super.reviveCaps()
valid = true
resolver = LazyOptional.of { this }
}
private LazyOptional<BlockEntityMatterPanel> resolver = LazyOptional.of(() -> this);
private var resolver = LazyOptional.of { this }
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
if (valid && (cap == MatteryCapability.MATTER_CELL || cap == MatteryCapability.TASK))
return resolver.cast();
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
if (valid && (cap === MatteryCapability.MATTER_CELL || cap === MatteryCapability.TASK))
return resolver.cast()
return super.getCapability(cap, side);
return super.getCapability(cap, side)
}
private MatterGrid grid;
override fun setLevel(p_155231_: Level) {
super.setLevel(p_155231_)
@Override
public void setLevel(Level p_155231_) {
super.setLevel(p_155231_);
if (grid == null)
scheduleDiscoverNeighbours(p_155231_, getBlockPos());
if (p_155231_ is ServerLevel)
MatterNetworkGraph.discoverFull(this, node)
}
@Override
public void setRemoved() {
super.setRemoved();
if (level != null && !level.isClientSide && grid != null)
grid.remove(this);
override fun setRemoved() {
super.setRemoved()
node.destroy(::MatterNetworkGraph)
}
@Nullable
@Override
public MatterGrid getMatterGrid() {
return grid;
override fun getTaskHandler(): IMatterTaskProvider? {
return this
}
@Override
public boolean isValidMatterCell() {
return valid;
private val tasks = HashMap<UUID, MatterTask?>()
override fun getTasks(): Collection<MatterTask> {
return tasks.values.stream().filter { task: MatterTask? -> task!!.required() > 0 }.collect(Collectors.toList()) as Collection<MatterTask>
}
@Override
public void setMatterGrid(MatterGrid grid) {
this.grid = grid;
override fun getAllTasks(): Collection<MatterTask> {
return List.copyOf(tasks.values) as Collection<MatterTask>
}
@Nullable
@Override
public IMatterTaskProvider getTaskProvider() {
return this;
}
override fun allocateTask(simulate: Boolean): MatterTaskAllocation? {
val graph = node.graph as MatterNetworkGraph? ?: return null
private final HashMap<UUID, MatterTask> tasks = new HashMap<>();
for ((key, task) in tasks) {
if (task!!.required > 0) {
val getPattern = graph.getPattern(task.pattern!!)
@Nonnull
@Override
public Collection<MatterTask> getTasks() {
return tasks.values().stream().filter(task -> task.required() > 0).collect(Collectors.toList());
}
@Nonnull
@Override
public Collection<MatterTask> getAllTasks() {
return List.copyOf(tasks.values());
}
@Nullable
@Override
public MatterTaskAllocation allocateTask(boolean simulate) {
if (grid == null)
return null;
for (var entry : tasks.entrySet()) {
var task = entry.getValue();
if (task.required() > 0) {
var get_pattern = grid.getPattern(task.pattern());
if (get_pattern != null) {
if (getPattern != null) {
if (!simulate) {
var newer = task.shrinkRequired(1);
tasks.put(entry.getKey(), newer);
listeners.forEach(menu -> menu.taskUpdated(newer));
grid.onMatterTaskUpdated(newer, task);
setChanged();
val new = task.shrinkRequired(1)
tasks[key] = new
listeners.forEach { menu: MatterPanelMenu -> menu.taskUpdated(new) }
graph.onMatterTaskUpdated(new, task)
setChanged()
}
return new MatterTaskAllocation(task, get_pattern);
return MatterTaskAllocation(task, getPattern)
}
}
}
return null;
return null
}
@Override
public boolean notifyTaskCompletion(MatterTask task) {
var get_task = tasks.get(task.id());
override fun notifyTaskCompletion(task: MatterTask): Boolean {
var localTask = tasks[task.id] ?: return false
val oldTask = localTask
if (get_task == null) {
return false;
}
localTask = localTask.shrinkInProgress(1)
val graph = node.graph as MatterNetworkGraph?
var old_task = get_task;
get_task = get_task.shrinkInProgress(1);
if (get_task.required() <= 0 && get_task.in_progress() <= 0) {
tasks.remove(task.id());
if (grid != null)
grid.onMatterTaskCreated(task);
MatterTask finalGet_task1 = get_task;
listeners.forEach(menu -> menu.taskRemoved(finalGet_task1));
// Задача полностью выполнена
if (localTask.required <= 0 && localTask.in_progress <= 0) {
tasks.remove(task.id)
graph?.onMatterTaskCreated(task)
listeners.forEach { menu: MatterPanelMenu -> menu.taskRemoved(localTask) }
} else {
tasks.put(task.id(), get_task);
if (grid != null) {
grid.onMatterTaskUpdated(get_task, old_task);
}
MatterTask finalGet_task = get_task;
listeners.forEach(menu -> menu.taskUpdated(finalGet_task));
// Задача обновлена
tasks[task.id()] = localTask
graph?.onMatterTaskUpdated(localTask, oldTask)
listeners.forEach { menu: MatterPanelMenu -> menu.taskUpdated(localTask) }
}
setChanged();
return true;
setChanged()
return true
}
@Override
public void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
ListTag list = new ListTag();
override fun saveAdditional(nbt: CompoundTag) {
super.saveAdditional(nbt)
for (MatterTask task : tasks.values()) {
list.add(task.serializeNBT());
val list = ListTag()
for (task in tasks.values) {
list.add(task!!.serializeNBT())
}
nbt.put("tasks", list);
nbt.put("tasks", list)
}
@Override
public void load(CompoundTag nbt) {
super.load(nbt);
tasks.clear();
override fun load(nbt: CompoundTag) {
super.load(nbt)
tasks.clear()
val list = nbt.getList("tasks", Tag.TAG_COMPOUND.toInt())
ListTag list = nbt.getList("tasks", Tag.TAG_COMPOUND);
for (Tag tag : list) {
MatterTask task = MatterTask.deserializeNBT(tag);
for (tag in list) {
val task = MatterTask.deserializeNBT(tag)
if (task != null) {
tasks.put(task.id(), task);
tasks[task.id()] = task
}
}
}
@Nullable
@Override
public MatterTask getTask(UUID id) {
return tasks.get(id);
override fun getTask(id: UUID): MatterTask? {
return tasks[id]
}
public void removeTask(UUID id) {
var task = tasks.get(id);
fun removeTask(id: UUID) {
val task = tasks[id] ?: return
tasks.remove(id)
if (task == null)
return;
(node.graph as MatterNetworkGraph?)?.onMatterTaskRemoved(task)
tasks.remove(id);
if (grid != null)
grid.onMatterTaskRemoved(task);
listeners.forEach(menu -> menu.taskRemoved(task));
setChanged();
listeners.forEach { menu: MatterPanelMenu -> menu.taskRemoved(task) }
setChanged()
}
public void removeTask(PatternState state) {
removeTask(state.id());
fun removeTask(state: PatternState) = removeTask(state.id)
fun addTask(state: PatternState, how_much: Int): MatterTask {
val task = MatterTask(UUID.randomUUID(), state.id, state.item, 0, 0, how_much)
tasks[task.id()] = task
(node.graph as MatterNetworkGraph?)?.onMatterTaskCreated(task)
listeners.forEach { menu: MatterPanelMenu -> menu.taskUpdated(task) }
setChanged()
return task
}
public MatterTask addTask(PatternState state, int how_much) {
var task = new MatterTask(UUID.randomUUID(), state.id(), state.item(), 0, 0, how_much);
tasks.put(task.id(), task);
override fun dropAllTasks() {
val graph = node.graph as MatterNetworkGraph?
if (grid != null)
grid.onMatterTaskCreated(task);
for (task in tasks.values) {
graph?.onMatterTaskRemoved(task!!)
listeners.forEach { menu: MatterPanelMenu -> menu.taskUpdated(task!!) }
}
listeners.forEach(menu -> menu.taskUpdated(task));
setChanged();
return task;
tasks.clear()
}
@Override
public void dropAllTasks() {
tasks.clear();
companion object {
private val NAME = TranslatableComponent("block.overdrive_that_matters.matter_panel")
}
}
}

View File

@ -1,278 +1,236 @@
package ru.dbotthepony.mc.otm.block.entity;
package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.world.entity.player.Inventory;
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.state.BlockState;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler;
import ru.dbotthepony.mc.otm.Registry;
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;
import ru.dbotthepony.mc.otm.block.entity.worker.WorkTickContext;
import ru.dbotthepony.mc.otm.capability.*;
import ru.dbotthepony.mc.otm.capability.matter.*;
import ru.dbotthepony.mc.otm.container.MatteryContainer;
import ru.dbotthepony.mc.otm.container.MatteryContainerHandler;
import ru.dbotthepony.mc.otm.core.Fraction;
import ru.dbotthepony.mc.otm.matter.MatterGrid;
import ru.dbotthepony.mc.otm.matter.MatterRegistry;
import ru.dbotthepony.mc.otm.menu.MatterReplicatorMenu;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.math.BigDecimal;
import net.minecraft.MethodsReturnNonnullByDefault
import javax.annotation.ParametersAreNonnullByDefault
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.block.entity.worker.BlockEntityMatteryWorker
import ru.dbotthepony.mc.otm.capability.matter.MatterHandlerCapability
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler
import ru.dbotthepony.mc.otm.container.MatteryContainer
import net.minecraft.world.item.ItemStack
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import ru.dbotthepony.mc.otm.menu.MatterReplicatorMenu
import ru.dbotthepony.mc.otm.block.entity.worker.MachineJob
import ru.dbotthepony.mc.otm.block.entity.worker.MachineJobStatus
import ru.dbotthepony.mc.otm.capability.matter.MatterTask
import ru.dbotthepony.mc.otm.capability.matter.PatternState
import ru.dbotthepony.mc.otm.matter.MatterRegistry
import ru.dbotthepony.mc.otm.block.entity.worker.WorkTickContext
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component
import net.minecraftforge.common.util.LazyOptional
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import net.minecraftforge.items.CapabilityItemHandler
import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage
import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.level.Level
import net.minecraftforge.common.capabilities.Capability
import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.set
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public class BlockEntityMatterReplicator extends BlockEntityMatteryWorker implements IMatterGridCell {
public BlockEntityMatterReplicator(BlockPos p_155229_, BlockState p_155230_) {
super(Registry.BlockEntities.MATTER_REPLICATOR, p_155229_, p_155230_);
energy = new MatteryMachineEnergyStorage(this, MatteryMachineEnergyStorage.MachineType.WORKER, new Fraction(200_000), new Fraction(4000), new Fraction(4000));
class BlockEntityMatterReplicator(p_155229_: BlockPos, p_155230_: BlockState) :
BlockEntityMatteryWorker(Registry.BlockEntities.MATTER_REPLICATOR, p_155229_, p_155230_), IMatterGraphNode {
private val node = Graph6Node<IMatterGraphNode>(this)
private val resolverNode = LazyOptional.of { this }
override fun getAsMatterNode(): Graph6Node<IMatterGraphNode> {
return node
}
public final MatterHandlerCapability matter = new MatterHandlerCapability(this::setChanged, IMatterHandler.MatterDirection.RECEIVE, new Fraction(2));
@JvmField
val matter = MatterHandlerCapability(this::setChangedLight, IMatterHandler.MatterDirection.RECEIVE, Fraction(2))
// обычные запросы
public final MatteryContainer regular_slots = new MatteryContainer(this::setChanged, 3);
@JvmField
val regularSlots = MatteryContainer(this::setChangedLight, 3)
// запросы от matter replicator interface
public final MatteryContainer reserved_slots = new MatteryContainer(this::setChanged, 3);
// запросы от matter replicator interface?
val reservedSlots = MatteryContainer(this::setChangedLight, 3)
private final MatteryContainerHandler slots_handler = regular_slots.handler((slot, stack) -> false);
private val itemHandler = regularSlots.handler { slot: Int, stack: ItemStack? -> false }
private static final TranslatableComponent NAME = new TranslatableComponent("block.overdrive_that_matters.matter_replicator");
private static final Fraction BASE_CONSUMPTION = new Fraction(400);
@Override
protected Component getDefaultDisplayName() {
return NAME;
override fun getDefaultDisplayName(): Component {
return NAME
}
@Nullable
@Override
public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply) {
return new MatterReplicatorMenu(containerID, inventory, this);
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
return MatterReplicatorMenu(containerID, inventory, this)
}
@Nonnull
@Override
protected Fraction getBaseConsumption() {
return BASE_CONSUMPTION;
override fun getBaseConsumption(): Fraction {
return BASE_CONSUMPTION
}
@Nonnull
@Override
protected MachineJobStatus onJobFinish(MachineJob job) {
if (!regular_slots.fullyAddItem(job.stack())) {
return new MachineJobStatus(false, 20);
override fun onJobFinish(job: MachineJob): MachineJobStatus {
if (!regularSlots.fullyAddItem(job.stack())) {
return MachineJobStatus(false, 20)
}
if (grid != null) {
grid.notifyTaskCompletion(MatterTask.deserializeNBT(job.data().get("task")));
}
return new MachineJobStatus();
(node.graph as MatterNetworkGraph?)?.notifyTaskCompletion(MatterTask.deserializeNBT(job.data["task"])!!)
return MachineJobStatus()
}
@Override
public void onMatterTaskCreated(MatterTask task) {
is_idling = false;
override fun onMatterTaskCreated(task: MatterTask) {
is_idling = false
}
@Override
public void onMatterTaskUpdated(MatterTask new_state, MatterTask old_state) {
is_idling = false;
override fun onMatterTaskUpdated(new_state: MatterTask, old_state: MatterTask) {
is_idling = false
}
@Override
public void onPatternAdded(PatternState state) {
is_idling = false;
override fun onPatternAdded(state: PatternState) {
is_idling = false
}
@Override
public void setRemoved() {
super.setRemoved();
if (level != null && !level.isClientSide && grid != null)
grid.remove(this);
override fun setRemoved() {
super.setRemoved()
node.destroy(::MatterNetworkGraph)
}
private static final double TICKS_PER_MTU = 20_000d;
private static final Fraction TICKS_PER_MTU_BD = new Fraction(20_000);
private static final double MTU_PER_TICK = 1d / 20_000d;
private static final Fraction MTU_PER_TICK_BD = Fraction.ONE.div(TICKS_PER_MTU_BD);
override fun setLevel(p_155231_: Level) {
super.setLevel(p_155231_)
@Override
public void setLevel(Level p_155231_) {
super.setLevel(p_155231_);
if (grid == null)
scheduleDiscoverNeighbours(p_155231_, getBlockPos());
if (p_155231_ is ServerLevel)
MatterNetworkGraph.discoverFull(this, node)
}
@Nullable
@Override
protected MachineJob getNextJob() {
if (grid == null)
return null;
MatterTaskAllocation allocation = grid.allocateTask(false);
if (allocation == null)
return null;
ItemStack stack = allocation.task().stack(1);
override fun getNextJob(): MachineJob? {
val graph = node.graph as MatterNetworkGraph? ?: return null
val allocation = graph.allocateTask(false) ?: return null
val stack = allocation.task().stack(1)
// ????????
if (!MatterRegistry.hasMatterValue(stack))
return null;
if (!MatterRegistry.hasMatterValue(stack)) return null
val job = MachineJob(stack, MatterRegistry.getMatterValue(stack).toDouble() * TICKS_PER_MTU)
MachineJob job = new MachineJob(stack, MatterRegistry.getMatterValue(stack).toDouble() * TICKS_PER_MTU);
job.data["task"] = allocation.task.serializeNBT()
if (allocation.pattern != null) job.data["pattern"] = allocation.pattern!!.serializeNBT()
job.data().put("task", allocation.task().serializeNBT());
if (allocation.pattern() != null)
job.data().put("pattern", allocation.pattern().serializeNBT());
return job;
return job
}
private static final Fraction DRAIN_MULT = new Fraction(200);
override fun onWorkTick(context: WorkTickContext): MachineJobStatus {
val drainPerTick = MTU_PER_TICK_BD.times(context.work_speed())
val graph = node.graph as MatterNetworkGraph? ?: return MachineJobStatus(false, 20)
@Override
protected MachineJobStatus onWorkTick(WorkTickContext context) {
var drain_per_tick = MTU_PER_TICK_BD.times(context.work_speed());
if (matter.extractMatterInner(drain_per_tick, true).compareTo(drain_per_tick) < 0) {
if (matter.extractMatterInner(drainPerTick, true) < drainPerTick) {
// в машине недостаточно материи
if (grid == null)
return new MachineJobStatus(false, 20);
if (drain_per_tick.compareTo(matter.getMaxStoredMatter()) > 0) {
if (drainPerTick > matter.maxStoredMatter) {
// в тик требуется больше материи, чем её может хранить репликатор
var to_extract = drain_per_tick.minus(matter.extractMatterInner(drain_per_tick, true));
var drain = grid.extractMatter(to_extract, true);
val toExtract = drainPerTick - matter.extractMatterInner(drainPerTick, true)
val drain = graph.extractMatter(toExtract, true)
if (drain.compareTo(to_extract) < 0) {
if (drain < toExtract) {
// недостаточно материи в сети
return new MachineJobStatus(false, 200);
return MachineJobStatus(false, 200)
}
// достаточно материи в сети + внутри машины
matter.extractMatterInner(drain_per_tick, false);
grid.extractMatter(drain, false);
return new MachineJobStatus();
matter.extractMatterInner(drainPerTick, false)
graph.extractMatter(drain, false)
return MachineJobStatus()
} else {
// в тик требуется меньше материи, чем её может хранить репликатор
// примем из сети недостающее количество бака материи, или 200 тиков репликации, что меньше
var to_extract = matter.getMissingMatter().min(drain_per_tick.times(DRAIN_MULT));
var drain = grid.extractMatter(to_extract, true);
val toExtract =
matter.missingMatter.min(drainPerTick.times(DRAIN_MULT))
if (drain.compareTo(Fraction.ZERO) == 0) {
val drain = graph.extractMatter(toExtract, true)
if (drain.isZero()) {
// в сети нет материи
return new MachineJobStatus(false, 200);
return MachineJobStatus(false, 200)
}
var received = matter.receiveMatterOuter(drain, false);
grid.extractMatter(received, false);
val received = matter.receiveMatterOuter(drain, false)
graph.extractMatter(received, false)
// получили материю, проверяем возможность работы
if (matter.extractMatterInner(drain_per_tick, false).compareTo(drain_per_tick) >= 0) {
return new MachineJobStatus();
if (matter.extractMatterInner(drainPerTick, false) >= drainPerTick) {
return MachineJobStatus()
} else {
// :(
return new MachineJobStatus(false, 200);
return MachineJobStatus(false, 200)
}
}
}
// в машине достаточно материи
matter.extractMatterInner(drain_per_tick, false);
return new MachineJobStatus();
matter.extractMatterInner(drainPerTick, false)
return MachineJobStatus()
}
@Override
public void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
nbt.put("regular_slots", regular_slots.serializeNBT());
nbt.put("reserved_slots", reserved_slots.serializeNBT());
nbt.put("matter_capability", matter.serializeNBT());
override fun saveAdditional(nbt: CompoundTag) {
super.saveAdditional(nbt)
nbt["regular_slots"] = regularSlots.serializeNBT()
nbt["reserved_slots"] = reservedSlots.serializeNBT()
nbt["matter_capability"] = matter.serializeNBT()
}
@Override
public void load(CompoundTag nbt) {
super.load(nbt);
regular_slots.deserializeNBT(nbt.get("regular_slots"));
reserved_slots.deserializeNBT(nbt.get("reserved_slots"));
override fun load(nbt: CompoundTag) {
super.load(nbt)
regularSlots.deserializeNBT(nbt["regular_slots"])
reservedSlots.deserializeNBT(nbt["reserved_slots"])
if (nbt.get("matter_capability") instanceof CompoundTag tag)
matter.deserializeNBT(tag);
nbt.ifHas("matter_capability", CompoundTag::class.java) {
matter.deserializeNBT(it)
}
}
private boolean valid = true;
private var valid = true
@Override
public void invalidateCaps() {
super.invalidateCaps();
valid = false;
slots_handler.invalidate();
resolver_self.invalidate();
override fun invalidateCaps() {
super.invalidateCaps()
valid = false
itemHandler.invalidate()
}
@Override
public void reviveCaps() {
super.reviveCaps();
valid = true;
slots_handler.revive();
resolver_self = LazyOptional.of(() -> this);
override fun reviveCaps() {
super.reviveCaps()
valid = true
itemHandler.revive()
}
private LazyOptional<BlockEntityMatterReplicator> resolver_self = LazyOptional.of(() -> this);
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
if (valid) {
if (cap == MatteryCapability.MATTER_CELL)
return resolver_self.cast();
if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
return slots_handler.get().cast();
if (cap === MatteryCapability.MATTER_CELL) return resolverNode.cast()
if (cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return itemHandler.get().cast()
}
return super.getCapability(cap, side);
return super.getCapability(cap, side)
}
private MatterGrid grid;
@Nullable
@Override
public MatterGrid getMatterGrid() {
return grid;
init {
energy = MatteryMachineEnergyStorage(
this,
MatteryMachineEnergyStorage.MachineType.WORKER,
Fraction(200000),
Fraction(4000),
Fraction(4000)
)
}
@Override
public boolean isValidMatterCell() {
return valid;
companion object {
private val NAME = TranslatableComponent("block.overdrive_that_matters.matter_replicator")
private val BASE_CONSUMPTION = Fraction(400)
private const val TICKS_PER_MTU = 20000.0
private val TICKS_PER_MTU_BD = Fraction(20000)
private const val MTU_PER_TICK = 1.0 / 20000.0
private val MTU_PER_TICK_BD = Fraction.ONE.div(TICKS_PER_MTU_BD)
private val DRAIN_MULT = Fraction(200)
}
@Override
public void setMatterGrid(MatterGrid grid) {
this.grid = grid;
}
}
}

View File

@ -1,267 +1,208 @@
package ru.dbotthepony.mc.otm.block.entity;
package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.world.entity.player.Inventory;
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 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;
import ru.dbotthepony.mc.otm.capability.*;
import ru.dbotthepony.mc.otm.capability.matter.*;
import ru.dbotthepony.mc.otm.container.MatteryContainerHandler;
import ru.dbotthepony.mc.otm.core.Fraction;
import ru.dbotthepony.mc.otm.matter.MatterGrid;
import ru.dbotthepony.mc.otm.matter.MatterRegistry;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.container.MatteryContainer;
import ru.dbotthepony.mc.otm.menu.MatterScannerMenu;
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.player.Inventory
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.state.BlockState
import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.items.CapabilityItemHandler
import ru.dbotthepony.mc.otm.Registry
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
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.*
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.matter.MatterRegistry
import ru.dbotthepony.mc.otm.menu.MatterScannerMenu
import java.util.*
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.UUID;
class BlockEntityMatterScanner(p_155229_: BlockPos, p_155230_: BlockState) :
BlockEntityMatteryWorker(Registry.BlockEntities.MATTER_SCANNER, p_155229_, p_155230_), IMatterGraphNode {
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public class BlockEntityMatterScanner extends BlockEntityMatteryWorker implements IMatterGridCell {
private static final TranslatableComponent NAME = new TranslatableComponent("block.overdrive_that_matters.matter_scanner");
val input_slot = MatteryContainer(this::setChanged, 1)
public final MatteryContainer input_slot = new MatteryContainer(this::setChanged, 1);
private val inputHandler = input_slot.handler(
{ slot: Int, stack: ItemStack? -> MatterRegistry.canDecompose(stack) },
{ slot: Int, amount: Int, stack: ItemStack? -> is_idling }
)
private final MatteryContainerHandler input_handler = input_slot.handler(
(slot, stack) -> MatterRegistry.canDecompose(stack),
(slot, amount, stack) -> is_idling
);
public BlockEntityMatterScanner(BlockPos p_155229_, BlockState p_155230_) {
super(Registry.BlockEntities.MATTER_SCANNER, p_155229_, p_155230_);
energy = new MatteryMachineEnergyStorage(this, MatteryMachineEnergyStorage.MachineType.WORKER, new Fraction(40000), new Fraction(400), new Fraction(400));
// IMatterGraphNode
override fun getAsMatterNode(): Graph6Node<IMatterGraphNode> {
return matterNode
}
private boolean valid = true;
override fun onPatternAdded(state: PatternState) {
is_idling = false
}
private LazyOptional<IMatterGridCell> resolver_grid = LazyOptional.of(() -> this);
override fun onPatternRemoved(state: PatternState) {
is_idling = false
}
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
override fun onPatternUpdated(new_state: PatternState, old_state: PatternState) {
is_idling = false
}
// /IMatterGraphNode
private var valid = true
private val matterNode: Graph6Node<IMatterGraphNode> = Graph6Node(this)
private var resolverNode = LazyOptional.of { this }
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
if (valid) {
if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
return input_handler.get().cast();
if (cap == MatteryCapability.MATTER_CELL)
return resolver_grid.cast();
if (cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return inputHandler.get().cast()
//if (cap === MatteryCapability.MATTER_CELL) return resolver_grid.cast()
if (cap == MatteryCapability.MATTER_CELL) return resolverNode.cast()
}
return super.getCapability(cap, side);
return super.getCapability(cap, side)
}
@Override
public void invalidateCaps() {
super.invalidateCaps();
valid = false;
input_handler.invalidate();
resolver_grid.invalidate();
override fun invalidateCaps() {
super.invalidateCaps()
valid = false
inputHandler.invalidate()
resolverNode.invalidate()
matterNode.destroy(::MatterNetworkGraph)
}
@Override
public void reviveCaps() {
super.reviveCaps();
valid = true;
input_handler.revive();
resolver_grid = LazyOptional.of(() -> this);
override fun reviveCaps() {
super.reviveCaps()
valid = true
inputHandler.revive()
resolverNode = LazyOptional.of { this }
}
@Override
public void onPatternAdded(PatternState state) {
is_idling = false;
override fun setRemoved() {
super.setRemoved()
matterNode.destroy(::MatterNetworkGraph)
}
@Override
public void onPatternRemoved(PatternState state) {
is_idling = false;
override fun getDefaultDisplayName(): Component {
return NAME
}
@Override
public void onPatternUpdated(PatternState new_state, PatternState old_state) {
is_idling = false;
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu? {
return MatterScannerMenu(containerID, inventory, this)
}
@Override
public void setRemoved() {
super.setRemoved();
if (level != null && !level.isClientSide && grid != null)
grid.remove(this);
override fun saveAdditional(nbt: CompoundTag) {
super.saveAdditional(nbt)
nbt.put("work_slots", input_slot.serializeNBT())
}
@Override
public void onNeighbourMatterCell(Level level, BlockPos pos, Direction direction, IMatterGridCell cell, BlockEntity entity) {
is_idling = false;
override fun load(nbt: CompoundTag) {
input_slot.deserializeNBT(nbt["work_slots"])
super.load(nbt)
}
@Override
protected Component getDefaultDisplayName() {
return NAME;
override fun getBaseConsumption(): Fraction {
return BASE_CONSUMPTION
}
@Nullable
@Override
public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply) {
return new MatterScannerMenu(containerID, inventory, this);
}
override fun onJobFinish(job: MachineJob): MachineJobStatus {
val grid = matterNode.graph as MatterNetworkGraph? ?: return MachineJobStatus(false, 100)
@Override
public void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
nbt.put("work_slots", input_slot.serializeNBT());
}
val stack = job.stack()
if (stack.isEmpty || !MatterRegistry.hasMatterValue(stack)) return MachineJobStatus()
@Override
public void load(CompoundTag nbt) {
input_slot.deserializeNBT(nbt.get("work_slots"));
super.load(nbt);
}
val get_state = grid.findPatterns(stack.item)
var find_state: PatternState? = null
private static final Fraction BASE_CONSUMPTION = new Fraction("40");
@Override
@Nonnull
protected Fraction getBaseConsumption() {
return BASE_CONSUMPTION;
}
@Nonnull
@Override
protected MachineJobStatus onJobFinish(MachineJob job) {
if (grid == null)
return new MachineJobStatus(false, 100);
ItemStack stack = job.stack();
if (stack.isEmpty() || !MatterRegistry.hasMatterValue(stack))
return new MachineJobStatus();
Collection<PatternState> get_state = grid.findPatterns(stack.getItem());
PatternState find_state = null;
for (PatternState state : get_state) {
if (state.item() == stack.getItem()) {
if (find_state == null && state.research_percent() < 1d) {
find_state = state;
for (state in get_state) {
if (state.item() === stack.item) {
if (find_state == null && state.research_percent() < 1.0) {
find_state = state
} else if (find_state != null && find_state.research_percent() < state.research_percent()) {
find_state = state;
find_state = state
}
}
}
PatternState new_state;
val new_state =
if (find_state != null) {
PatternState(find_state.id(), stack.item, find_state.research_percent() + 0.2)
} else {
PatternState(UUID.randomUUID(), stack.item, 0.2)
}
if (find_state != null) {
new_state = new PatternState(find_state.id(), stack.getItem(), find_state.research_percent() + 0.2d);
if (grid.insertPattern(new_state, false, false).status != PatternInsertStatus.Status.FAIL) {
return MachineJobStatus()
} else {
new_state = new PatternState(UUID.randomUUID(), stack.getItem(), 0.2d);
return MachineJobStatus(false, 200)
}
if (grid.insertPattern(new_state, false, false).status() != PatternInsertStatus.Status.FAIL) {
return new MachineJobStatus();
}
return new MachineJobStatus(false, 200);
}
@Nullable
@Override
protected MachineJob getNextJob() {
if (grid == null)
return null;
override fun getNextJob(): MachineJob? {
val grid = matterNode.graph as MatterNetworkGraph? ?: return null
ItemStack stack = input_slot.getItem(0);
val stack = input_slot.getItem(0)
if (stack.isEmpty || !MatterRegistry.canDecompose(stack)) return null
if (stack.isEmpty() || !MatterRegistry.canDecompose(stack))
return null;
val getState = grid.findPatterns(stack.item)
var findState: PatternState? = null
Collection<PatternState> get_state = grid.findPatterns(stack.getItem());
PatternState find_state = null;
for (PatternState state : get_state) {
if (state.item() == stack.getItem() && state.research_percent() < 1d) {
find_state = state;
} else if (state.item() == stack.getItem() && state.research_percent() >= 1d) {
return null;
for (state in getState) {
if (state.item() === stack.item && state.research_percent() < 1.0) {
findState = state
} else if (state.item() === stack.item && state.research_percent() >= 1.0) {
return null
}
}
PatternState new_state;
val new_state: PatternState =
if (findState != null) {
PatternState(findState.id, stack.item, findState.research_percent + 0.2)
} else {
PatternState(UUID.randomUUID(), stack.item, 0.2)
}
if (find_state != null) {
new_state = new PatternState(find_state.id(), stack.getItem(), find_state.research_percent() + 0.2d);
} else {
new_state = new PatternState(UUID.randomUUID(), stack.getItem(), 0.2d);
if (grid.insertPattern(new_state, false, true).status != PatternInsertStatus.Status.FAIL) {
val copy = stack.copy()
copy.count = 1
stack.shrink(1)
input_slot.setChanged()
return MachineJob(copy, MatterRegistry.getMatterValue(copy).toDouble() * 35000.0)
}
if (grid.insertPattern(new_state, false, true).status() != PatternInsertStatus.Status.FAIL) {
ItemStack copy = stack.copy();
copy.setCount(1);
stack.shrink(1);
input_slot.setChanged();
return new MachineJob(copy, MatterRegistry.getMatterValue(copy).toDouble() * 35_000d);
return null
}
init {
energy = MatteryMachineEnergyStorage(
this,
MatteryMachineEnergyStorage.MachineType.WORKER,
Fraction(40000),
Fraction(400),
Fraction(400)
)
}
override fun setLevel(p_155231_: Level) {
super.setLevel(p_155231_)
if (p_155231_ is ServerLevel) {
MatterNetworkGraph.discoverFull(this, matterNode)
}
return null;
}
@Nullable
@Override
public IPatternStorage getPatternStorage() {
return null;
companion object {
private val NAME = TranslatableComponent("block.overdrive_that_matters.matter_scanner")
private val BASE_CONSUMPTION = Fraction("40")
}
private MatterGrid grid;
@Override
public void setLevel(Level p_155231_) {
super.setLevel(p_155231_);
if (grid == null)
scheduleDiscoverNeighbours(p_155231_, getBlockPos());
}
@Nullable
@Override
public MatterGrid getMatterGrid() {
return grid;
}
@Nullable
@Override
public IMatterHandler getMatterHandler() {
return null;
}
@Override
public boolean isValidMatterCell() {
return valid;
}
@Override
public void setMatterGrid(MatterGrid grid) {
this.grid = grid;
}
}
}

View File

@ -1,243 +1,214 @@
package ru.dbotthepony.mc.otm.block.entity;
package ru.dbotthepony.mc.otm.block.entity
import com.google.common.collect.ImmutableList;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.world.entity.player.Inventory;
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.Block;
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.BlockPatternStorage;
import ru.dbotthepony.mc.otm.capability.*;
import ru.dbotthepony.mc.otm.capability.matter.*;
import ru.dbotthepony.mc.otm.container.MatteryContainerHandler;
import ru.dbotthepony.mc.otm.matter.MatterGrid;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.container.MatteryContainer;
import ru.dbotthepony.mc.otm.menu.PatternStorageMenu;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.ArrayList;
import java.util.Collection;
import javax.annotation.ParametersAreNonnullByDefault
import net.minecraft.core.BlockPos
import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage
import ru.dbotthepony.mc.otm.container.MatteryContainer
import java.lang.Runnable
import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.matter.PatternState
import ru.dbotthepony.mc.otm.block.BlockPatternStorage
import net.minecraft.nbt.CompoundTag
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.items.CapabilityItemHandler
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import ru.dbotthepony.mc.otm.menu.PatternStorageMenu
import net.minecraft.MethodsReturnNonnullByDefault
import net.minecraft.core.Direction
import net.minecraft.network.chat.Component
import ru.dbotthepony.mc.otm.capability.matter.PatternInsertStatus
import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraftforge.common.capabilities.Capability
import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.set
import java.util.ArrayList
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public class BlockEntityPatternStorage extends BlockEntityMattery implements IMatterGridCell, IPatternStorage {
public BlockEntityPatternStorage(BlockPos p_155229_, BlockState p_155230_) {
super(Registry.BlockEntities.PATTERN_STORAGE, p_155229_, p_155230_);
}
class BlockEntityPatternStorage(p_155229_: BlockPos, p_155230_: BlockState) :
BlockEntityMattery(Registry.BlockEntities.PATTERN_STORAGE, p_155229_, p_155230_), IMatterGraphNode, IPatternStorage {
private val node = Graph6Node<IMatterGraphNode>(this)
private val resolverPatterns = LazyOptional.of { this }
private val resolverNode = LazyOptional.of { this }
@JvmField
val patterns: MatteryContainer = object : MatteryContainer(Runnable { this.setChanged() }, 8) {
override fun setChanged(slot: Int, new_state: ItemStack, old_state: ItemStack) {
val grid = node.graph as MatterNetworkGraph?
public final MatteryContainer patterns = new MatteryContainer(this::setChanged, 8) {
@Override
public void setChanged(int slot, ItemStack new_state, ItemStack old_state) {
if (grid != null && !ItemStack.isSameItemSameTags(new_state, old_state)) {
if (!old_state.isEmpty()) {
old_state.getCapability(MatteryCapability.PATTERN).ifPresent(cap -> cap.getStoredPatterns().forEach(grid::onPatternRemoved));
if (!old_state.isEmpty) {
old_state.getCapability(MatteryCapability.PATTERN).ifPresent { cap: IPatternStorage ->
cap.storedPatterns.forEach { state: PatternState? -> grid.onPatternRemoved(state!!) }
}
}
if (!new_state.isEmpty()) {
new_state.getCapability(MatteryCapability.PATTERN).ifPresent(cap -> cap.getStoredPatterns().forEach(grid::onPatternAdded));
if (!new_state.isEmpty) {
new_state.getCapability(MatteryCapability.PATTERN).ifPresent { cap: IPatternStorage ->
cap.storedPatterns.forEach { state: PatternState? -> grid.onPatternAdded(state!!) }
}
}
updateBlockstate();
updateBlockstate()
}
super.setChanged(slot, new_state, old_state);
super.setChanged(slot, new_state, old_state)
}
@Override
public int getMaxStackSize() {
return 1;
}
};
private void updateBlockstate() {
if (level == null)
return;
var state = getBlockState();
for (int i = 0; i < 8; i++) {
state = state.setValue(BlockPatternStorage.PATTERN_STORAGE_DISKS_PROPS[i], patterns.getItem(i).getCapability(MatteryCapability.PATTERN).isPresent());
}
if (state != getBlockState()) {
level.setBlock(getBlockPos(), state, Block.UPDATE_CLIENTS);
override fun getMaxStackSize(): Int {
return 1
}
}
private final MatteryContainerHandler resolver_item = patterns.handler(
((slot, stack) -> stack.getCapability(MatteryCapability.PATTERN).isPresent())
);
private fun updateBlockstate() {
val level = level ?: return
private MatterGrid grid;
var state = blockState
@Override
public void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
nbt.put("patterns", patterns.serializeNBT());
for (i in 0..7) {
state = state.setValue(
BlockPatternStorage.PATTERN_STORAGE_DISKS_PROPS[i],
patterns.getItem(i).getCapability(MatteryCapability.PATTERN).isPresent
)
}
if (state !== blockState) {
level.setBlock(blockPos, state, Block.UPDATE_CLIENTS)
}
}
@Override
public void load(CompoundTag nbt) {
super.load(nbt);
patterns.deserializeNBT(nbt.get("patterns"));
private val resolverItem =
patterns.handler { slot: Int, stack: ItemStack -> stack.getCapability(MatteryCapability.PATTERN).isPresent }
override fun saveAdditional(nbt: CompoundTag) {
super.saveAdditional(nbt)
nbt["patterns"] = patterns.serializeNBT()
}
@Override
public void setLevel(Level p_155231_) {
super.setLevel(p_155231_);
override fun load(nbt: CompoundTag) {
super.load(nbt)
if (grid == null)
MatterGrid.scheduleDiscoverNeighbours(this, getBlockPos(), p_155231_);
nbt.ifHas("patterns") {
patterns.deserializeNBT(it)
}
}
@Nullable
@Override
public MatterGrid getMatterGrid() {
return grid;
override fun setLevel(p_155231_: Level) {
super.setLevel(p_155231_)
if (p_155231_ is ServerLevel)
MatterNetworkGraph.discoverFull(this, node)
}
@Nullable
@Override
public IMatterHandler getMatterHandler() {
return null;
override fun getAsMatterNode(): Graph6Node<IMatterGraphNode> {
return node
}
@Nullable
@Override
public IPatternStorage getPatternStorage() {
return valid ? this : null;
override fun getPatternHandler(): IPatternStorage {
return this
}
private boolean valid = true;
private var valid = true
@Override
public boolean isValidMatterCell() {
return valid;
override fun invalidateCaps() {
super.invalidateCaps()
valid = false
resolverItem.invalidate()
node.destroy(::MatterNetworkGraph)
}
@Override
public void setMatterGrid(MatterGrid grid) {
this.grid = grid;
override fun reviveCaps() {
super.reviveCaps()
valid = true
resolverItem.revive()
}
@Override
public void invalidateCaps() {
super.invalidateCaps();
valid = false;
resolver_item.invalidate();
}
@Override
public void reviveCaps() {
super.reviveCaps();
valid = true;
resolver_item.revive();
}
private final LazyOptional<BlockEntityPatternStorage> resolver = LazyOptional.of(() -> this);
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
if (valid) {
if (cap == MatteryCapability.PATTERN || cap == MatteryCapability.MATTER_CELL)
return resolver.cast();
if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
return resolver_item.get().cast();
if (cap === MatteryCapability.PATTERN) return resolverPatterns.cast()
if (cap === MatteryCapability.MATTER_CELL) return resolverNode.cast()
if (cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return resolverItem.get().cast()
}
return super.getCapability(cap, side);
return super.getCapability(cap, side)
}
private static final TranslatableComponent NAME = new TranslatableComponent("block.overdrive_that_matters.pattern_storage");
@Override
protected Component getDefaultDisplayName() {
return NAME;
override fun getDefaultDisplayName(): Component {
return NAME
}
@Nullable
@Override
public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply) {
return new PatternStorageMenu(containerID, inventory, this);
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
return PatternStorageMenu(containerID, inventory, this)
}
@Nonnull
@Override
public Collection<PatternState> getStoredPatterns() {
ArrayList<PatternState> list = new ArrayList<>();
patterns.consumeCapability(MatteryCapability.PATTERN, capability -> list.addAll(capability.getStoredPatterns()));
return ImmutableList.copyOf(list);
override fun getStoredPatterns(): Collection<PatternState> {
val list = ArrayList<PatternState>()
patterns.consumeCapability(MatteryCapability.PATTERN) { capability: IPatternStorage -> list.addAll(capability.storedPatterns) }
return list
}
@Override
public int getCapacity() {
long stored = 0;
override fun getCapacity(): Int {
var stored = 0L
for (var pattern : patterns.capabilityIterator(MatteryCapability.PATTERN)) {
stored += pattern.getCapacity();
}
for (pattern in patterns.capabilityIterator(MatteryCapability.PATTERN))
stored += pattern.capacity.toLong()
return stored > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) stored;
return if (stored > Int.MAX_VALUE) Int.MAX_VALUE else stored.toInt()
}
@Override
public int getStored() {
long stored = 0;
override fun getStored(): Int {
var stored = 0L
for (var pattern : patterns.capabilityIterator(MatteryCapability.PATTERN)) {
stored += pattern.getStored();
}
for (pattern in patterns.capabilityIterator(MatteryCapability.PATTERN))
stored += pattern.stored.toLong()
return stored > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) stored;
return if (stored > Int.MAX_VALUE) Int.MAX_VALUE else stored.toInt()
}
@Override
public void setRemoved() {
super.setRemoved();
if (level != null && !level.isClientSide && grid != null)
grid.remove(this);
override fun setRemoved() {
super.setRemoved()
node.destroy(::MatterNetworkGraph)
}
@Override
public PatternInsertStatus insertPattern(PatternState pattern, boolean only_update, boolean simulate) {
for (IPatternStorage storage : patterns.capabilityIterator(MatteryCapability.PATTERN)) {
var status = storage.insertPattern(pattern, only_update, simulate);
override fun insertPattern(pattern: PatternState, only_update: Boolean, simulate: Boolean): PatternInsertStatus {
for (storage in patterns.capabilityIterator(MatteryCapability.PATTERN)) {
val status = storage.insertPattern(pattern, only_update, simulate)
if (status.status() != PatternInsertStatus.Status.FAIL) {
if (!simulate) {
setChanged();
setChanged()
if (grid != null) {
val graph = node.graph as MatterNetworkGraph?
if (graph != null) {
if (status.status() == PatternInsertStatus.Status.INSERTED) {
grid.onPatternAdded(status.new_state());
graph.onPatternAdded(status.new_state()!!)
} else {
grid.onPatternUpdated(status.new_state(), status.old_state());
graph.onPatternUpdated(status.new_state()!!, status.old_state()!!)
}
}
}
return status;
return status
}
}
return new PatternInsertStatus();
return PatternInsertStatus()
}
}
companion object {
private val NAME = TranslatableComponent("block.overdrive_that_matters.pattern_storage")
}
}

View File

@ -24,4 +24,4 @@ class BatteryBankScreen(menu: BatteryBankMenu, p_97742_: Inventory, p_97743_: Co
return frame
}
}
}

View File

@ -1,33 +1,48 @@
package ru.dbotthepony.mc.otm.client.screen;
package ru.dbotthepony.mc.otm.client.screen
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.world.entity.player.Inventory;
import ru.dbotthepony.mc.otm.client.screen.panels.*;
import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel;
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel;
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel;
import ru.dbotthepony.mc.otm.menu.MatterBottlerMenu;
import ru.dbotthepony.mc.otm.menu.slot.MatterySlot;
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.client.screen.panels.ButtonPanel
import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
import ru.dbotthepony.mc.otm.client.screen.panels.SlotPanel
import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
import ru.dbotthepony.mc.otm.menu.MatterBottlerMenu
import javax.annotation.Nullable;
import java.util.List;
class MatterBottlerScreen(menu: MatterBottlerMenu, inventory: Inventory, title: Component) :
MatteryScreen<MatterBottlerMenu>(menu, inventory, title) {
public class MatterBottlerScreen extends MatteryScreen<MatterBottlerMenu> {
public MatterBottlerScreen(MatterBottlerMenu menu, Inventory inventory, Component title) {
super(menu, inventory, title);
private var progress: ProgressGaugePanel? = null
override fun makeMainFrame(): FramePanel {
val frame = super.makeMainFrame()!!
val p = PowerGaugePanel(this, frame, menu.battery_widget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT)
MatterGaugePanel(this, frame, menu.matterWidget, LEFT_MARGIN + p.width, GAUGE_TOP_WITH_SLOT)
SlotPanel(this, frame, menu.battery_slot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE)
for (i in 0 .. 2) {
SlotPanel(this, frame, menu.container[i], 31f + i * 18, PROGRESS_SLOT_TOP)
}
for (i in 3 .. 5) {
SlotPanel(this, frame, menu.container[i], 116f + (i - 3) * 18, PROGRESS_SLOT_TOP)
}
progress = ProgressGaugePanel(this, frame, menu.progressWidget, 90f, PROGRESS_ARROW_TOP)
val mode = ButtonPanel(this, frame, 46f, 69f, 100f, 20f, TranslatableComponent("otm.matter_bottler.switch_mode"))
mode.bindOnPress { menu.switchBottlerMode() }
return frame
}
@Nullable
@Override
protected FramePanel makeMainFrame() {
var frame = super.makeMainFrame();
override fun containerTick() {
super.containerTick()
var mode = new ButtonPanel(this, frame, 0, 0, 100, 20, new TranslatableComponent("otm.matter_bottler.switch_mode"));
mode.bindOnPress(menu::switchBottlerMode);
mode.setDock(Dock.TOP);
mode.asGrid(); // for auto alignment on center
return frame;
progress?.flop = !menu.workFlow.value
}
}

View File

@ -4,6 +4,7 @@ import net.minecraft.nbt.ByteArrayTag
import net.minecraft.nbt.StringTag
import net.minecraft.nbt.Tag
import net.minecraft.network.FriendlyByteBuf
import org.apache.logging.log4j.LogManager
import java.math.BigDecimal
import java.math.BigInteger
import java.math.MathContext
@ -44,6 +45,196 @@ inline fun invertCompare(int: Int): Int {
}
private val BI_MINUS_ZERO = BigInteger("-0")
private val BI_MINUS_ONE = BigInteger("-1")
private val BI_DIV = BigInteger.valueOf(1_000_000_000)
private val BI_DIV2 = BigInteger.valueOf(10)
private val BI_MINUS_DIV = BigInteger.valueOf(-1_000_000_000)
private fun isZero(value: BigInteger): Boolean {
return when (value.signum()) {
0 -> true
1 -> value == BigInteger.ZERO
-1 -> value == BI_MINUS_ZERO
else -> false
}
}
private fun isOne(value: BigInteger): Boolean {
return when (value.signum()) {
0 -> false
1 -> value == BigInteger.ONE
-1 -> value == BI_MINUS_ONE
else -> false
}
}
private fun compactTwoMod(value1: BigInteger, value2: BigInteger, compact: Boolean = true): Fraction {
val mod = value1.divideAndRemainder(value2)
if (isZero(mod[1]))
return Fraction(mod[0], compact = compact)
return Fraction(value1, value2, compact = compact)
}
private fun positive(value: BigInteger): BigInteger {
return when (value.signum()) {
0 -> value
1 -> value
-1 -> -value
else -> throw InternalError()
}
}
private val GCDs = arrayOf(
BigInteger.valueOf(2), BigInteger.valueOf(3), BigInteger.valueOf(5), BigInteger.valueOf(7), BigInteger.valueOf(11), BigInteger.valueOf(13), BigInteger.valueOf(17), BigInteger.valueOf(19), BigInteger.valueOf(23), BigInteger.valueOf(29), BigInteger.valueOf(31), BigInteger.valueOf(37), BigInteger.valueOf(41), BigInteger.valueOf(43), BigInteger.valueOf(47), BigInteger.valueOf(53), BigInteger.valueOf(59), BigInteger.valueOf(61), BigInteger.valueOf(67), BigInteger.valueOf(71),
BigInteger.valueOf(73), BigInteger.valueOf(79), BigInteger.valueOf(83), BigInteger.valueOf(89), BigInteger.valueOf(97), BigInteger.valueOf(101), BigInteger.valueOf(103), BigInteger.valueOf(107), BigInteger.valueOf(109), BigInteger.valueOf(113), BigInteger.valueOf(127), BigInteger.valueOf(131), BigInteger.valueOf(137), BigInteger.valueOf(139), BigInteger.valueOf(149), BigInteger.valueOf(151), BigInteger.valueOf(157), BigInteger.valueOf(163), BigInteger.valueOf(167), BigInteger.valueOf(173),
BigInteger.valueOf(179), BigInteger.valueOf(181), BigInteger.valueOf(191), BigInteger.valueOf(193), BigInteger.valueOf(197), BigInteger.valueOf(199), BigInteger.valueOf(211), BigInteger.valueOf(223), BigInteger.valueOf(227), BigInteger.valueOf(229), BigInteger.valueOf(233), BigInteger.valueOf(239), BigInteger.valueOf(241), BigInteger.valueOf(251), BigInteger.valueOf(257), BigInteger.valueOf(263), BigInteger.valueOf(269), BigInteger.valueOf(271), BigInteger.valueOf(277), BigInteger.valueOf(281),
BigInteger.valueOf(283), BigInteger.valueOf(293), BigInteger.valueOf(307), BigInteger.valueOf(311), BigInteger.valueOf(313), BigInteger.valueOf(317), BigInteger.valueOf(331), BigInteger.valueOf(337), BigInteger.valueOf(347), BigInteger.valueOf(349), BigInteger.valueOf(353), BigInteger.valueOf(359), BigInteger.valueOf(367), BigInteger.valueOf(373), BigInteger.valueOf(379), BigInteger.valueOf(383), BigInteger.valueOf(389), BigInteger.valueOf(397), BigInteger.valueOf(401), BigInteger.valueOf(409),
BigInteger.valueOf(419), BigInteger.valueOf(421), BigInteger.valueOf(431), BigInteger.valueOf(433), BigInteger.valueOf(439), BigInteger.valueOf(443), BigInteger.valueOf(449), BigInteger.valueOf(457), BigInteger.valueOf(461), BigInteger.valueOf(463), BigInteger.valueOf(467), BigInteger.valueOf(479), BigInteger.valueOf(487), BigInteger.valueOf(491), BigInteger.valueOf(499), BigInteger.valueOf(503), BigInteger.valueOf(509), BigInteger.valueOf(521), BigInteger.valueOf(523), BigInteger.valueOf(541),
BigInteger.valueOf(547), BigInteger.valueOf(557), BigInteger.valueOf(563), BigInteger.valueOf(569), BigInteger.valueOf(571), BigInteger.valueOf(577), BigInteger.valueOf(587), BigInteger.valueOf(593), BigInteger.valueOf(599), BigInteger.valueOf(601), BigInteger.valueOf(607), BigInteger.valueOf(613), BigInteger.valueOf(617), BigInteger.valueOf(619), BigInteger.valueOf(631), BigInteger.valueOf(641), BigInteger.valueOf(643), BigInteger.valueOf(647), BigInteger.valueOf(653), BigInteger.valueOf(659),
BigInteger.valueOf(661), BigInteger.valueOf(673), BigInteger.valueOf(677), BigInteger.valueOf(683), BigInteger.valueOf(691), BigInteger.valueOf(701), BigInteger.valueOf(709), BigInteger.valueOf(719), BigInteger.valueOf(727), BigInteger.valueOf(733), BigInteger.valueOf(739), BigInteger.valueOf(743), BigInteger.valueOf(751), BigInteger.valueOf(757), BigInteger.valueOf(761), BigInteger.valueOf(769), BigInteger.valueOf(773), BigInteger.valueOf(787), BigInteger.valueOf(797), BigInteger.valueOf(809),
BigInteger.valueOf(811), BigInteger.valueOf(821), BigInteger.valueOf(823), BigInteger.valueOf(827), BigInteger.valueOf(829), BigInteger.valueOf(839), BigInteger.valueOf(853), BigInteger.valueOf(857), BigInteger.valueOf(859), BigInteger.valueOf(863), BigInteger.valueOf(877), BigInteger.valueOf(881), BigInteger.valueOf(883), BigInteger.valueOf(887), BigInteger.valueOf(907), BigInteger.valueOf(911), BigInteger.valueOf(919), BigInteger.valueOf(929), BigInteger.valueOf(937), BigInteger.valueOf(941),
BigInteger.valueOf(947), BigInteger.valueOf(953), BigInteger.valueOf(967), BigInteger.valueOf(971), BigInteger.valueOf(977), BigInteger.valueOf(983), BigInteger.valueOf(991), BigInteger.valueOf(997), BigInteger.valueOf(1009), BigInteger.valueOf(1013), BigInteger.valueOf(1019), BigInteger.valueOf(1021), BigInteger.valueOf(1031), BigInteger.valueOf(1033), BigInteger.valueOf(1039), BigInteger.valueOf(1049), BigInteger.valueOf(1051), BigInteger.valueOf(1061), BigInteger.valueOf(1063), BigInteger.valueOf(1069),
BigInteger.valueOf(1087), BigInteger.valueOf(1091), BigInteger.valueOf(1093), BigInteger.valueOf(1097), BigInteger.valueOf(1103), BigInteger.valueOf(1109), BigInteger.valueOf(1117), BigInteger.valueOf(1123), BigInteger.valueOf(1129), BigInteger.valueOf(1151), BigInteger.valueOf(1153), BigInteger.valueOf(1163), BigInteger.valueOf(1171), BigInteger.valueOf(1181), BigInteger.valueOf(1187), BigInteger.valueOf(1193), BigInteger.valueOf(1201), BigInteger.valueOf(1213), BigInteger.valueOf(1217), BigInteger.valueOf(1223),
BigInteger.valueOf(1229), BigInteger.valueOf(1231), BigInteger.valueOf(1237), BigInteger.valueOf(1249), BigInteger.valueOf(1259), BigInteger.valueOf(1277), BigInteger.valueOf(1279), BigInteger.valueOf(1283), BigInteger.valueOf(1289), BigInteger.valueOf(1291), BigInteger.valueOf(1297), BigInteger.valueOf(1301), BigInteger.valueOf(1303), BigInteger.valueOf(1307), BigInteger.valueOf(1319), BigInteger.valueOf(1321), BigInteger.valueOf(1327), BigInteger.valueOf(1361), BigInteger.valueOf(1367), BigInteger.valueOf(1373),
BigInteger.valueOf(1381), BigInteger.valueOf(1399), BigInteger.valueOf(1409), BigInteger.valueOf(1423), BigInteger.valueOf(1427), BigInteger.valueOf(1429), BigInteger.valueOf(1433), BigInteger.valueOf(1439), BigInteger.valueOf(1447), BigInteger.valueOf(1451), BigInteger.valueOf(1453), BigInteger.valueOf(1459), BigInteger.valueOf(1471), BigInteger.valueOf(1481), BigInteger.valueOf(1483), BigInteger.valueOf(1487), BigInteger.valueOf(1489), BigInteger.valueOf(1493), BigInteger.valueOf(1499), BigInteger.valueOf(1511),
BigInteger.valueOf(1523), BigInteger.valueOf(1531), BigInteger.valueOf(1543), BigInteger.valueOf(1549), BigInteger.valueOf(1553), BigInteger.valueOf(1559), BigInteger.valueOf(1567), BigInteger.valueOf(1571), BigInteger.valueOf(1579), BigInteger.valueOf(1583), BigInteger.valueOf(1597), BigInteger.valueOf(1601), BigInteger.valueOf(1607), BigInteger.valueOf(1609), BigInteger.valueOf(1613), BigInteger.valueOf(1619), BigInteger.valueOf(1621), BigInteger.valueOf(1627), BigInteger.valueOf(1637), BigInteger.valueOf(1657),
BigInteger.valueOf(1663), BigInteger.valueOf(1667), BigInteger.valueOf(1669), BigInteger.valueOf(1693), BigInteger.valueOf(1697), BigInteger.valueOf(1699), BigInteger.valueOf(1709), BigInteger.valueOf(1721), BigInteger.valueOf(1723), BigInteger.valueOf(1733), BigInteger.valueOf(1741), BigInteger.valueOf(1747), BigInteger.valueOf(1753), BigInteger.valueOf(1759), BigInteger.valueOf(1777), BigInteger.valueOf(1783), BigInteger.valueOf(1787), BigInteger.valueOf(1789), BigInteger.valueOf(1801), BigInteger.valueOf(1811),
BigInteger.valueOf(1823), BigInteger.valueOf(1831), BigInteger.valueOf(1847), BigInteger.valueOf(1861), BigInteger.valueOf(1867), BigInteger.valueOf(1871), BigInteger.valueOf(1873), BigInteger.valueOf(1877), BigInteger.valueOf(1879), BigInteger.valueOf(1889), BigInteger.valueOf(1901), BigInteger.valueOf(1907), BigInteger.valueOf(1913), BigInteger.valueOf(1931), BigInteger.valueOf(1933), BigInteger.valueOf(1949), BigInteger.valueOf(1951), BigInteger.valueOf(1973), BigInteger.valueOf(1979), BigInteger.valueOf(1987),
BigInteger.valueOf(1993), BigInteger.valueOf(1997), BigInteger.valueOf(1999), BigInteger.valueOf(2003), BigInteger.valueOf(2011), BigInteger.valueOf(2017), BigInteger.valueOf(2027), BigInteger.valueOf(2029), BigInteger.valueOf(2039), BigInteger.valueOf(2053), BigInteger.valueOf(2063), BigInteger.valueOf(2069), BigInteger.valueOf(2081), BigInteger.valueOf(2083), BigInteger.valueOf(2087), BigInteger.valueOf(2089), BigInteger.valueOf(2099), BigInteger.valueOf(2111), BigInteger.valueOf(2113), BigInteger.valueOf(2129),
BigInteger.valueOf(2131), BigInteger.valueOf(2137), BigInteger.valueOf(2141), BigInteger.valueOf(2143), BigInteger.valueOf(2153), BigInteger.valueOf(2161), BigInteger.valueOf(2179), BigInteger.valueOf(2203), BigInteger.valueOf(2207), BigInteger.valueOf(2213), BigInteger.valueOf(2221), BigInteger.valueOf(2237), BigInteger.valueOf(2239), BigInteger.valueOf(2243), BigInteger.valueOf(2251), BigInteger.valueOf(2267), BigInteger.valueOf(2269), BigInteger.valueOf(2273), BigInteger.valueOf(2281), BigInteger.valueOf(2287),
BigInteger.valueOf(2293), BigInteger.valueOf(2297), BigInteger.valueOf(2309), BigInteger.valueOf(2311), BigInteger.valueOf(2333), BigInteger.valueOf(2339), BigInteger.valueOf(2341), BigInteger.valueOf(2347), BigInteger.valueOf(2351), BigInteger.valueOf(2357), BigInteger.valueOf(2371), BigInteger.valueOf(2377), BigInteger.valueOf(2381), BigInteger.valueOf(2383), BigInteger.valueOf(2389), BigInteger.valueOf(2393), BigInteger.valueOf(2399), BigInteger.valueOf(2411), BigInteger.valueOf(2417), BigInteger.valueOf(2423),
BigInteger.valueOf(2437), BigInteger.valueOf(2441), BigInteger.valueOf(2447), BigInteger.valueOf(2459), BigInteger.valueOf(2467), BigInteger.valueOf(2473), BigInteger.valueOf(2477), BigInteger.valueOf(2503), BigInteger.valueOf(2521), BigInteger.valueOf(2531), BigInteger.valueOf(2539), BigInteger.valueOf(2543), BigInteger.valueOf(2549), BigInteger.valueOf(2551), BigInteger.valueOf(2557), BigInteger.valueOf(2579), BigInteger.valueOf(2591), BigInteger.valueOf(2593), BigInteger.valueOf(2609), BigInteger.valueOf(2617),
BigInteger.valueOf(2621), BigInteger.valueOf(2633), BigInteger.valueOf(2647), BigInteger.valueOf(2657), BigInteger.valueOf(2659), BigInteger.valueOf(2663), BigInteger.valueOf(2671), BigInteger.valueOf(2677), BigInteger.valueOf(2683), BigInteger.valueOf(2687), BigInteger.valueOf(2689), BigInteger.valueOf(2693), BigInteger.valueOf(2699), BigInteger.valueOf(2707), BigInteger.valueOf(2711), BigInteger.valueOf(2713), BigInteger.valueOf(2719), BigInteger.valueOf(2729), BigInteger.valueOf(2731), BigInteger.valueOf(2741),
BigInteger.valueOf(2749), BigInteger.valueOf(2753), BigInteger.valueOf(2767), BigInteger.valueOf(2777), BigInteger.valueOf(2789), BigInteger.valueOf(2791), BigInteger.valueOf(2797), BigInteger.valueOf(2801), BigInteger.valueOf(2803), BigInteger.valueOf(2819), BigInteger.valueOf(2833), BigInteger.valueOf(2837), BigInteger.valueOf(2843), BigInteger.valueOf(2851), BigInteger.valueOf(2857), BigInteger.valueOf(2861), BigInteger.valueOf(2879), BigInteger.valueOf(2887), BigInteger.valueOf(2897), BigInteger.valueOf(2903),
BigInteger.valueOf(2909), BigInteger.valueOf(2917), BigInteger.valueOf(2927), BigInteger.valueOf(2939), BigInteger.valueOf(2953), BigInteger.valueOf(2957), BigInteger.valueOf(2963), BigInteger.valueOf(2969), BigInteger.valueOf(2971), BigInteger.valueOf(2999), BigInteger.valueOf(3001), BigInteger.valueOf(3011), BigInteger.valueOf(3019), BigInteger.valueOf(3023), BigInteger.valueOf(3037), BigInteger.valueOf(3041), BigInteger.valueOf(3049), BigInteger.valueOf(3061), BigInteger.valueOf(3067), BigInteger.valueOf(3079),
BigInteger.valueOf(3083), BigInteger.valueOf(3089), BigInteger.valueOf(3109), BigInteger.valueOf(3119), BigInteger.valueOf(3121), BigInteger.valueOf(3137), BigInteger.valueOf(3163), BigInteger.valueOf(3167), BigInteger.valueOf(3169), BigInteger.valueOf(3181), BigInteger.valueOf(3187), BigInteger.valueOf(3191), BigInteger.valueOf(3203), BigInteger.valueOf(3209), BigInteger.valueOf(3217), BigInteger.valueOf(3221), BigInteger.valueOf(3229), BigInteger.valueOf(3251), BigInteger.valueOf(3253), BigInteger.valueOf(3257),
BigInteger.valueOf(3259), BigInteger.valueOf(3271), BigInteger.valueOf(3299), BigInteger.valueOf(3301), BigInteger.valueOf(3307), BigInteger.valueOf(3313), BigInteger.valueOf(3319), BigInteger.valueOf(3323), BigInteger.valueOf(3329), BigInteger.valueOf(3331), BigInteger.valueOf(3343), BigInteger.valueOf(3347), BigInteger.valueOf(3359), BigInteger.valueOf(3361), BigInteger.valueOf(3371), BigInteger.valueOf(3373), BigInteger.valueOf(3389), BigInteger.valueOf(3391), BigInteger.valueOf(3407), BigInteger.valueOf(3413),
BigInteger.valueOf(3433), BigInteger.valueOf(3449), BigInteger.valueOf(3457), BigInteger.valueOf(3461), BigInteger.valueOf(3463), BigInteger.valueOf(3467), BigInteger.valueOf(3469), BigInteger.valueOf(3491), BigInteger.valueOf(3499), BigInteger.valueOf(3511), BigInteger.valueOf(3517), BigInteger.valueOf(3527), BigInteger.valueOf(3529), BigInteger.valueOf(3533), BigInteger.valueOf(3539), BigInteger.valueOf(3541), BigInteger.valueOf(3547), BigInteger.valueOf(3557), BigInteger.valueOf(3559), BigInteger.valueOf(3571),
)
private val COMPACT_THRESHOLD = BigInteger("1000000000000000000000")
private fun compactTwo(value1: BigInteger, value2: BigInteger, compact: Boolean = true): Fraction {
when (value1.signum()) {
0 -> return Fraction(value1, value2, compact = compact)
1 -> if (value1 < BI_DIV) return compactTwoMod(value1, value2, compact)
-1 -> if (value1 > BI_MINUS_DIV) return compactTwoMod(value1, value2, compact)
}
when (value2.signum()) {
0 -> return Fraction(value1, value2, compact = compact)
1 -> if (value2 < BI_DIV) return compactTwoMod(value1, value2, compact)
-1 -> if (value2 > BI_MINUS_DIV) return compactTwoMod(value1, value2, compact)
}
var value1 = value1
var value2 = value2
while (true) {
val _a = value1.divideAndRemainder(BI_DIV)
val _b = value2.divideAndRemainder(BI_DIV)
if (!isZero(_a[1]) || !isZero(_b[1]))
break
value1 = _a[0]
value2 = _b[0]
}
while (true) {
val _a = value1.divideAndRemainder(BI_DIV2)
val _b = value2.divideAndRemainder(BI_DIV2)
if (!isZero(_a[1]) || !isZero(_b[1]))
break
value1 = _a[0]
value2 = _b[0]
}
val p1 = positive(value1)
val p2 = positive(value2)
if (p1 > COMPACT_THRESHOLD || p2 > COMPACT_THRESHOLD) {
var hit = true
while (hit) {
hit = false
for (i in GCDs.size - 1 downTo 0) {
val div = GCDs[i]
while (true) {
val _a = value1.divideAndRemainder(div)
val _b = value2.divideAndRemainder(div)
if (!isZero(_a[1]) || !isZero(_b[1]))
break
value1 = _a[0]
value2 = _b[0]
hit = true
}
}
}
} else if (p1 > GCDs[0] && p2 > GCDs[0]) {
var hit = true
while (hit) {
hit = false
for (i in 4 downTo 0) {
val div = GCDs[i]
while (true) {
val _a = value1.divideAndRemainder(div)
val _b = value2.divideAndRemainder(div)
if (!isZero(_a[1]) || !isZero(_b[1]))
break
value1 = _a[0]
value2 = _b[0]
hit = true
}
}
}
}
return compactTwoMod(value1, value2, compact)
}
fun unsignedInt(value: Byte): Int {
if (value < 0) {
return 256 + value
}
return value.toInt()
}
private data class MagnitudeCrunchResult(val value: BigInteger, val mag: Int)
private fun magnitude(value: BigInteger): MagnitudeCrunchResult {
if (isZero(value))
return MagnitudeCrunchResult(value, 0)
var mag = 0
var value = value
while (true) {
val c = value.divideAndRemainder(BI_DIV2)
if (!isZero(c[1]))
break
value = c[0]
mag++
}
return MagnitudeCrunchResult(value, mag)
}
@JvmRecord
@Suppress("unused")
@ -72,26 +263,21 @@ data class Fraction @JvmOverloads constructor(@JvmField val value: BigInteger, @
val c = divisor.signum()
if (a != b && a != c) {
if (divisor == BigInteger.ZERO || divisor == BI_MINUS_ZERO)
if (isZero(divisor))
return Fraction(-value, -divisor)
val mod = value % divisor
val mod = value.divideAndRemainder(divisor)
if (mod == BigInteger.ZERO)
return Fraction(-value / -divisor, compact = compact)
if (isZero(mod[1]))
return Fraction(mod[0], compact = compact)
return Fraction(-value, -divisor)
}
if (divisor == BigInteger.ZERO || divisor == BI_MINUS_ZERO)
if (isZero(divisor))
return this
val mod = value % divisor
if (mod == BigInteger.ZERO)
return Fraction(value / divisor, compact = compact)
return this
return compactTwo(value, divisor, compact)
}
fun isZero(): Boolean {
@ -108,12 +294,7 @@ data class Fraction @JvmOverloads constructor(@JvmField val value: BigInteger, @
if (divisor == BigInteger.ZERO || divisor == BI_MINUS_ZERO)
return this
val mod = value % divisor
if (mod == BigInteger.ZERO)
return Fraction(value / divisor, compact = compact)
return this
return compactTwo(value, divisor, compact)
}
fun canonize(): Fraction {
@ -181,8 +362,8 @@ data class Fraction @JvmOverloads constructor(@JvmField val value: BigInteger, @
if (isNaN()) return this
if (divisor == other.divisor) {
if (divisor == BigInteger.ONE)
return Fraction(value + other.value)
if (isOne(divisor))
return Fraction(value + other.value, divisor)
val new = value + other.value
@ -192,12 +373,7 @@ data class Fraction @JvmOverloads constructor(@JvmField val value: BigInteger, @
if (divisor == BigInteger.ZERO || divisor == BI_MINUS_ZERO)
return Fraction(new, divisor)
val mod = new % divisor
if (mod == BigInteger.ZERO)
return Fraction(new / divisor)
return Fraction(new, divisor)
return compactTwo(new, divisor)
}
val new = value * other.divisor + other.value * divisor
@ -206,12 +382,7 @@ data class Fraction @JvmOverloads constructor(@JvmField val value: BigInteger, @
if (div == BigInteger.ZERO || div == BI_MINUS_ZERO)
return Fraction(new, div)
val mod = new % div
if (mod == BigInteger.ZERO)
return Fraction(new / div)
return Fraction(new, div)
return compactTwo(new, div)
}
operator fun plus(other: Fraction): Fraction {
@ -230,8 +401,8 @@ data class Fraction @JvmOverloads constructor(@JvmField val value: BigInteger, @
private fun minusCompact(other: Fraction): Fraction {
if (divisor == other.divisor) {
if (divisor == BigInteger.ONE)
return Fraction(value - other.value)
if (isOne(divisor))
return Fraction(value - other.value, divisor)
val new = value - other.value
@ -241,12 +412,7 @@ data class Fraction @JvmOverloads constructor(@JvmField val value: BigInteger, @
if (divisor == BigInteger.ZERO || divisor == BI_MINUS_ZERO)
return Fraction(new, divisor)
val mod = new % divisor
if (mod == BigInteger.ZERO)
return Fraction(new / divisor)
return Fraction(new, divisor)
return compactTwo(new, divisor)
}
val new = value * other.divisor - other.value * divisor
@ -255,12 +421,7 @@ data class Fraction @JvmOverloads constructor(@JvmField val value: BigInteger, @
if (div == BigInteger.ZERO || div == BI_MINUS_ZERO)
return Fraction(new, div)
val mod = new % div
if (mod == BigInteger.ZERO)
return Fraction(new / div)
return Fraction(new, div)
return compactTwo(new, div)
}
operator fun minus(other: Fraction): Fraction {
@ -288,12 +449,7 @@ data class Fraction @JvmOverloads constructor(@JvmField val value: BigInteger, @
if (div == BigInteger.ZERO || div == BI_MINUS_ZERO)
return Fraction(new, div)
val mod = new % div
if (mod == BigInteger.ZERO)
return Fraction(new / div)
return Fraction(new, div)
return compactTwo(new, div)
}
operator fun times(other: Fraction): Fraction {
@ -317,12 +473,7 @@ data class Fraction @JvmOverloads constructor(@JvmField val value: BigInteger, @
if (div == BigInteger.ZERO || div == BI_MINUS_ZERO)
return Fraction(new, div)
val mod = new % div
if (mod == BigInteger.ZERO)
return Fraction(new / div)
return Fraction(new, div)
return compactTwo(new, div)
}
operator fun div(other: Fraction): Fraction {
@ -423,13 +574,32 @@ data class Fraction @JvmOverloads constructor(@JvmField val value: BigInteger, @
fun toByteArray(): ByteArray {
if (isNaN()) {
return byteArrayOf(1, 0, 1, 0)
return byteArrayOf(1, 0, 0, 0, 0, 1, 0, 0, 0, 0)
}
val bytesA = value.toByteArray()
val bytesB = divisor.toByteArray()
val magValue = magnitude(value)
val magDiv = magnitude(divisor)
return byteArrayOf(bytesA.size.toByte(), *bytesA, bytesB.size.toByte(), *bytesB)
val bytesA = magValue.value.toByteArray()
val bytesB = magDiv.value.toByteArray()
return byteArrayOf(
(bytesA.size and 0xFF).toByte(),
(bytesA.size ushr 8).toByte(),
(magValue.mag and 0xFF).toByte(),
(magValue.mag ushr 8).toByte(),
*bytesA,
(bytesB.size and 0xFF).toByte(),
(bytesB.size ushr 8).toByte(),
(magDiv.mag and 0xFF).toByte(),
(magDiv.mag ushr 8).toByte(),
*bytesB
)
}
fun toInt(): Int {
@ -592,6 +762,8 @@ data class Fraction @JvmOverloads constructor(@JvmField val value: BigInteger, @
}
companion object {
private val LOGGER = LogManager.getLogger()
@JvmField
val ZERO = Fraction(BigInteger.ZERO)
@ -635,11 +807,27 @@ data class Fraction @JvmOverloads constructor(@JvmField val value: BigInteger, @
@JvmStatic
fun fromByteArray(bytes: ByteArray): Fraction {
val bytesA = bytes.copyOfRange(1, 1 + bytes[0].toInt())
val offsetB = 1 + bytes[0].toInt()
val bytesB = bytes.copyOfRange(offsetB + 1, offsetB + 1 + bytes[offsetB].toInt())
try {
val rangeA = unsignedInt(bytes[0]) or (unsignedInt(bytes[1]) shl 8)
val magA = unsignedInt(bytes[2]) or (unsignedInt(bytes[3]) shl 8)
return Fraction(if (bytesA.isNotEmpty()) BigInteger(bytesA) else BigInteger.ZERO, if (bytesB.isNotEmpty()) BigInteger(bytesB) else BigInteger.ZERO)
val bytesA = bytes.copyOfRange(4, 4 + rangeA)
val offsetB = 4 + rangeA
val rangeB = unsignedInt(bytes[offsetB]) or (unsignedInt(bytes[offsetB + 1]) shl 8)
val magB = unsignedInt(bytes[offsetB + 2]) or (unsignedInt(bytes[offsetB + 3]) shl 8)
val bytesB = bytes.copyOfRange(offsetB + 4, offsetB + 4 + rangeB)
if (bytesB.isEmpty())
return NaN
return Fraction(if (bytesA.isNotEmpty()) (BigInteger(bytesA) * BigInteger("1" + "0".repeat(magA))) else BigInteger.ZERO, BigInteger(bytesB) * BigInteger("1" + "0".repeat(magB)))
} catch(err: Throwable) {
LOGGER.error("Unable to load Fraction from byte array", err)
return NaN
}
}
@JvmStatic

View File

@ -0,0 +1,159 @@
package ru.dbotthepony.mc.otm.graph
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.core.SectionPos
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.level.block.entity.BlockEntity
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.plus
import java.util.*
import kotlin.collections.ArrayList
abstract class Abstract6Graph<T> {
@JvmField
protected val _nodes = ArrayList<Graph6Node<T>>()
fun size() = _nodes.size
@JvmField
val nodes = Collections.unmodifiableCollection(_nodes)
abstract fun onNodeRemoved(node: Graph6Node<T>)
abstract fun onNodeAdded(node: Graph6Node<T>)
fun removeNode(node: Graph6Node<T>) {
if (!_nodes.contains(node))
throw IllegalStateException("Not containing node $node")
_nodes.remove(node)
node.graph = null
onNodeRemoved(node)
}
fun addNode(node: Graph6Node<T>) {
if (_nodes.contains(node))
throw IllegalStateException("Already containing node $node")
_nodes.add(node)
node.graph = this
onNodeAdded(node)
}
fun merge(other: Abstract6Graph<T>): Abstract6Graph<T> {
if (other === this)
return this
if (size() >= other.size()) {
for (node in other._nodes) {
_nodes.add(node)
node.graph = this
onNodeAdded(node)
}
return this
} else {
return other.merge(this)
}
}
companion object {
fun <T, G : Abstract6Graph<T>> discoverFull(
level: ServerLevel,
blockPos: BlockPos,
node: Graph6Node<T>,
nodeGetter: (BlockEntity) -> Graph6Node<T>?,
factory: () -> G
) {
OverdriveThatMatters.tickUntil(level) {
!node.valid || discover(level, blockPos, node, nodeGetter, factory)
}
}
@JvmStatic
fun <T, G : Abstract6Graph<T>> discover(
level: ServerLevel,
blockPos: BlockPos,
node: Graph6Node<T>,
nodeGetter: (BlockEntity) -> Graph6Node<T>?,
factory: () -> G
): Boolean {
var fullDiscovery = true
node.nullifyConnections()
var _graph = node.graph
// для начала найдем граф к которому будем принадлежать
if (_graph == null) {
for (dir in Direction.values()) {
val offset = blockPos + dir
val chunk = level.chunkSource.getChunkNow(SectionPos.blockToSectionCoord(offset.x), SectionPos.blockToSectionCoord(offset.z))
if (chunk == null) {
fullDiscovery = false
continue
}
val entity = chunk.getBlockEntity(offset)
if (entity != null) {
val getNode = nodeGetter(entity)
if (getNode?.graph != null) {
_graph = getNode.graph
break
}
}
}
// мы нашли граф рядом
if (_graph != null) {
node.graph = _graph
_graph.addNode(node)
} else {
// графов рядом нет, создаем свой
_graph = factory()
node.graph = _graph
_graph.addNode(node)
}
}
// теперь снова смотрим на соседей, если у них нет графа - присоединяем к своему
// если у них есть граф - слияем его со своим или свой с его
for (dir in Direction.values()) {
val offset = blockPos + dir
val chunk = level.chunkSource.getChunkNow(SectionPos.blockToSectionCoord(offset.x), SectionPos.blockToSectionCoord(offset.z))
if (chunk == null) {
fullDiscovery = false
continue
}
val entity = chunk.getBlockEntity(offset)
if (entity != null) {
val getNode = nodeGetter(entity)
if (getNode != null) {
// у вершины нет своего графа
// добавляем в свой граф
if (getNode.graph == null) {
getNode.graph = node.graph!!
node.graph!!.addNode(getNode)
} else if (getNode.graph != node.graph) {
// у вершины уже есть свой граф, и он не наш
// произведём слияние графов
val merged = getNode.graph!!.merge(node.graph!!)
getNode.graph = merged
node.graph = merged
}
node.setToNeightbour(getNode, dir)
}
}
}
return fullDiscovery
}
}
}

View File

@ -0,0 +1,299 @@
package ru.dbotthepony.mc.otm.graph
import net.minecraft.core.Direction
interface GraphNodeListener {
fun onNeighbourTop(node: Graph6Node<*>) = onNeighbour(node, Direction.UP)
fun onNeighbourBottom(node: Graph6Node<*>) = onNeighbour(node, Direction.DOWN)
fun onNeighbourLeft(node: Graph6Node<*>) = onNeighbour(node, Direction.WEST)
fun onNeighbourRight(node: Graph6Node<*>) = onNeighbour(node, Direction.EAST)
fun onNeighbourFront(node: Graph6Node<*>) = onNeighbour(node, Direction.SOUTH)
fun onNeighbourBack(node: Graph6Node<*>) = onNeighbour(node, Direction.NORTH)
fun onNeighbour(node: Graph6Node<*>, direction: Direction)
fun onUnNeighbourTop(node: Graph6Node<*>) = onUnNeighbour(node, Direction.UP)
fun onUnNeighbourBottom(node: Graph6Node<*>) = onUnNeighbour(node, Direction.DOWN)
fun onUnNeighbourLeft(node: Graph6Node<*>) = onUnNeighbour(node, Direction.WEST)
fun onUnNeighbourRight(node: Graph6Node<*>) = onUnNeighbour(node, Direction.EAST)
fun onUnNeighbourFront(node: Graph6Node<*>) = onUnNeighbour(node, Direction.SOUTH)
fun onUnNeighbourBack(node: Graph6Node<*>) = onUnNeighbour(node, Direction.NORTH)
fun onUnNeighbour(node: Graph6Node<*>, direction: Direction)
}
// Вершина графа, содержит то, к какому графу принадлежит, соседей и своё "значение"
class Graph6Node<T>(@JvmField val value: T, graph: Abstract6Graph<T>? = null) {
var graph: Abstract6Graph<T>? = null
init {
this.graph = graph
}
var top: Graph6Node<T>? = null
set(value) {
if (value != null && (graph == null || value.graph !== graph)) throw IllegalStateException("Can not be neighbour with node from different graph")
if (field != value && this.value is GraphNodeListener) {
if (field != null) {
this.value.onUnNeighbourTop(field!!)
}
if (value != null) {
this.value.onNeighbourTop(value)
}
}
field = value
}
var bottom: Graph6Node<T>? = null
set(value) {
if (value != null && (graph == null || value.graph !== graph)) throw IllegalStateException("Can not be neighbour with node from different graph")
if (field != value && this.value is GraphNodeListener) {
if (field != null) {
this.value.onUnNeighbourBottom(field!!)
}
if (value != null) {
this.value.onNeighbourBottom(value)
}
}
field = value
}
var left: Graph6Node<T>? = null
set(value) {
if (value != null && (graph == null || value.graph !== graph)) throw IllegalStateException("Can not be neighbour with node from different graph")
if (field != value && this.value is GraphNodeListener) {
if (field != null) {
this.value.onUnNeighbourLeft(field!!)
}
if (value != null) {
this.value.onNeighbourLeft(value)
}
}
field = value
}
var right: Graph6Node<T>? = null
set(value) {
if (value != null && (graph == null || value.graph !== graph)) throw IllegalStateException("Can not be neighbour with node from different graph")
if (field != value && this.value is GraphNodeListener) {
if (field != null) {
this.value.onUnNeighbourRight(field!!)
}
if (value != null) {
this.value.onNeighbourRight(value)
}
}
field = value
}
var front: Graph6Node<T>? = null
set(value) {
if (value != null && (graph == null || value.graph !== graph)) throw IllegalStateException("Can not be neighbour with node from different graph")
if (field != value && this.value is GraphNodeListener) {
if (field != null) {
this.value.onUnNeighbourFront(field!!)
}
if (value != null) {
this.value.onNeighbourFront(value)
}
}
field = value
}
var back: Graph6Node<T>? = null
set(value) {
if (value != null && (graph == null || value.graph !== graph)) throw IllegalStateException("Can not be neighbour with node from different graph")
if (field != value && this.value is GraphNodeListener) {
if (field != null) {
this.value.onUnNeighbourBack(field!!)
}
if (value != null) {
this.value.onNeighbourBack(value)
}
}
field = value
}
fun nullifyConnections() {
top?.bottom = null
bottom?.top = null
left?.right = null
right?.left = null
front?.back = null
back?.front = null
top = null
bottom = null
left = null
right = null
front = null
back = null
}
fun setToNeightbour(node: Graph6Node<T>, direction: Direction) {
when (direction) {
Direction.DOWN -> {
node.top = this
bottom = node
}
Direction.UP -> {
node.bottom = this
top = node
}
Direction.NORTH -> {
node.front = this
back = node
}
Direction.SOUTH -> {
node.back = this
front = node
}
Direction.WEST -> {
node.right = this
left = node
}
Direction.EAST -> {
node.left = this
right = node
}
}
}
var seen: Int = 0
private fun _flood(): List<GraphFlooder<T>> {
val list = ArrayList<GraphFlooder<T>>()
var seen = Int.MAX_VALUE
GraphFlooder.floodIf(top, seen) {
seen = it.seen
list.add(it)
}
GraphFlooder.floodIf(bottom, seen) {
seen = it.seen
list.add(it)
}
GraphFlooder.floodIf(left, seen) {
seen = it.seen
list.add(it)
}
GraphFlooder.floodIf(right, seen) {
seen = it.seen
list.add(it)
}
GraphFlooder.floodIf(front, seen) {
seen = it.seen
list.add(it)
}
GraphFlooder.floodIf(back, seen) {
seen = it.seen
list.add(it)
}
return list
}
fun flood(): List<GraphFlooder<T>> {
top?.bottom = null
bottom?.top = null
left?.right = null
right?.left = null
front?.back = null
back?.front = null
val list = _flood()
top?.bottom = this
bottom?.top = this
left?.right = this
right?.left = this
front?.back = this
back?.front = this
return list
}
var valid = true
private set
fun destroy(factory: () -> Abstract6Graph<T>): List<GraphFlooder<T>> {
if (!valid) return emptyList()
top?.bottom = null
bottom?.top = null
left?.right = null
right?.left = null
front?.back = null
back?.front = null
graph?.removeNode(this)
var num = 0
if (top != null) num++
if (bottom != null) num++
if (left != null) num++
if (right != null) num++
if (front != null) num++
if (back != null) num++
if (num < 2) {
return emptyList()
}
val paths = _flood()
if (paths.size < 2) {
return paths
}
var biggest = paths[0]
for (i in 1 until paths.size) {
if (biggest.size() < paths[i].size()) {
biggest = paths[i]
}
}
for (flooder in paths) {
if (flooder == biggest) continue
val graph = factory()
for (node in flooder.nodes) {
node.graph?.removeNode(node)
graph.addNode(node)
}
}
return paths
}
}

View File

@ -0,0 +1,64 @@
package ru.dbotthepony.mc.otm.graph
import java.util.*
import kotlin.collections.ArrayList
class GraphFlooder<T>(val startNode: Graph6Node<T>, @JvmField val seen: Int = nextSeen++) {
var flooded = false
private set
private val _nodes = ArrayList<Graph6Node<T>>()
@JvmField
val nodes = Collections.unmodifiableCollection(_nodes)
fun size() = _nodes.size
private fun flood(node: Graph6Node<T>) {
if (node.seen >= seen) return
_nodes.add(node)
node.seen = seen
if (node.top != null) flood(node.top!!)
if (node.bottom != null) flood(node.bottom!!)
if (node.left != null) flood(node.left!!)
if (node.right != null) flood(node.right!!)
if (node.front != null) flood(node.front!!)
if (node.back != null) flood(node.back!!)
}
fun flood() {
if (flooded) throw IllegalStateException("Already flooded")
flooded = true
_nodes.add(startNode)
startNode.seen = seen
if (startNode.top != null) flood(startNode.top!!)
if (startNode.bottom != null) flood(startNode.bottom!!)
if (startNode.left != null) flood(startNode.left!!)
if (startNode.right != null) flood(startNode.right!!)
if (startNode.front != null) flood(startNode.front!!)
if (startNode.back != null) flood(startNode.back!!)
}
companion object {
private var nextSeen = 0
fun <T> floodIf(node: Graph6Node<T>?, seen: Int, runnable: (GraphFlooder<T>) -> Unit) {
if (node != null && node.seen < seen) {
if (seen == Int.MAX_VALUE) {
val flooder = GraphFlooder(node)
flooder.flood()
runnable(flooder)
} else {
val flooder = GraphFlooder(node, seen)
flooder.flood()
runnable(flooder)
}
}
}
}
}

View File

@ -0,0 +1,23 @@
package ru.dbotthepony.mc.otm.graph.matter
import ru.dbotthepony.mc.otm.capability.matter.*
import ru.dbotthepony.mc.otm.graph.Graph6Node
interface IMatterGraphListener {
fun onPatternAdded(state: PatternState) {}
fun onPatternRemoved(state: PatternState) {}
fun onPatternUpdated(new_state: PatternState, old_state: PatternState) {}
fun onMatterTaskCreated(task: MatterTask) {}
fun onMatterTaskUpdated(new_state: MatterTask, old_state: MatterTask) {}
fun onMatterTaskFinished(state: MatterTask) {}
fun onMatterTaskRemoved(state: MatterTask) {}
}
interface IMatterGraphNode : IMatterGraphListener {
fun getMatterHandler(): IMatterHandler? = null
fun getPatternHandler(): IPatternStorage? = null
fun getTaskHandler(): IMatterTaskProvider? = null
fun getAsMatterNode(): Graph6Node<IMatterGraphNode>
fun getAsMatterGraph(): MatterNetworkGraph? = getAsMatterNode().graph as MatterNetworkGraph?
}

View File

@ -0,0 +1,416 @@
package ru.dbotthepony.mc.otm.graph.matter
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.item.Item
import net.minecraft.world.level.block.entity.BlockEntity
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.matter.*
import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.graph.Abstract6Graph
import ru.dbotthepony.mc.otm.graph.Graph6Node
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashSet
@Suppress("unused")
class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListener {
private val listeners = HashSet<IMatterGraphListener>()
fun addListener(listener: IMatterGraphListener) = listeners.add(listener)
fun removeListener(listener: IMatterGraphListener) = listeners.remove(listener)
override fun onNodeRemoved(node: Graph6Node<IMatterGraphNode>) {
val patterns = node.value.getPatternHandler()
if (patterns != null) {
for (pattern in patterns.storedPatterns) {
onPatternRemoved(pattern)
}
}
val tasks = node.value.getTaskHandler()
if (tasks != null) {
for (task in tasks.tasks) {
onMatterTaskRemoved(task)
}
}
for (pattern in getStoredPatterns()) {
node.value.onPatternRemoved(pattern)
}
for (task in getTasks()) {
node.value.onMatterTaskRemoved(task)
}
}
override fun onNodeAdded(node: Graph6Node<IMatterGraphNode>) {
for (pattern in getStoredPatterns()) {
node.value.onPatternAdded(pattern)
}
for (task in getTasks()) {
node.value.onMatterTaskCreated(task)
}
val patterns = node.value.getPatternHandler()
if (patterns != null) {
for (pattern in patterns.storedPatterns) {
onPatternAdded(pattern)
}
}
val tasks = node.value.getTaskHandler()
if (tasks != null) {
for (task in tasks.tasks) {
onMatterTaskCreated(task)
}
}
}
fun getMatterStorageLevel(): Fraction {
var level = Fraction.ZERO
for (node in _nodes) {
val matter = node.value.getMatterHandler()
if (matter != null && matter.direction == IMatterHandler.MatterDirection.BIDIRECTIONAL) {
level += matter.storedMatter
}
}
return level
}
fun getMatterStorageMaxLevel(): Fraction {
var level = Fraction.ZERO
for (node in _nodes) {
val matter = node.value.getMatterHandler()
if (matter != null && matter.direction == IMatterHandler.MatterDirection.BIDIRECTIONAL) {
level += matter.maxStoredMatter
}
}
return level
}
fun extractMatter(howMuch: Fraction, simulate: Boolean): Fraction {
if (howMuch <= Fraction.ZERO)
return Fraction.ZERO
var howMuch = howMuch
var extracted = Fraction.ZERO
for (node in _nodes) {
val matter = node.value.getMatterHandler()
if (matter != null) {
val value = matter.extractMatterOuter(howMuch, simulate)
howMuch -= value
extracted += value
if (howMuch <= Fraction.ZERO)
return extracted
}
}
return extracted
}
fun receiveMatter(howMuch: Fraction, simulate: Boolean): Fraction {
if (howMuch <= Fraction.ZERO)
return Fraction.ZERO
var howMuch = howMuch
var received = Fraction.ZERO
for (node in _nodes) {
val matter = node.value.getMatterHandler()
if (matter != null && matter.direction == IMatterHandler.MatterDirection.BIDIRECTIONAL) {
val value = matter.receiveMatterOuter(howMuch, simulate)
howMuch -= value
received += value
if (howMuch <= Fraction.ZERO)
return received
}
}
return received
}
fun receiveMatterForce(howMuch: Fraction, simulate: Boolean): Fraction {
if (howMuch <= Fraction.ZERO)
return Fraction.ZERO
var howMuch = howMuch
var received = Fraction.ZERO
for (node in _nodes) {
val matter = node.value.getMatterHandler()
if (matter != null && matter.direction != IMatterHandler.MatterDirection.EXTRACT) {
val value = matter.receiveMatterOuter(howMuch, simulate)
howMuch -= value
received += value
if (howMuch <= Fraction.ZERO)
return received
}
}
return received
}
private fun _insertPattern(state: PatternState, onlyUpdate: Boolean, simulate: Boolean): PatternInsertStatus {
for (node in _nodes) {
val storage = node.value.getPatternHandler()
if (storage != null) {
val status = storage.insertPattern(state, onlyUpdate, simulate)
if (status.status != PatternInsertStatus.Status.FAIL) {
return status
}
}
}
return PatternInsertStatus()
}
fun insertPattern(state: PatternState, onlyUpdate: Boolean, simulate: Boolean): PatternInsertStatus {
if (onlyUpdate) return _insertPattern(state, true, simulate)
val status = _insertPattern(state, true, simulate)
if (status.status != PatternInsertStatus.Status.FAIL) return status
return _insertPattern(state, false, simulate)
}
fun getTasks(): Collection<MatterTask> {
val list = ArrayList<MatterTask>()
for (node in _nodes) {
val tasks = node.value.getTaskHandler()
if (tasks != null) {
list.addAll(tasks.tasks)
}
}
return list
}
fun getStoredPatterns(): Collection<PatternState> {
val list = ArrayList<PatternState>()
for (node in _nodes) {
val storage = node.value.getPatternHandler()
if (storage != null) {
list.addAll(storage.storedPatterns)
}
}
return list
}
fun getPatternCount(): Long {
var value = 0L
for (node in _nodes) {
val storage = node.value.getPatternHandler()
if (storage != null) {
value += storage.stored
}
}
return value
}
fun getPatternCapacity(): Long {
var value = 0L
for (node in _nodes) {
val storage = node.value.getPatternHandler()
if (storage != null) {
value += storage.capacity
}
}
return value
}
fun getPattern(id: UUID): PatternState? {
for (node in _nodes) {
val storage = node.value.getPatternHandler()
if (storage != null) {
val get = storage.getPattern(id)
if (get != null) {
return get
}
}
}
return null
}
fun getPattern(state: PatternState) = getPattern(state.id)
fun hasPattern(state: PatternState) = getPattern(state.id) != null
fun hasPattern(id: UUID) = getPattern(id) != null
fun findPattern(predicate: (PatternState) -> Boolean): PatternState? {
for (node in _nodes) {
val storage = node.value.getPatternHandler()
if (storage != null) {
for (state in storage.storedPatterns) {
if (predicate(state)) {
return state
}
}
}
}
return null
}
fun findPattern(predicate: Item) = findPattern { it.item == predicate }
fun findPatterns(predicate: (PatternState) -> Boolean): Collection<PatternState> {
val list = ArrayList<PatternState>()
for (node in _nodes) {
val storage = node.value.getPatternHandler()
if (storage != null) {
for (state in storage.storedPatterns) {
if (predicate(state)) {
list.add(state)
}
}
}
}
return list
}
fun findPatterns(predicate: Item) = findPatterns { it.item == predicate }
fun allocateTask(simulate: Boolean): MatterTaskAllocation? {
for (node in _nodes) {
val tasks = node.value.getTaskHandler()
if (tasks != null) {
val allocated = tasks.allocateTask(simulate)
if (allocated != null) {
return allocated
}
}
}
return null
}
fun notifyTaskCompletion(task: MatterTask): Boolean {
for (node in _nodes) {
val tasks = node.value.getTaskHandler()
if (tasks != null && tasks.notifyTaskCompletion(task)) {
return true
}
}
return false
}
override fun onPatternAdded(state: PatternState) {
for (node in _nodes) node.value.onPatternAdded(state)
for (node in listeners) node.onPatternAdded(state)
}
override fun onPatternRemoved(state: PatternState) {
for (node in _nodes) node.value.onPatternRemoved(state)
for (node in listeners) node.onPatternRemoved(state)
}
override fun onPatternUpdated(new_state: PatternState, old_state: PatternState) {
for (node in _nodes) node.value.onPatternUpdated(new_state, old_state)
for (node in listeners) node.onPatternUpdated(new_state, old_state)
}
override fun onMatterTaskCreated(task: MatterTask) {
for (node in _nodes) node.value.onMatterTaskCreated(task)
for (node in listeners) node.onMatterTaskCreated(task)
}
override fun onMatterTaskUpdated(new_state: MatterTask, old_state: MatterTask) {
for (node in _nodes) node.value.onMatterTaskUpdated(new_state, old_state)
for (node in listeners) node.onMatterTaskUpdated(new_state, old_state)
}
override fun onMatterTaskFinished(state: MatterTask) {
for (node in _nodes) node.value.onMatterTaskFinished(state)
for (node in listeners) node.onMatterTaskFinished(state)
}
override fun onMatterTaskRemoved(state: MatterTask) {
for (node in _nodes) node.value.onMatterTaskRemoved(state)
for (node in listeners) node.onMatterTaskRemoved(state)
}
companion object {
@JvmStatic
fun discoverFull(tile: BlockEntity, node: Graph6Node<IMatterGraphNode>) {
if (tile.level !is ServerLevel)
return
return discoverFull(
tile.level!! as ServerLevel,
tile.blockPos,
node,
fun(_tile): Graph6Node<IMatterGraphNode>? {
val resolve = _tile.getCapability(MatteryCapability.MATTER_CELL)
return if (resolve.isPresent) {
resolve.resolve().get().getAsMatterNode()
} else {
null
}
},
::MatterNetworkGraph
)
}
@JvmStatic
fun discover(tile: BlockEntity, node: Graph6Node<IMatterGraphNode>): Boolean {
if (tile.level !is ServerLevel)
return false
return discover(
tile.level!! as ServerLevel,
tile.blockPos,
node,
fun(_tile): Graph6Node<IMatterGraphNode>? {
val resolve = _tile.getCapability(MatteryCapability.MATTER_CELL)
return if (resolve.isPresent) {
resolve.resolve().get().getAsMatterNode()
} else {
null
}
},
::MatterNetworkGraph
)
}
}
}

View File

@ -1,103 +1,83 @@
package ru.dbotthepony.mc.otm.menu;
package ru.dbotthepony.mc.otm.menu
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.ContainerData;
import net.minecraft.world.item.ItemStack;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterBottler;
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.menu.slot.MatterySlot;
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget;
import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget;
import ru.dbotthepony.mc.otm.network.MatterBottlerSwitchPacket;
import ru.dbotthepony.mc.otm.network.MatteryNetworking;
import ru.dbotthepony.mc.otm.client.screen.UVWindingOrder;
import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterBottler
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler
import ru.dbotthepony.mc.otm.menu.data.BooleanDataContainer
import ru.dbotthepony.mc.otm.menu.slot.MatterySlot
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget
import ru.dbotthepony.mc.otm.network.MatterBottlerSwitchPacket
import ru.dbotthepony.mc.otm.network.MatteryNetworking
public class MatterBottlerMenu extends PoweredMatteryMenu {
public MatterBottlerMenu(int p_38852_, Inventory inventory) {
this(p_38852_, inventory, null);
}
class MatterBottlerMenu @JvmOverloads constructor(
p_38852_: Int,
inventory: Inventory,
tile: BlockEntityMatterBottler? = null
) : PoweredMatteryMenu(
Registry.Menus.MATTER_BOTTLER, p_38852_, inventory, tile
) {
var workFlow = BooleanDataContainer()
public ContainerData work_flow = new ContainerData() {
private int value;
val progressWidget: ProgressGaugeWidget
val matterWidget: LevelGaugeWidget
val container = arrayOfNulls<MatterySlot>(6)
@Override
public int get(int i) {
if (tile != null) {
return ((BlockEntityMatterBottler) tile).getWorkFlow() ? 1 : 0;
init {
val container = tile?.container ?: SimpleContainer(6)
if (tile == null) {
progressWidget = ProgressGaugeWidget(this)
matterWidget = LevelGaugeWidget(this)
} else {
progressWidget = ProgressGaugeWidget(this) { tile.getWorkProgress() }
matterWidget = LevelGaugeWidget(this, tile.matter)
}
for (i in 0 until container.containerSize) {
this.container[i] = object : MatterySlot(container, i) {
override fun mayPlace(p_40231_: ItemStack): Boolean {
val cap = p_40231_.getCapability(MatteryCapability.MATTER).resolve()
if (!cap.isPresent) return false
if (workFlow.value) {
return index < 3 && cap.get().direction != IMatterHandler.MatterDirection.EXTRACT
} else {
return index >= 3 && cap.get().direction != IMatterHandler.MatterDirection.RECEIVE
}
}
}
return value;
addSlot(this.container[i]!!)
}
@Override
public void set(int i, int i1) {
value = i1;
}
addDataSlots(workFlow)
addBatterySlot()
addInventorySlots()
}
@Override
public int getCount() {
return 1;
}
};
override fun broadcastChanges() {
super.broadcastChanges()
workFlow.value = (tile as BlockEntityMatterBottler).workFlow
}
public ProgressGaugeWidget progress;
public LevelGaugeWidget matter_widget;
override fun getWorkingSlotStart(): Int {
return 0
}
public MatterySlot[] work_slots = new MatterySlot[6];
public MatterBottlerMenu(int p_38852_, Inventory inventory, BlockEntityMatterBottler tile) {
super(Registry.Menus.MATTER_BOTTLER, p_38852_, inventory, tile);
var container = tile != null ? tile.work_slots : new SimpleContainer(6);
override fun getWorkingSlotEnd(): Int {
return 7
}
fun switchBottlerMode() {
if (tile == null) {
progress = new ProgressGaugeWidget(this);
matter_widget = new LevelGaugeWidget(this);
MatteryNetworking.CHANNEL.sendToServer(MatterBottlerSwitchPacket())
} else {
progress = new ProgressGaugeWidget(this, tile::getWorkProgress);
matter_widget = new LevelGaugeWidget(this, tile.matter);
}
for (int i = 0; i < container.getContainerSize(); i++) {
work_slots[i] = new MatterySlot(container, i) {
@Override
public boolean mayPlace(ItemStack p_40231_) {
var cap = p_40231_.getCapability(MatteryCapability.MATTER).resolve();
if (work_flow.get(0) > 0) {
return index < 3 && cap.isPresent() && cap.get().getDirection() != IMatterHandler.MatterDirection.EXTRACT;
}
return index >= 3 && cap.isPresent() && cap.get().getDirection() != IMatterHandler.MatterDirection.RECEIVE;
}
};
addSlot(work_slots[i]);
}
addDataSlots(work_flow);
addBatterySlot();
addInventorySlots();
}
@Override
protected int getWorkingSlotStart() {
return 0;
}
@Override
protected int getWorkingSlotEnd() {
return 7;
}
public void switchBottlerMode() {
if (tile == null) {
MatteryNetworking.CHANNEL.sendToServer(new MatterBottlerSwitchPacket());
} else {
((BlockEntityMatterBottler) tile).switchWorkFlow();
(tile as BlockEntityMatterBottler).switchWorkFlow()
}
}
}
}

View File

@ -1,69 +1,63 @@
package ru.dbotthepony.mc.otm.menu;
package ru.dbotthepony.mc.otm.menu
import net.minecraft.world.Container;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Inventory;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterCapacitorBank;
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler;
import ru.dbotthepony.mc.otm.core.Fraction;
import ru.dbotthepony.mc.otm.menu.slot.MatterContainerInputSlot;
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget;
import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterCapacitorBank
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler
import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.menu.slot.MatterContainerInputSlot
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
import java.math.BigDecimal;
public class MatterCapacitorBankMenu extends MatteryMenu {
public MatterCapacitorBankMenu(int p_38852_, Inventory inventory) {
this(p_38852_, inventory, null);
}
public LevelGaugeWidget matter_widget;
public LevelGaugeWidget total_matter_widget;
public MatterContainerInputSlot[] container_slots = new MatterContainerInputSlot[2 * 6];
public MatterCapacitorBankMenu(int p_38852_, Inventory inventory, BlockEntityMatterCapacitorBank tile) {
super(Registry.Menus.MATTER_CAPACITOR_BANK, p_38852_, inventory, tile);
class MatterCapacitorBankMenu @JvmOverloads constructor(
p_38852_: Int,
inventory: Inventory?,
tile: BlockEntityMatterCapacitorBank? = null
) : MatteryMenu(
Registry.Menus.MATTER_CAPACITOR_BANK, p_38852_, inventory!!, tile
) {
val matter_widget: LevelGaugeWidget
val total_matter_widget: LevelGaugeWidget
val container_slots = arrayOfNulls<MatterContainerInputSlot>(2 * 6)
init {
if (tile == null) {
matter_widget = new LevelGaugeWidget(this);
total_matter_widget = new LevelGaugeWidget(this);
matter_widget = LevelGaugeWidget(this)
total_matter_widget = LevelGaugeWidget(this)
} else {
matter_widget = new LevelGaugeWidget(this, tile.matter);
total_matter_widget = new LevelGaugeWidget(this, () -> {
if (tile.getMatterGrid() != null) {
return tile.getMatterGrid().getStored();
}
return Fraction.ZERO;
}, () -> {
if (tile.getMatterGrid() != null) {
return tile.getMatterGrid().getCapacity();
}
return Fraction.ZERO;
});
matter_widget = LevelGaugeWidget(this, tile)
total_matter_widget = LevelGaugeWidget(this, {
(tile.getAsMatterNode().graph as MatterNetworkGraph?)?.getMatterStorageLevel() ?: Fraction.ZERO
}, {
(tile.getAsMatterNode().graph as MatterNetworkGraph?)?.getMatterStorageMaxLevel() ?: Fraction.ZERO
})
}
Container container = tile != null ? tile.matter_container : new SimpleContainer(2 * 6);
val container = tile?.matterContainer ?: SimpleContainer(2 * 6)
for (int row = 0; row < 2; row++){
for (int column = 0; column < 6; column++) {
container_slots[row * 6 + column] = new MatterContainerInputSlot(container, row * 6 + column, 44 + column * 18, 20 + row * 18, true, IMatterHandler.MatterDirection.BIDIRECTIONAL);
addSlot(container_slots[row * 6 + column]);
for (row in 0..1) {
for (column in 0..5) {
container_slots[row * 6 + column] = MatterContainerInputSlot(
container,
row * 6 + column,
44 + column * 18,
20 + row * 18,
true,
IMatterHandler.MatterDirection.BIDIRECTIONAL
)
addSlot(container_slots[row * 6 + column]!!)
}
}
addInventorySlots();
addInventorySlots()
}
@Override
protected int getWorkingSlotStart() {
return 0;
override fun getWorkingSlotStart(): Int {
return 0
}
@Override
protected int getWorkingSlotEnd() {
return 2 * 6;
override fun getWorkingSlotEnd(): Int {
return 2 * 6
}
}
}

View File

@ -1,214 +1,186 @@
package ru.dbotthepony.mc.otm.menu;
package ru.dbotthepony.mc.otm.menu
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.network.PacketDistributor;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterPanel;
import ru.dbotthepony.mc.otm.capability.matter.IMatterGridListener;
import ru.dbotthepony.mc.otm.capability.matter.MatterTask;
import ru.dbotthepony.mc.otm.capability.matter.PatternState;
import ru.dbotthepony.mc.otm.matter.MatterGrid;
import ru.dbotthepony.mc.otm.network.CancelMatterTaskPacket;
import ru.dbotthepony.mc.otm.network.MatterTaskPacket;
import ru.dbotthepony.mc.otm.network.MatteryNetworking;
import ru.dbotthepony.mc.otm.network.PatternGridPacket;
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraftforge.network.PacketDistributor
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterPanel
import ru.dbotthepony.mc.otm.capability.matter.MatterTask
import ru.dbotthepony.mc.otm.capability.matter.PatternState
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphListener
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.network.CancelMatterTaskPacket
import ru.dbotthepony.mc.otm.network.MatterTaskPacket
import ru.dbotthepony.mc.otm.network.MatteryNetworking
import ru.dbotthepony.mc.otm.network.PatternGridPacket
import java.util.*
import java.util.function.Consumer
import java.util.ArrayList;
import java.util.UUID;
import java.util.function.Consumer;
public class MatterPanelMenu extends MatteryMenu implements IMatterGridListener {
public MatterPanelMenu(int p_38852_, Inventory inventory) {
this(p_38852_, inventory, null);
class MatterPanelMenu @JvmOverloads constructor(
p_38852_: Int,
inventory: Inventory,
tile: BlockEntityMatterPanel? = null
) : MatteryMenu(Registry.Menus.MATTER_PANEL, p_38852_, inventory, tile), IMatterGraphListener {
fun taskUpdated(task: MatterTask) {
sendNetwork(MatterTaskPacket(true, listOf(task)))
}
private BlockEntityMatterPanel tile;
private MatterGrid grid;
public MatterPanelMenu(int p_38852_, Inventory inventory, BlockEntityMatterPanel tile) {
super(Registry.Menus.MATTER_PANEL, p_38852_, inventory, tile);
this.tile = tile;
if (tile != null) {
grid = tile.getMatterGrid();
tile.attachMenu(this);
if (grid != null) {
grid.attach(this);
}
}
}
public void taskUpdated(MatterTask task) {
sendNetwork(new MatterTaskPacket(true, task));
}
public void taskRemoved(MatterTask task) {
sendNetwork(new MatterTaskPacket(false, task));
fun taskRemoved(task: MatterTask) {
sendNetwork(MatterTaskPacket(false, listOf(task)))
}
// client code
public ArrayList<PatternState> patterns = new ArrayList<>();
public ArrayList<MatterTask> tasks = new ArrayList<>();
public int changeset = 0;
@JvmField
var patterns = ArrayList<PatternState>()
public void networkPatternsUpdated(PatternState[] patterns) {
changeset++;
@JvmField
var tasks = ArrayList<MatterTask>()
for (var pattern : patterns) {
var index_of = this.patterns.indexOf(pattern);
var changeset = 0
if (index_of != -1) {
this.patterns.set(index_of, pattern);
fun networkPatternsUpdated(patterns: Collection<PatternState>) {
changeset++
for (pattern in patterns) {
val index = this.patterns.indexOf(pattern)
if (index != -1) {
this.patterns[index] = pattern
} else {
this.patterns.add(pattern);
this.patterns.add(pattern)
}
}
}
public void networkPatternsRemoved(PatternState[] patterns) {
changeset++;
fun networkPatternsRemoved(patterns: Collection<PatternState>) {
changeset++
for (var pattern : patterns) {
this.patterns.remove(pattern);
for (pattern in patterns) {
this.patterns.remove(pattern)
}
}
public void networkTasksUpdated(MatterTask[] tasks) {
changeset++;
fun networkTasksUpdated(tasks: Collection<MatterTask>) {
changeset++
for (var task : tasks) {
var index_of = this.tasks.indexOf(task);
for (task in tasks) {
val index = this.tasks.indexOf(task)
if (index_of != -1) {
this.tasks.set(index_of, task);
if (index != -1) {
this.tasks[index] = task
} else {
this.tasks.add(task);
this.tasks.add(task)
}
if (watcher_update != null)
watcher_update.accept(task);
watcher_update?.accept(task)
}
}
public void networkTasksRemoved(MatterTask[] tasks) {
changeset++;
fun networkTasksRemoved(tasks: Collection<MatterTask>) {
changeset++
for (var task : tasks) {
this.tasks.remove(task);
if (watcher_delete != null)
watcher_delete.accept(task);
for (task in tasks) {
this.tasks.remove(task)
watcher_delete?.accept(task)
}
}
private Consumer<MatterTask> watcher_delete;
private Consumer<MatterTask> watcher_update;
private var watcher_delete: Consumer<MatterTask>? = null
private var watcher_update: Consumer<MatterTask>? = null
public void networkTaskWatcher(Consumer<MatterTask> watcher_update, Consumer<MatterTask> watcher_delete) {
this.watcher_delete = watcher_delete;
this.watcher_update = watcher_update;
fun networkTaskWatcher(watcher_update: Consumer<MatterTask>, watcher_delete: Consumer<MatterTask>) {
this.watcher_delete = watcher_delete
this.watcher_update = watcher_update
}
// server code
public void requestReplication(ServerPlayer ply, PatternState state, int how_much) {
if (tile == null)
return;
fun requestReplication(ply: ServerPlayer, state: PatternState, how_much: Int) {
val tile = tile as BlockEntityMatterPanel? ?: return
var grid = tile.getMatterGrid();
val graph = tile.getAsMatterNode().graph as MatterNetworkGraph? ?: return
if (grid == null)
return;
var get_pattern = grid.getPattern(state);
if (get_pattern == null) {
OverdriveThatMatters.LOGGER.error("Received replication request from {} of {}, but it is no longer in grid", ply, state);
return;
if (graph.getPattern(state) == null) {
OverdriveThatMatters.LOGGER.error("Received replication request from {} of {}, but it is no longer in grid", ply, state)
return
}
tile.addTask(state, how_much);
tile.addTask(state, how_much)
}
public void receiveTaskCancel(ServerPlayer ply, UUID id) {
if (tile == null)
return;
tile.removeTask(id);
fun receiveTaskCancel(ply: ServerPlayer, id: UUID) {
(tile as BlockEntityMatterPanel?)?.removeTask(id)
}
public void requestTaskCancel(UUID id) {
MatteryNetworking.CHANNEL.sendToServer(new CancelMatterTaskPacket(id));
fun requestTaskCancel(id: UUID) {
MatteryNetworking.CHANNEL.sendToServer(CancelMatterTaskPacket(id))
}
@Override
public void onPatternAdded(PatternState state) {
sendNetwork(new PatternGridPacket(true, state));
override fun onPatternAdded(state: PatternState) {
sendNetwork(PatternGridPacket(true, listOf(state)))
}
@Override
public void onPatternRemoved(PatternState state) {
sendNetwork(new PatternGridPacket(false, state));
override fun onPatternRemoved(state: PatternState) {
sendNetwork(PatternGridPacket(false, listOf(state)))
}
@Override
public void onPatternUpdated(PatternState new_state, PatternState old_state) {
sendNetwork(new PatternGridPacket(true, new_state));
override fun onPatternUpdated(new_state: PatternState, old_state: PatternState) {
sendNetwork(PatternGridPacket(true, listOf(new_state)))
}
private boolean initial_send = false;
private var initial_send = false
@Override
public void removed(Player p_38940_) {
super.removed(p_38940_);
private var listeningGrid: MatterNetworkGraph? = null
if (tile != null)
tile.deatachMenu(this);
if (grid != null)
grid.detach(this);
init {
if (tile != null) {
listeningGrid = tile.getAsMatterNode().graph as MatterNetworkGraph?
tile.attachMenu(this)
listeningGrid?.addListener(this)
}
}
@Override
public void broadcastChanges() {
super.broadcastChanges();
if (!initial_send)
fullPatternBroadcast();
override fun removed(p_38940_: Player) {
super.removed(p_38940_)
(tile as BlockEntityMatterPanel?)?.deatachMenu(this)
listeningGrid?.removeListener(this)
}
private void sendNetwork(Object packet) {
MatteryNetworking.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) inventory.player), packet);
override fun broadcastChanges() {
super.broadcastChanges()
if (!initial_send) fullPatternBroadcast()
}
public void fullPatternBroadcast() {
private fun sendNetwork(packet: Any) {
MatteryNetworking.CHANNEL.send(PacketDistributor.PLAYER.with { inventory.player as ServerPlayer }, packet)
}
fun fullPatternBroadcast() {
if (inventory.player.level.isClientSide) {
initial_send = true;
return;
initial_send = true
return
}
val tile = tile as BlockEntityMatterPanel?
if (tile != null) {
var grid = tile.getMatterGrid();
val grid = tile.getAsMatterNode().graph as MatterNetworkGraph?
if (grid != null) {
initial_send = true;
sendNetwork(new PatternGridPacket(true, grid.getStoredPatterns().toArray(new PatternState[0])));
initial_send = true
sendNetwork(PatternGridPacket(true, grid.getStoredPatterns()))
}
sendNetwork(new MatterTaskPacket(true, tile.getAllTasks().toArray(new MatterTask[0])));
sendNetwork(MatterTaskPacket(true, tile.allTasks))
}
}
@Override
protected int getWorkingSlotStart() {
return 0;
override fun getWorkingSlotStart(): Int {
return 0
}
@Override
protected int getWorkingSlotEnd() {
return 0;
override fun getWorkingSlotEnd(): Int {
return 0
}
}
}

View File

@ -11,6 +11,7 @@ import net.minecraft.world.SimpleContainer
import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.matter.MatterRegistry
import java.math.BigInteger
@ -38,8 +39,8 @@ class MatterScannerMenu @JvmOverloads constructor(
if (tile != null) {
progress = ProgressGaugeWidget(this, { tile.workProgress.toFloat() }) { tile.cantProcessJob() }
patterns = LevelGaugeWidget(this,
{ Fraction(tile.matterGrid?.storedPatternCount?.toBigInteger() ?: BigInteger.ZERO) },
{ Fraction(tile.matterGrid?.patternCapacity?.toBigInteger() ?: BigInteger.ZERO) })
{ Fraction(tile.getAsMatterGraph()?.getPatternCount()?.toBigInteger() ?: BigInteger.ZERO) },
{ Fraction(tile.getAsMatterGraph()?.getPatternCapacity()?.toBigInteger() ?: BigInteger.ZERO) })
} else {
progress = ProgressGaugeWidget(this)
patterns = LevelGaugeWidget(this)

View File

@ -1,66 +1,55 @@
package ru.dbotthepony.mc.otm.menu;
package ru.dbotthepony.mc.otm.menu
import net.minecraft.world.Container;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Inventory;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.block.entity.BlockEntityPatternStorage;
import ru.dbotthepony.mc.otm.core.Fraction;
import ru.dbotthepony.mc.otm.menu.slot.PatternSlot;
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget;
import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.block.entity.BlockEntityPatternStorage
import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.menu.slot.PatternSlot
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
public class PatternStorageMenu extends MatteryMenu {
public PatternStorageMenu(int p_38852_, Inventory inventory) {
this(p_38852_, inventory, null);
}
public PatternSlot[] pattern_slots = new PatternSlot[2 * 4];
public LevelGaugeWidget stored_this;
public LevelGaugeWidget stored_grid;
public PatternStorageMenu(int p_38852_, Inventory inventory, BlockEntityPatternStorage tile) {
super(Registry.Menus.PATTERN_STORAGE, p_38852_, inventory, tile);
class PatternStorageMenu @JvmOverloads constructor(
p_38852_: Int,
inventory: Inventory?,
tile: BlockEntityPatternStorage? = null
) : MatteryMenu(
Registry.Menus.PATTERN_STORAGE, p_38852_, inventory!!, tile
) {
val pattern_slots = arrayOfNulls<PatternSlot>(2 * 4)
val stored_this: LevelGaugeWidget
val stored_grid: LevelGaugeWidget
init {
if (tile == null) {
stored_this = new LevelGaugeWidget(this);
stored_grid = new LevelGaugeWidget(this);
stored_this = LevelGaugeWidget(this)
stored_grid = LevelGaugeWidget(this)
} else {
stored_this = new LevelGaugeWidget(this, tile.getPatternStorage());
stored_grid = new LevelGaugeWidget(this, () -> {
if (tile.getMatterGrid() != null) {
return new Fraction(tile.getMatterGrid().getStoredPatternCount());
}
return Fraction.ZERO;
}, () -> {
if (tile.getMatterGrid() != null) {
return new Fraction(tile.getMatterGrid().getPatternCapacity());
}
return Fraction.ZERO;
});
stored_this = LevelGaugeWidget(this, tile)
stored_grid = LevelGaugeWidget(this, {
Fraction((tile.getAsMatterNode().graph as MatterNetworkGraph?)?.getPatternCount() ?: 0)
}, {
Fraction((tile.getAsMatterNode().graph as MatterNetworkGraph?)?.getPatternCapacity() ?: 0)
})
}
Container patterns = tile != null ? tile.patterns : new SimpleContainer(2 * 4);
val patterns = tile?.patterns ?: SimpleContainer(2 * 4)
for (int row = 0; row < 2; row++) {
for (int column = 0; column < 4; column++) {
pattern_slots[row * 4 + column] = new PatternSlot(patterns, row * 4 + column, 48 + column * 20, 27 + row * 24);
addSlot(pattern_slots[row * 4 + column]);
for (row in 0..1) {
for (column in 0..3) {
pattern_slots[row * 4 + column] = PatternSlot(patterns, row * 4 + column, 48 + column * 20, 27 + row * 24)
addSlot(pattern_slots[row * 4 + column]!!)
}
}
addInventorySlots();
addInventorySlots()
}
@Override
protected int getWorkingSlotStart() {
return 0;
override fun getWorkingSlotStart(): Int {
return 0
}
@Override
protected int getWorkingSlotEnd() {
return 2 * 4;
override fun getWorkingSlotEnd(): Int {
return 2 * 4
}
}
}

View File

@ -1,26 +1,47 @@
package ru.dbotthepony.mc.otm.menu.data
import net.minecraft.world.inventory.ContainerData
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.network.NetworkHelper
import java.util.zip.CRC32
class FractionDataContainer : ContainerData {
companion object {
const val NETWORK_PAYLOAD_SIZE = 32
// CRC32 + Данные
const val NETWORK_PAYLOAD_SIZE = 64 + 2
private val LOGGER = LogManager.getLogger()
}
private var _value: Fraction? = Fraction.ZERO
private var _value2: Fraction? = Fraction.ZERO
fun hasComputedValue(): Boolean {
return _value != null
}
private var mute = false
var value: Fraction
get() {
if (_value != null)
return _value!!
_value = Fraction.fromByteArray(NetworkHelper.shortsToBytes(buffer))
val bytes = NetworkHelper.shortsToBytes(buffer, 2)
val crc = CRC32()
crc.update(bytes)
val crcValue = crc.value
val a = (crcValue and 0xFFFF).toShort()
val b = ((crcValue and 0xFFFF0000) ushr 16).toShort()
if (a == buffer[0] && b == buffer[1]) {
_value = Fraction.fromByteArray(bytes)
} else {
_value = _value2
}
return _value!!
}
set(value) {
@ -31,7 +52,28 @@ class FractionDataContainer : ContainerData {
return
}
NetworkHelper.bytesToShorts(_value!!.toByteArray()).copyInto(buffer)
try {
val bytes = ByteArray(128) {0}
_value!!.toByteArray().copyInto(bytes)
val crc = CRC32()
crc.update(bytes)
val crcValue = crc.value
val a = (crcValue and 0xFFFF).toShort()
val b = ((crcValue and 0xFFFF0000) ushr 16).toShort()
buffer[0] = a
buffer[1] = b
NetworkHelper.bytesToShorts(bytes).copyInto(buffer, destinationOffset = 2)
} catch(err: Throwable) {
if (!mute) {
LOGGER.error("Unable to serialize value $value for network transportation", err)
mute = true
}
buffer.fill(0)
}
}
val buffer = ShortArray(NETWORK_PAYLOAD_SIZE)
@ -42,6 +84,7 @@ class FractionDataContainer : ContainerData {
override operator fun set(p_39285_: Int, p_39286_: Int) {
buffer[p_39285_] = p_39286_.toShort()
if (_value != null) _value2 = _value
_value = null
}

View File

@ -4,8 +4,10 @@ import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import ru.dbotthepony.mc.otm.core.Fraction
import java.lang.Math.floor
import java.math.BigDecimal
import java.math.BigInteger
import kotlin.random.Random
object FractionTests {
@Test
@ -113,12 +115,121 @@ object FractionTests {
fun math() {
assert((Fraction(1) / Fraction(1)) == Fraction(1))
assert((Fraction(2) / Fraction(1)) == Fraction(2, 1))
assert((Fraction(2) / Fraction(2)) == Fraction(1))
assert((Fraction(2) / Fraction(2)) == Fraction(1)) { Fraction(2) / Fraction(2) }
assert((Fraction(4, 3) / Fraction(5, 4)) == (Fraction(4, 3) * Fraction(4, 5)))
assert((Fraction(4, 3) + Fraction(5, 4)) == Fraction(31, 12))
}
@Test
@DisplayName("Fraction compacting")
fun compacting() {
val frac = Fraction("2721280000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "25600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
println("Compacting $frac => ${frac + Fraction.ZERO}")
}
private val samples = arrayOf(
Fraction(9475, 4729),
Fraction(23535, 58723),
Fraction(-4852, 6859),
Fraction(-45623, -76849),
Fraction(38494, -76849),
Fraction(1043, -648),
)
private val samples2 = arrayOf(
(9475.0 / 4729),
(23535.0 / 58723),
(-4852.0 / 6859),
(-45623.0 / -76849),
(38494.0 / -76849),
(1043.0 / -648),
)
private val samples3 = arrayOf(
BigDecimal((9475.0 / 4729).toString()),
BigDecimal((23535.0 / 58723).toString()),
BigDecimal((-4852.0 / 6859).toString()),
BigDecimal((-45623.0 / -76849).toString()),
BigDecimal((38494.0 / -76849).toString()),
BigDecimal((1043.0 / -648).toString()),
)
@Test
@DisplayName("Fraction performance measurement")
fun performance() {
val rand = java.util.Random()
val blackHole = arrayOfNulls<Fraction>(100_000)
val size = samples.size
var time = System.currentTimeMillis()
for (i in 0 until 100_000) {
when (rand.nextInt(3)) {
0 -> blackHole[i] = samples[rand.nextInt(size)] + samples[rand.nextInt(size)]
1 -> blackHole[i] = samples[rand.nextInt(size)] - samples[rand.nextInt(size)]
2 -> blackHole[i] = samples[rand.nextInt(size)] * samples[rand.nextInt(size)]
// 3 -> blackHole[i] = samples[rand.nextInt(size)] / samples[rand.nextInt(size)]
}
}
println("Mean time for Fraction operation is ~${System.currentTimeMillis() - time} ms per 100,000 ops")
var sum = Fraction.ZERO
// перемешаем чтоб оптимизатор не отбросил
for (i in 0 until size) {
sum += blackHole[i]!!
blackHole[i] = blackHole[rand.nextInt(size)]
}
val blackHole2 = arrayOfNulls<Double>(100_000)
time = System.currentTimeMillis()
for (i in 0 until 100_000) {
when (rand.nextInt(3)) {
0 -> blackHole2[i] = samples2[rand.nextInt(size)] + samples2[rand.nextInt(size)]
1 -> blackHole2[i] = samples2[rand.nextInt(size)] - samples2[rand.nextInt(size)]
2 -> blackHole2[i] = samples2[rand.nextInt(size)] * samples2[rand.nextInt(size)]
// 3 -> blackHole2[i] = samples2[rand.nextInt(size)] / samples2[rand.nextInt(size)]
}
}
println("Mean time for Double operation is ~${System.currentTimeMillis() - time} ms per 100,000 ops")
val blackHole3 = arrayOfNulls<BigDecimal>(100_000)
time = System.currentTimeMillis()
for (i in 0 until 100_000) {
when (rand.nextInt(3)) {
0 -> blackHole3[i] = samples3[rand.nextInt(size)] + samples3[rand.nextInt(size)]
1 -> blackHole3[i] = samples3[rand.nextInt(size)] - samples3[rand.nextInt(size)]
2 -> blackHole3[i] = samples3[rand.nextInt(size)] * samples3[rand.nextInt(size)]
// 3 -> blackHole2[i] = samples2[rand.nextInt(size)] / samples2[rand.nextInt(size)]
}
}
println("Mean time for BigDecimal operation is ~${System.currentTimeMillis() - time} ms per 100,000 ops")
var sum2 = 0.0
// перемешаем чтоб оптимизатор не отбросил
for (i in 0 until size) {
sum2 += blackHole2[i]!!
blackHole2[i] = blackHole2[rand.nextInt(size)]
}
var sum3 = 0.0
// перемешаем чтоб оптимизатор не отбросил
for (i in 0 until size) {
sum3 += blackHole2[i]!!
blackHole3[i] = blackHole3[rand.nextInt(size)]
}
println("$sum $sum2 $sum3")
}
@Test
@DisplayName("Fraction serialization test")
fun serialization() {
@ -146,6 +257,26 @@ object FractionTests {
serialized = value.serializeNBT()
assert(value.compareTo(Fraction.deserializeNBT(serialized)) == 0)
value = Fraction("320", "100")
serialized = value.serializeNBT()
assert(value.compareTo(Fraction.deserializeNBT(serialized)) == 0)
value = Fraction("324", "100")
serialized = value.serializeNBT()
assert(value.compareTo(Fraction.deserializeNBT(serialized)) == 0)
value = Fraction("328", "100")
serialized = value.serializeNBT()
assert(value.compareTo(Fraction.deserializeNBT(serialized)) == 0)
value = Fraction("332", "100")
serialized = value.serializeNBT()
assert(value.compareTo(Fraction.deserializeNBT(serialized)) == 0)
value = Fraction("336", "100")
serialized = value.serializeNBT()
assert(value.compareTo(Fraction.deserializeNBT(serialized)) == 0)
}
@Test