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/ design/
libs/ libs/
logs/
# Files from Forge MDK # Files from Forge MDK
forge*changelog.txt 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.AndroidGui;
import ru.dbotthepony.mc.otm.client.EventHandler; import ru.dbotthepony.mc.otm.client.EventHandler;
import ru.dbotthepony.mc.otm.item.ItemPortableCondensationDrive; 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.matter.MatterRegistry;
import ru.dbotthepony.mc.otm.network.MatteryNetworking; import ru.dbotthepony.mc.otm.network.MatteryNetworking;
import ru.dbotthepony.mc.otm.storage.ItemStackWrapper; import ru.dbotthepony.mc.otm.storage.ItemStackWrapper;
@ -129,7 +128,6 @@ public class OverdriveThatMatters {
MinecraftForge.EVENT_BUS.register(this); MinecraftForge.EVENT_BUS.register(this);
MinecraftForge.EVENT_BUS.register(AndroidCapabilityPlayer.class); MinecraftForge.EVENT_BUS.register(AndroidCapabilityPlayer.class);
MinecraftForge.EVENT_BUS.register(AndroidCapability.class); MinecraftForge.EVENT_BUS.register(AndroidCapability.class);
MinecraftForge.EVENT_BUS.register(MatterGrid.class);
MinecraftForge.EVENT_BUS.register(MatterRegistry.class); MinecraftForge.EVENT_BUS.register(MatterRegistry.class);
MinecraftForge.EVENT_BUS.register(BlockEntityBlackHole.BlackHoleExplosionQueue.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.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.phys.shapes.VoxelShape;
import ru.dbotthepony.mc.otm.capability.matter.IMatterGridCell;
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterCable; import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterCable;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -172,62 +171,6 @@ public class BlockMatterCable extends Block implements EntityBlock {
return true; 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 @Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) { protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(CONNECTION_SOUTH, 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 net.minecraftforge.energy.IEnergyStorage;
import ru.dbotthepony.mc.otm.capability.android.IAndroidCapability; import ru.dbotthepony.mc.otm.capability.android.IAndroidCapability;
import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive; 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.IMatterHandler;
import ru.dbotthepony.mc.otm.capability.matter.IMatterTaskProvider; import ru.dbotthepony.mc.otm.capability.matter.IMatterTaskProvider;
import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage; import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage;
import ru.dbotthepony.mc.otm.core.Fraction; 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.MathContext;
import java.math.RoundingMode; 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<IMatteryEnergyStorage> ENERGY = CapabilityManager.get(new CapabilityToken<>() {});
public static final Capability<IAndroidCapability> ANDROID = 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<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<IPatternStorage> PATTERN = CapabilityManager.get(new CapabilityToken<>() {});
public static final Capability<IMatterTaskProvider> TASK = CapabilityManager.get(new CapabilityToken<>() {}); public static final Capability<IMatterTaskProvider> TASK = CapabilityManager.get(new CapabilityToken<>() {});
public static final Capability<IMatteryDrive> DRIVE = 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(IMatteryEnergyStorage.class);
event.register(IAndroidCapability.class); event.register(IAndroidCapability.class);
event.register(IMatterHandler.class); event.register(IMatterHandler.class);
event.register(IMatterGridCell.class);
event.register(IPatternStorage.class); event.register(IPatternStorage.class);
event.register(IMatterTaskProvider.class); event.register(IMatterTaskProvider.class);
event.register(IMatteryDrive.class); event.register(IMatteryDrive.class);
event.register(IStorageGridCell.class); event.register(IStorageGridCell.class);
event.register(IMatterGraphNode.class);
} }
public static final MathContext ROUND_RULES = new MathContext(32, RoundingMode.HALF_DOWN); 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) { public MatterDecomposerMenu(int containerID, Inventory inventory, @Nullable BlockEntityMatterDecomposer tile) {
super(Registry.Menus.MATTER_DECOMPOSER, containerID, inventory, 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) { 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) { public MatterReplicatorMenu(int p_38852_, Inventory inventory, BlockEntityMatterReplicator tile) {
super(Registry.Menus.MATTER_REPLICATOR, p_38852_, inventory, 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++) { for (int i = 0; i < container.getContainerSize(); i++) {
output_slots[i] = new MachineOutputSlot(container, i, 64 + 18 * i, 38, true); 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 ru.dbotthepony.mc.otm.menu.MatterPanelMenu;
import javax.annotation.ParametersAreNonnullByDefault; import javax.annotation.ParametersAreNonnullByDefault;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects; import java.util.Objects;
import java.util.function.Supplier; import java.util.function.Supplier;
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
public record MatterTaskPacket(boolean action, MatterTask...state) { public record MatterTaskPacket(boolean action, Collection<MatterTask> state) {
public void write(FriendlyByteBuf buffer) { public void write(FriendlyByteBuf buffer) {
buffer.writeBoolean(action); buffer.writeBoolean(action);
buffer.writeInt(state.length); buffer.writeInt(state.size());
for (var state1 : state) for (var state1 : state)
state1.write(buffer); state1.write(buffer);
@ -42,10 +44,10 @@ public record MatterTaskPacket(boolean action, MatterTask...state) {
public static MatterTaskPacket read(FriendlyByteBuf buffer) { public static MatterTaskPacket read(FriendlyByteBuf buffer) {
boolean action = buffer.readBoolean(); boolean action = buffer.readBoolean();
int amount = buffer.readInt(); int amount = buffer.readInt();
var list = new MatterTask[amount]; var list = new ArrayList<MatterTask>(amount);
for (int i = 0; i < amount; i++) 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); return new MatterTaskPacket(action, list);
} }

View File

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

View File

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

View File

@ -44,3 +44,11 @@ fun CompoundTag.ifHas(s: String, type: Byte, consumer: (Tag) -> Unit) {
consumer(tag) 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.MethodsReturnNonnullByDefault
import net.minecraft.core.BlockPos; import javax.annotation.ParametersAreNonnullByDefault
import net.minecraft.world.level.Level; import ru.dbotthepony.mc.otm.block.BlockMatteryRotatable
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.EntityBlock; import net.minecraft.core.BlockPos
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.Level
import net.minecraft.world.level.block.entity.BlockEntityTicker; import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.StateDefinition; import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterBottler
import ru.dbotthepony.mc.otm.Registry; import net.minecraft.world.level.block.entity.BlockEntityType
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterBottler; import net.minecraft.world.level.block.entity.BlockEntityTicker
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState; import net.minecraft.world.level.block.state.StateDefinition
import ru.dbotthepony.mc.otm.Registry
import javax.annotation.Nullable; import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import javax.annotation.ParametersAreNonnullByDefault;
@MethodsReturnNonnullByDefault @MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
public class BlockMatterBottler extends BlockMatteryRotatable implements EntityBlock { class BlockMatterBottler : BlockMatteryRotatable(), EntityBlock {
@Nullable override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity? {
@Override return BlockEntityMatterBottler(blockPos, blockState)
public BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
return new BlockEntityMatterBottler(blockPos, blockState);
} }
@Nullable override fun <T : BlockEntity?> getTicker(
@Override p_153212_: Level,
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level p_153212_, BlockState p_153213_, BlockEntityType<T> p_153214_) { p_153213_: BlockState,
return p_153212_.isClientSide || p_153214_ != Registry.BlockEntities.MATTER_BOTTLER ? null : BlockEntityMatterBottler::tick; 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 override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) { super.createBlockStateDefinition(builder)
super.createBlockStateDefinition(builder); builder.add(WorkerState.SEMI_WORKER_STATE)
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.MethodsReturnNonnullByDefault
import net.minecraft.core.BlockPos; import javax.annotation.ParametersAreNonnullByDefault
import net.minecraft.core.Direction; import ru.dbotthepony.mc.otm.block.BlockMatteryRotatable
import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.Level; import net.minecraft.core.BlockPos
import net.minecraft.world.level.block.Block; import net.minecraft.core.Direction
import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntityTicker; import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterDecomposer
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.entity.BlockEntityTicker
import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.level.BlockGetter
import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.level.Level
import ru.dbotthepony.mc.otm.Registry; import net.minecraft.world.level.block.Block
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterDecomposer; import net.minecraft.world.phys.shapes.CollisionContext
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState; import net.minecraft.world.phys.shapes.VoxelShape
import ru.dbotthepony.mc.otm.shapes.BlockShapes; import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.block.BlockMatterDecomposer
import javax.annotation.Nullable; import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import javax.annotation.ParametersAreNonnullByDefault; import ru.dbotthepony.mc.otm.shapes.BlockShapes
import java.util.List;
@MethodsReturnNonnullByDefault @MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
public class BlockMatterDecomposer extends BlockMatteryRotatable implements EntityBlock { class BlockMatterDecomposer : BlockMatteryRotatable(), EntityBlock {
@Nullable override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity? {
@Override return BlockEntityMatterDecomposer(blockPos, blockState)
public BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
return new BlockEntityMatterDecomposer(blockPos, blockState);
} }
@Nullable override fun <T : BlockEntity?> getTicker(
@Override p_153212_: Level,
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level p_153212_, BlockState p_153213_, BlockEntityType<T> p_153214_) { p_153213_: BlockState,
return p_153212_.isClientSide || p_153214_ != Registry.BlockEntities.MATTER_DECOMPOSER ? null : BlockEntityMatterDecomposer::tick; 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 override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) { super.createBlockStateDefinition(builder)
super.createBlockStateDefinition(builder); builder.add(WorkerState.WORKER_STATE)
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 { companion object {
var def = BlockShapes.MATTER_DECOMPOSER.computeShape(); private val def = BlockShapes.MATTER_DECOMPOSER.computeShape()
SHAPES = List.of( private val SHAPES: List<VoxelShape> = listOf(
def, def,
def, def,
def, def,
BlockShapes.MATTER_DECOMPOSER.rotate(Direction.NORTH).computeShape(), BlockShapes.MATTER_DECOMPOSER.rotate(Direction.NORTH).computeShape(),
BlockShapes.MATTER_DECOMPOSER.rotate(Direction.WEST).computeShape(), BlockShapes.MATTER_DECOMPOSER.rotate(Direction.WEST).computeShape(),
BlockShapes.MATTER_DECOMPOSER.rotate(Direction.EAST).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 valid = true
private var resolver = LazyOptional.of {energy} 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)) if (valid && (cap == MatteryCapability.ENERGY || cap == CapabilityEnergy.ENERGY) && side != blockState.getValue(BlockMatteryRotatable.FACING))
return resolver.cast() 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.MethodsReturnNonnullByDefault
import net.minecraft.core.BlockPos; import javax.annotation.ParametersAreNonnullByDefault
import net.minecraft.core.Direction; import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag; import net.minecraft.core.Direction
import net.minecraft.network.chat.Component; import net.minecraft.world.level.block.state.BlockState
import net.minecraft.network.chat.TranslatableComponent; import ru.dbotthepony.mc.otm.container.MatteryContainer
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.item.ItemStack
import net.minecraft.world.entity.player.Player; import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler
import net.minecraft.world.inventory.AbstractContainerMenu; import ru.dbotthepony.mc.otm.capability.MatteryCapability
import net.minecraft.world.item.ItemStack; import ru.dbotthepony.mc.otm.capability.matter.MatterHandlerCapability
import net.minecraft.world.level.Level; import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler.MatterDirection
import net.minecraft.world.level.block.Block; import net.minecraftforge.common.util.LazyOptional
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraftforge.items.CapabilityItemHandler
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.entity.player.Inventory
import net.minecraftforge.common.capabilities.Capability; import net.minecraft.world.entity.player.Player
import net.minecraftforge.common.util.LazyOptional; import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraftforge.items.CapabilityItemHandler; import ru.dbotthepony.mc.otm.menu.MatterBottlerMenu
import ru.dbotthepony.mc.otm.Registry; import net.minecraft.nbt.CompoundTag
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState; import net.minecraft.network.chat.Component
import ru.dbotthepony.mc.otm.capability.*; import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.IMatterGridCell; import net.minecraft.network.chat.TranslatableComponent
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler; import net.minecraft.server.level.ServerLevel
import ru.dbotthepony.mc.otm.capability.matter.MatterHandlerCapability; import net.minecraft.world.level.Level
import ru.dbotthepony.mc.otm.container.MatteryContainer; import net.minecraft.world.level.block.Block
import ru.dbotthepony.mc.otm.container.MatteryContainerHandler; import net.minecraftforge.common.capabilities.Capability
import ru.dbotthepony.mc.otm.core.Fraction; import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.matter.MatterGrid; import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.menu.MatterBottlerMenu; import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.graph.Graph6Node
import javax.annotation.Nonnull; import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import javax.annotation.Nullable; import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import javax.annotation.ParametersAreNonnullByDefault; import ru.dbotthepony.mc.otm.ifHas
import java.math.BigDecimal; import ru.dbotthepony.mc.otm.set
@MethodsReturnNonnullByDefault @MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
public class BlockEntityMatterBottler extends BlockEntityMatteryPowered implements IMatterGridCell { class BlockEntityMatterBottler(p_155229_: BlockPos, p_155230_: BlockState) :
public BlockEntityMatterBottler(BlockPos p_155229_, BlockState p_155230_) { BlockEntityMatteryPowered(Registry.BlockEntities.MATTER_BOTTLER, p_155229_, p_155230_), IMatterGraphNode {
super(Registry.BlockEntities.MATTER_BOTTLER, p_155229_, p_155230_);
energy = new MatteryMachineEnergyStorage(this, MatteryMachineEnergyStorage.MachineType.WORKER);
}
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() { override fun getAsMatterNode(): Graph6Node<IMatterGraphNode> {
return work_flow; return node
}
public void setWorkFlow(boolean work_flow) {
this.work_flow = work_flow;
this.setChanged();
}
public void switchWorkFlow() {
setWorkFlow(!work_flow);
} }
// true - bottling // true - bottling
// false - unbottling // 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 // true - continue even if empty when bottling / if full while unbottling
// false - spit into output slot // 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) { @JvmField
@Override val container: MatteryContainer = object : MatteryContainer(this::setChangedLight, 6) {
public int getMaxStackSize(int slot) { override fun getMaxStackSize(slot: Int): Int {
return 1; return 1
} }
}; }
public final MatteryContainerHandler work_slots_handler = work_slots.handler((slot, stack) -> { val itemHandler = container.handler({ slot: Int, stack: ItemStack ->
if (work_flow) { if (this.workFlow) {
return slot < 3 && stack.getCapability(MatteryCapability.MATTER).isPresent(); 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(); private var initialCapacity: Fraction? = null
}, (slot, amount, stack) -> { private var lastWorkStack: ItemStack? = null
if (work_flow) {
return slot >= 3;
}
return slot < 3; override fun getMatterHandler(): IMatterHandler {
}); return matter
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 override fun setLevel(p_155231_: Level) {
public boolean isValidMatterCell() { super.setLevel(p_155231_)
return valid;
if (p_155231_ is ServerLevel)
MatterNetworkGraph.discoverFull(this, node)
} }
@Override private var valid = true
public void setMatterGrid(MatterGrid grid) {
this.grid = grid; override fun invalidateCaps() {
super.invalidateCaps()
valid = false
itemHandler.invalidate()
matter.invalidate()
} }
@Nullable override fun reviveCaps() {
@Override super.reviveCaps()
public IMatterHandler getMatterHandler() { valid = true
return matter; itemHandler.revive()
matter.revive()
} }
@Override override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
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) {
if (valid) { if (valid) {
if (cap == MatteryCapability.MATTER) { if (cap === MatteryCapability.MATTER) {
return matter.get().cast(); return matter.get().cast()
} }
if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { if (cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
return work_slots_handler.get().cast(); return itemHandler.get().cast()
} }
if (cap == MatteryCapability.MATTER_CELL) { if (cap === MatteryCapability.MATTER_CELL) {
return cell_resolver.cast(); return resolverNode.cast()
} }
} }
return super.getCapability(cap, side); return super.getCapability(cap, side)
} }
@Override override fun getDefaultDisplayName(): Component {
protected Component getDefaultDisplayName() { return MACHINE_NAME
return MACHINE_NAME;
} }
@Nullable override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
@Override return MatterBottlerMenu(containerID, inventory, this)
public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply) {
return new MatterBottlerMenu(containerID, inventory, this);
} }
@Override override fun saveAdditional(nbt: CompoundTag) {
public void saveAdditional(CompoundTag nbt) { super.saveAdditional(nbt)
super.saveAdditional(nbt); nbt["work_slots"] = container.serializeNBT()
nbt.put("work_slots", work_slots.serializeNBT()); nbt["work_flow"] = this.workFlow
nbt.putBoolean("work_flow", work_flow); nbt["matter_capability"] = matter.serializeNBT()
nbt.put("matter_capability", matter.serializeNBT());
} }
@Override override fun load(nbt: CompoundTag) {
public void load(CompoundTag nbt) { super.load(nbt)
super.load(nbt); container.deserializeNBT(nbt["work_slots"])
work_slots.deserializeNBT(nbt.get("work_slots")); workFlow = nbt.getBoolean("work_flow")
work_flow = nbt.getBoolean("work_flow");
if (nbt.get("matter_capability") instanceof CompoundTag _matter) nbt.ifHas("matter_capability", CompoundTag::class.java) {
matter.deserializeNBT(_matter); matter.deserializeNBT(it)
}
} }
private static final Fraction EXTRACTION_TICKS = new Fraction(200); init {
energy = MatteryMachineEnergyStorage(this, MatteryMachineEnergyStorage.MachineType.WORKER)
}
public float getWorkProgress() { fun getWorkProgress(): Float {
if (last_work_stack == null) { if (lastWorkStack == null) {
return 0; return 0f
} }
var cap = last_work_stack.getCapability(MatteryCapability.MATTER).resolve(); val resolver = lastWorkStack!!.getCapability(MatteryCapability.MATTER).resolve()
if (cap.isEmpty()) { if (resolver.isEmpty) {
return 0; return 0f
} }
if (work_flow) { val cap = resolver.get()
if (cap.get().getMaxStoredMatter().minus(initial_capacity).compareTo(Fraction.ZERO) <= 0) {
return 0; 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) { if (initialCapacity!! <= Fraction.ZERO) {
return 0; 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) { fun tick() {
if (t instanceof BlockEntityMatterBottler tile) { batteryChargeLoop()
tile.batteryChargeLoop();
if (tile.isBlockedByRedstone()) { if (isBlockedByRedstone) {
if (tile.getBlockState().getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.IDLE) { if (blockState.getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.IDLE) {
level.setBlock(tile.getBlockPos(), tile.getBlockState().setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS); level!!.setBlock(
} blockPos,
blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE),
return; Block.UPDATE_CLIENTS
)
} }
ItemStack work_stack = null; return
IMatterHandler capability = null; }
int align = tile.work_flow ? 0 : 3;
int work_slot = -1;
for (int i = align; i < align + 3; i++) { var work_stack: ItemStack? = null
var get = tile.work_slots.getItem(i); 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()) { for (i in align until align + 3) {
var cap = get.getCapability(MatteryCapability.MATTER).resolve(); 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)) { if (!itemStack.isEmpty) {
work_stack = get; val cap = itemStack.getCapability(MatteryCapability.MATTER).resolve()
capability = cap.get();
work_slot = i; if (cap.isPresent && cap.get().direction != unexpectedDirection) {
break; 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) { if (work_stack == null) {
tile.last_work_stack = null; lastWorkStack = null
tile.initial_capacity = null; initialCapacity = null
} else if (work_stack != tile.last_work_stack) { } else if (work_stack != lastWorkStack) {
tile.last_work_stack = work_stack; lastWorkStack = work_stack
tile.initial_capacity = capability.getStoredMatter(); 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 (workFlow) {
if (capability != null) { if (matter.storedMatter < MATTER_EXCHANGE_RATE && graph != null) {
if (tile.getBlockState().getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.WORKING) { val extracted = graph.extractMatter(
level.setBlock(tile.getBlockPos(), tile.getBlockState().setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.WORKING), Block.UPDATE_CLIENTS); 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 (matter.storedMatter > Fraction.ZERO) {
if (tile.grid != null) { val energyExtracted = energy.extractEnergyInner(ENERGY_CONSUMPTION, true)
var extracted = tile.grid.extractMatter(
tile.matter.getMissingMatter()
.min(MATTER_EXCHANGE_RATE.times(EXTRACTION_TICKS))
.min(capability.getMissingMatter().minus(tile.matter.getStoredMatter()))
, true);
if (extracted.compareTo(Fraction.ZERO) > 0) { if (!energyExtracted.isZero()) {
var received = tile.matter.receiveMatterOuter(extracted, false); val matter = capability.receiveMatterOuter(MATTER_EXCHANGE_RATE.min(matter.storedMatter) * (energyExtracted / ENERGY_CONSUMPTION), true)
tile.grid.extractMatter(received, false);
}
}
}
if (tile.matter.getStoredMatter().compareTo(Fraction.ZERO) > 0) { if (!matter.isZero()) {
var energy = tile.energy.extractEnergyInner(ENERGY_CONSUMPTION, true); energy.extractEnergyInner(ENERGY_CONSUMPTION * matter / MATTER_EXCHANGE_RATE,false)
if (energy.compareTo(Fraction.ZERO) > 0) { capability.receiveMatterOuter(matter, false)
var matter = capability.receiveMatterOuter(MATTER_EXCHANGE_RATE.min(tile.matter.getStoredMatter()).times(energy.div(ENERGY_CONSUMPTION)), true); this.matter.extractMatterInner(matter, false)
if (matter.compareTo(Fraction.ZERO) > 0) { if (capability.missingMatter.isZero()) {
tile.energy.extractEnergyInner(ENERGY_CONSUMPTION.times(matter.div(MATTER_EXCHANGE_RATE)), false); for (i in 3..5) {
capability.receiveMatterOuter(matter, false); if (container.getItem(i).isEmpty) {
tile.matter.extractMatterInner(matter, false); container.setItem(work_slot, ItemStack.EMPTY)
container.setItem(i, work_stack!!)
if (capability.getMissingMatter().compareTo(Fraction.ZERO) == 0) { break
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;
}
} }
} }
} }
} }
} }
} 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 { } else {
if (capability != null) { val energyExtracted = energy.extractEnergyInner(ENERGY_CONSUMPTION, true)
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);
}
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) { if (!matter.isZero()) {
var matter = capability.extractMatterOuter(MATTER_EXCHANGE_RATE.min(tile.matter.getMissingMatter()).times(energy.div(ENERGY_CONSUMPTION)), true); this.energy.extractEnergyInner(ENERGY_CONSUMPTION * matter / MATTER_EXCHANGE_RATE,false)
if (matter.compareTo(Fraction.ZERO) > 0) { capability.extractMatterOuter(matter, false)
tile.energy.extractEnergyInner(ENERGY_CONSUMPTION.times(matter.div(MATTER_EXCHANGE_RATE)), false); this.matter.receiveMatterInner(matter, false)
capability.extractMatterOuter(matter, false);
tile.matter.receiveMatterInner(matter, false);
if (capability.getStoredMatter().compareTo(Fraction.ZERO) == 0) { if (capability.storedMatter.isZero()) {
for (int i = 2; i >= 0; i--) { for (i in 2 downTo 0) {
if (tile.work_slots.getItem(i).isEmpty()) { if (container.getItem(i).isEmpty) {
tile.work_slots.setItem(work_slot, ItemStack.EMPTY); container.setItem(work_slot, ItemStack.EMPTY)
tile.work_slots.setItem(i, work_stack); container.setItem(i, work_stack!!)
break; 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.MethodsReturnNonnullByDefault
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos
import net.minecraft.core.Direction; import net.minecraft.core.Direction
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component
import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.world.entity.player.Inventory; import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack; import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.level.Level; import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.Block
import net.minecraftforge.common.capabilities.Capability; import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.capabilities.Capability
import ru.dbotthepony.mc.otm.block.BlockBatteryBank; import net.minecraftforge.common.util.LazyOptional
import ru.dbotthepony.mc.otm.capability.matter.IMatterGridCell; import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.core.Fraction; import ru.dbotthepony.mc.otm.block.BlockBatteryBank
import ru.dbotthepony.mc.otm.matter.MatterGrid; import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.Registry; import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler; import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler.MatterDirection
import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage; import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.capability.MatteryCapability; import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.container.MatteryContainer; import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.menu.MatterCapacitorBankMenu; import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import javax.annotation.Nonnull; import ru.dbotthepony.mc.otm.menu.MatterCapacitorBankMenu
import javax.annotation.Nullable; import ru.dbotthepony.mc.otm.set
import javax.annotation.ParametersAreNonnullByDefault; import javax.annotation.ParametersAreNonnullByDefault
import java.math.BigDecimal;
import java.util.Optional;
@MethodsReturnNonnullByDefault @MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
public class BlockEntityMatterCapacitorBank extends BlockEntityMattery implements IMatterGridCell { class BlockEntityMatterCapacitorBank(p_155229_: BlockPos, p_155230_: BlockState) :
public final IMatterHandler matter = new IMatterHandler() { BlockEntityMattery(Registry.BlockEntities.MATTER_CAPACITOR_BANK, p_155229_, p_155230_), IMatterGraphNode, IMatterHandler {
@Nonnull
@Override
public Fraction getStoredMatter() {
Fraction summ = Fraction.ZERO;
for (int i = 0; i < matter_container.getContainerSize(); i++) { private val node = Graph6Node<IMatterGraphNode>(this)
ItemStack stack = matter_container.getItem(i); private val resolverNode = LazyOptional.of { this }
if (!stack.isEmpty()) { override fun getAsMatterNode(): Graph6Node<IMatterGraphNode> {
Optional<IMatterHandler> handler = stack.getCapability(MatteryCapability.MATTER).resolve(); return node
}
if (handler.isPresent()) { override fun getStoredMatter(): Fraction {
summ = summ.plus(handler.get().getStoredMatter()); 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 return summ
@Override }
public Fraction getMaxStoredMatter() {
Fraction summ = Fraction.ZERO;
for (int i = 0; i < matter_container.getContainerSize(); i++) { override fun extractMatterOuter(howMuch: Fraction, simulate: Boolean): Fraction {
ItemStack stack = matter_container.getItem(i); return extractMatterInner(howMuch, simulate)
}
if (!stack.isEmpty()) { override fun extractMatterInner(howMuch: Fraction, simulate: Boolean): Fraction {
Optional<IMatterHandler> handler = stack.getCapability(MatteryCapability.MATTER).resolve(); var howMuch = howMuch
var summ = Fraction.ZERO
if (handler.isPresent()) { for (stack in matterContainer) {
summ = summ.plus(handler.get().getMaxStoredMatter()); 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 fun getDirection(): MatterDirection {
@Override return MatterDirection.BIDIRECTIONAL
public Fraction receiveMatterOuter(Fraction howMuch, boolean simulate) { }
return receiveMatterInner(howMuch, simulate);
}
@Nonnull private var resolver = LazyOptional.of { this }
@Override
public Fraction receiveMatterInner(Fraction howMuch, boolean simulate) {
Fraction summ = Fraction.ZERO;
for (int i = 0; i < matter_container.getContainerSize(); i++) { @JvmField
ItemStack stack = matter_container.getItem(i); val matterContainer = object : MatteryContainer(this::setChangedLight, 6 * 2) {
override fun setChanged(slot: Int, new_state: ItemStack, old_state: ItemStack) {
if (!stack.isEmpty()) { super.setChanged(slot, new_state, old_state)
Optional<IMatterHandler> handler = stack.getCapability(MatteryCapability.MATTER).resolve(); val level = level
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);
if (level != null) { if (level != null) {
var state = getBlockState(); var state = blockState
for (int i = 0; i < BlockBatteryBank.BATTERY_SLOTS_PROPS.length; i++) { for (i in BlockBatteryBank.BATTERY_SLOTS_PROPS.indices) {
state = state.setValue(BlockBatteryBank.BATTERY_SLOTS_PROPS[i], getItem(i).getCapability(MatteryCapability.MATTER).isPresent()); state = state.setValue(
BlockBatteryBank.BATTERY_SLOTS_PROPS[i],
getItem(i).getCapability(MatteryCapability.MATTER).isPresent
)
} }
if (state != getBlockState()) { if (state !== blockState) {
level.setBlock(getBlockPos(), state, Block.UPDATE_CLIENTS); 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"); companion object {
private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.matter_capacitor_bank")
@Override
protected Component getDefaultDisplayName() {
return MACHINE_NAME;
} }
@Override override fun getDefaultDisplayName(): Component {
public void saveAdditional(CompoundTag nbt) { return MACHINE_NAME
super.saveAdditional(nbt);
nbt.put("matter_container", matter_container.serializeNBT());
} }
@Override override fun saveAdditional(nbt: CompoundTag) {
public void load(CompoundTag nbt) { super.saveAdditional(nbt)
matter_container.deserializeNBT(nbt.get("matter_container")); nbt["matter_container"] = matterContainer.serializeNBT()
super.load(nbt);
} }
@Nullable override fun load(nbt: CompoundTag) {
@Override matterContainer.deserializeNBT(nbt["matter_container"])
public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply) { super.load(nbt)
return new MatterCapacitorBankMenu(containerID, inventory, this);
} }
private boolean valid = true; override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
return MatterCapacitorBankMenu(containerID, inventory, this)
@Override
public void invalidateCaps() {
super.invalidateCaps();
valid = false;
resolver.invalidate();
resolver_grid.invalidate();
} }
@Override private var valid = true
public void reviveCaps() {
super.reviveCaps(); override fun invalidateCaps() {
valid = true; super.invalidateCaps()
resolver = LazyOptional.of(() -> matter); valid = false
resolver_grid = LazyOptional.of(() -> this); resolver.invalidate()
} }
private LazyOptional<IMatterGridCell> resolver_grid = LazyOptional.of(() -> this); override fun reviveCaps() {
super.reviveCaps()
valid = true
resolver = LazyOptional.of { this }
}
@Nonnull override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
if (valid) { if (valid) {
if (cap == MatteryCapability.MATTER) if (cap === MatteryCapability.MATTER) return resolver.cast()
return resolver.cast(); if (cap === MatteryCapability.MATTER_CELL) return resolverNode.cast()
if (cap == MatteryCapability.MATTER_CELL)
return resolver_grid.cast();
} }
return super.getCapability(cap, side); return super.getCapability(cap, side)
} }
private MatterGrid grid; override fun setRemoved() {
super.setRemoved()
@Nullable node.destroy(::MatterNetworkGraph)
@Override
public MatterGrid getMatterGrid() {
return grid;
} }
@Override override fun setLevel(p_155231_: Level) {
public void setRemoved() { super.setLevel(p_155231_)
super.setRemoved();
if (grid != null) if (p_155231_ is ServerLevel)
grid.remove(this); MatterNetworkGraph.discoverFull(this, node)
} }
@Override override fun getMatterHandler(): IMatterHandler {
public void setLevel(Level p_155231_) { return this
super.setLevel(p_155231_);
if (!p_155231_.isClientSide)
MatterGrid.scheduleDiscoverNeighbours(this, getBlockPos(), p_155231_);
}
@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.MethodsReturnNonnullByDefault
import net.minecraft.core.BlockPos; import javax.annotation.ParametersAreNonnullByDefault
import net.minecraft.core.Direction; import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag; import net.minecraft.core.Direction
import net.minecraft.nbt.ListTag; import net.minecraft.world.level.block.state.BlockState
import net.minecraft.nbt.Tag; import ru.dbotthepony.mc.otm.capability.matter.IMatterTaskProvider
import net.minecraft.network.chat.Component; import ru.dbotthepony.mc.otm.menu.MatterPanelMenu
import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player
import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraftforge.common.util.LazyOptional
import net.minecraft.world.level.Level; import ru.dbotthepony.mc.otm.capability.MatteryCapability
import net.minecraft.world.level.block.state.BlockState; import java.util.HashMap
import net.minecraftforge.common.capabilities.Capability; import java.util.UUID
import net.minecraftforge.common.util.LazyOptional; import ru.dbotthepony.mc.otm.capability.matter.MatterTask
import ru.dbotthepony.mc.otm.Registry; import java.util.stream.Collectors
import ru.dbotthepony.mc.otm.capability.*; import ru.dbotthepony.mc.otm.capability.matter.MatterTaskAllocation
import ru.dbotthepony.mc.otm.capability.matter.*; import ru.dbotthepony.mc.otm.capability.matter.PatternState
import ru.dbotthepony.mc.otm.matter.MatterGrid; import net.minecraft.nbt.CompoundTag
import ru.dbotthepony.mc.otm.menu.MatterPanelMenu; import net.minecraft.nbt.ListTag
import net.minecraft.nbt.Tag
import javax.annotation.Nonnull; import net.minecraft.network.chat.Component
import javax.annotation.Nullable; import net.minecraft.network.chat.TranslatableComponent
import javax.annotation.ParametersAreNonnullByDefault; import net.minecraft.server.level.ServerLevel
import java.util.*; import net.minecraft.world.level.Level
import java.util.stream.Collectors; 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 @MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
public class BlockEntityMatterPanel extends BlockEntityMattery implements IMatterGridCell, IMatterTaskProvider { class BlockEntityMatterPanel(p_155229_: BlockPos, p_155230_: BlockState) :
public BlockEntityMatterPanel(BlockPos p_155229_, BlockState p_155230_) { BlockEntityMattery(Registry.BlockEntities.MATTER_PANEL, p_155229_, p_155230_), IMatterGraphNode, IMatterTaskProvider {
super(Registry.BlockEntities.MATTER_PANEL, p_155229_, p_155230_);
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"); fun attachMenu(menu: MatterPanelMenu) {
listeners.add(menu)
private final ArrayList<MatterPanelMenu> listeners = new ArrayList<>();
public void attachMenu(MatterPanelMenu menu) {
listeners.add(menu);
} }
public void deatachMenu(MatterPanelMenu menu) { fun deatachMenu(menu: MatterPanelMenu) {
listeners.remove(menu); listeners.remove(menu)
} }
@Override override fun getDefaultDisplayName(): Component {
protected Component getDefaultDisplayName() { return NAME
return NAME;
} }
@Nullable override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
@Override return MatterPanelMenu(containerID, inventory, this)
public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply) {
return new MatterPanelMenu(containerID, inventory, this);
} }
private boolean valid = true; private var valid = true
@Override override fun invalidateCaps() {
public void invalidateCaps() { super.invalidateCaps()
super.invalidateCaps(); valid = false
valid = false; resolver.invalidate()
resolver.invalidate();
} }
@Override override fun reviveCaps() {
public void reviveCaps() { super.reviveCaps()
super.reviveCaps(); valid = true
valid = true; resolver = LazyOptional.of { this }
resolver = LazyOptional.of(() -> this);
} }
private LazyOptional<BlockEntityMatterPanel> resolver = LazyOptional.of(() -> this); private var resolver = LazyOptional.of { this }
@Nonnull override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
@Override if (valid && (cap === MatteryCapability.MATTER_CELL || cap === MatteryCapability.TASK))
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) { return resolver.cast()
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 if (p_155231_ is ServerLevel)
public void setLevel(Level p_155231_) { MatterNetworkGraph.discoverFull(this, node)
super.setLevel(p_155231_);
if (grid == null)
scheduleDiscoverNeighbours(p_155231_, getBlockPos());
} }
@Override override fun setRemoved() {
public void setRemoved() { super.setRemoved()
super.setRemoved(); node.destroy(::MatterNetworkGraph)
if (level != null && !level.isClientSide && grid != null)
grid.remove(this);
} }
@Nullable override fun getTaskHandler(): IMatterTaskProvider? {
@Override return this
public MatterGrid getMatterGrid() {
return grid;
} }
@Override private val tasks = HashMap<UUID, MatterTask?>()
public boolean isValidMatterCell() {
return valid; override fun getTasks(): Collection<MatterTask> {
return tasks.values.stream().filter { task: MatterTask? -> task!!.required() > 0 }.collect(Collectors.toList()) as Collection<MatterTask>
} }
@Override override fun getAllTasks(): Collection<MatterTask> {
public void setMatterGrid(MatterGrid grid) { return List.copyOf(tasks.values) as Collection<MatterTask>
this.grid = grid;
} }
@Nullable override fun allocateTask(simulate: Boolean): MatterTaskAllocation? {
@Override val graph = node.graph as MatterNetworkGraph? ?: return null
public IMatterTaskProvider getTaskProvider() {
return this;
}
private final HashMap<UUID, MatterTask> tasks = new HashMap<>(); for ((key, task) in tasks) {
if (task!!.required > 0) {
val getPattern = graph.getPattern(task.pattern!!)
@Nonnull if (getPattern != null) {
@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 (!simulate) { if (!simulate) {
var newer = task.shrinkRequired(1); val new = task.shrinkRequired(1)
tasks.put(entry.getKey(), newer); tasks[key] = new
listeners.forEach(menu -> menu.taskUpdated(newer)); listeners.forEach { menu: MatterPanelMenu -> menu.taskUpdated(new) }
grid.onMatterTaskUpdated(newer, task); graph.onMatterTaskUpdated(new, task)
setChanged(); setChanged()
} }
return new MatterTaskAllocation(task, get_pattern); return MatterTaskAllocation(task, getPattern)
} }
} }
} }
return null; return null
} }
@Override override fun notifyTaskCompletion(task: MatterTask): Boolean {
public boolean notifyTaskCompletion(MatterTask task) { var localTask = tasks[task.id] ?: return false
var get_task = tasks.get(task.id()); val oldTask = localTask
if (get_task == null) { localTask = localTask.shrinkInProgress(1)
return false; val graph = node.graph as MatterNetworkGraph?
}
var old_task = get_task; // Задача полностью выполнена
get_task = get_task.shrinkInProgress(1); if (localTask.required <= 0 && localTask.in_progress <= 0) {
tasks.remove(task.id)
if (get_task.required() <= 0 && get_task.in_progress() <= 0) { graph?.onMatterTaskCreated(task)
tasks.remove(task.id()); listeners.forEach { menu: MatterPanelMenu -> menu.taskRemoved(localTask) }
if (grid != null)
grid.onMatterTaskCreated(task);
MatterTask finalGet_task1 = get_task;
listeners.forEach(menu -> menu.taskRemoved(finalGet_task1));
} else { } else {
tasks.put(task.id(), get_task); // Задача обновлена
tasks[task.id()] = localTask
if (grid != null) { graph?.onMatterTaskUpdated(localTask, oldTask)
grid.onMatterTaskUpdated(get_task, old_task); listeners.forEach { menu: MatterPanelMenu -> menu.taskUpdated(localTask) }
}
MatterTask finalGet_task = get_task;
listeners.forEach(menu -> menu.taskUpdated(finalGet_task));
} }
setChanged(); setChanged()
return true
return true;
} }
@Override override fun saveAdditional(nbt: CompoundTag) {
public void saveAdditional(CompoundTag nbt) { super.saveAdditional(nbt)
super.saveAdditional(nbt);
ListTag list = new ListTag();
for (MatterTask task : tasks.values()) { val list = ListTag()
list.add(task.serializeNBT());
for (task in tasks.values) {
list.add(task!!.serializeNBT())
} }
nbt.put("tasks", list); nbt.put("tasks", list)
} }
@Override override fun load(nbt: CompoundTag) {
public void load(CompoundTag nbt) { super.load(nbt)
super.load(nbt); tasks.clear()
tasks.clear(); val list = nbt.getList("tasks", Tag.TAG_COMPOUND.toInt())
ListTag list = nbt.getList("tasks", Tag.TAG_COMPOUND); for (tag in list) {
val task = MatterTask.deserializeNBT(tag)
for (Tag tag : list) {
MatterTask task = MatterTask.deserializeNBT(tag);
if (task != null) { if (task != null) {
tasks.put(task.id(), task); tasks[task.id()] = task
} }
} }
} }
@Nullable override fun getTask(id: UUID): MatterTask? {
@Override return tasks[id]
public MatterTask getTask(UUID id) {
return tasks.get(id);
} }
public void removeTask(UUID id) { fun removeTask(id: UUID) {
var task = tasks.get(id); val task = tasks[id] ?: return
tasks.remove(id)
if (task == null) (node.graph as MatterNetworkGraph?)?.onMatterTaskRemoved(task)
return;
tasks.remove(id); listeners.forEach { menu: MatterPanelMenu -> menu.taskRemoved(task) }
setChanged()
if (grid != null)
grid.onMatterTaskRemoved(task);
listeners.forEach(menu -> menu.taskRemoved(task));
setChanged();
} }
public void removeTask(PatternState state) { fun removeTask(state: PatternState) = removeTask(state.id)
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) { override fun dropAllTasks() {
var task = new MatterTask(UUID.randomUUID(), state.id(), state.item(), 0, 0, how_much); val graph = node.graph as MatterNetworkGraph?
tasks.put(task.id(), task);
if (grid != null) for (task in tasks.values) {
grid.onMatterTaskCreated(task); graph?.onMatterTaskRemoved(task!!)
listeners.forEach { menu: MatterPanelMenu -> menu.taskUpdated(task!!) }
}
listeners.forEach(menu -> menu.taskUpdated(task)); tasks.clear()
setChanged();
return task;
} }
@Override companion object {
public void dropAllTasks() { private val NAME = TranslatableComponent("block.overdrive_that_matters.matter_panel")
tasks.clear();
} }
} }

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

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.BlockPos; import net.minecraft.core.Direction
import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TranslatableComponent
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.Inventory
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.items.CapabilityItemHandler
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.BlockEntityMatteryWorker
import ru.dbotthepony.mc.otm.block.entity.worker.MachineJob; 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.MachineJobStatus
import ru.dbotthepony.mc.otm.capability.*; import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.matter.*; import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage
import ru.dbotthepony.mc.otm.container.MatteryContainerHandler; import ru.dbotthepony.mc.otm.capability.matter.*
import ru.dbotthepony.mc.otm.core.Fraction; import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.matter.MatterGrid; import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.matter.MatterRegistry; import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.Registry; import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.container.MatteryContainer; import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.menu.MatterScannerMenu; import ru.dbotthepony.mc.otm.matter.MatterRegistry
import ru.dbotthepony.mc.otm.menu.MatterScannerMenu
import java.util.*
import javax.annotation.Nonnull; class BlockEntityMatterScanner(p_155229_: BlockPos, p_155230_: BlockState) :
import javax.annotation.Nullable; BlockEntityMatteryWorker(Registry.BlockEntities.MATTER_SCANNER, p_155229_, p_155230_), IMatterGraphNode {
import javax.annotation.ParametersAreNonnullByDefault;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.UUID;
@MethodsReturnNonnullByDefault val input_slot = MatteryContainer(this::setChanged, 1)
@ParametersAreNonnullByDefault
public class BlockEntityMatterScanner extends BlockEntityMatteryWorker implements IMatterGridCell {
private static final TranslatableComponent NAME = new TranslatableComponent("block.overdrive_that_matters.matter_scanner");
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( // IMatterGraphNode
(slot, stack) -> MatterRegistry.canDecompose(stack), override fun getAsMatterNode(): Graph6Node<IMatterGraphNode> {
(slot, amount, stack) -> is_idling return matterNode
);
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));
} }
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 fun onPatternUpdated(new_state: PatternState, old_state: PatternState) {
@Override is_idling = false
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) { }
// /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 (valid) {
if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) if (cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return inputHandler.get().cast()
return input_handler.get().cast(); //if (cap === MatteryCapability.MATTER_CELL) return resolver_grid.cast()
if (cap == MatteryCapability.MATTER_CELL) return resolverNode.cast()
if (cap == MatteryCapability.MATTER_CELL)
return resolver_grid.cast();
} }
return super.getCapability(cap, side); return super.getCapability(cap, side)
} }
@Override override fun invalidateCaps() {
public void invalidateCaps() { super.invalidateCaps()
super.invalidateCaps(); valid = false
valid = false; inputHandler.invalidate()
input_handler.invalidate(); resolverNode.invalidate()
resolver_grid.invalidate(); matterNode.destroy(::MatterNetworkGraph)
} }
@Override override fun reviveCaps() {
public void reviveCaps() { super.reviveCaps()
super.reviveCaps(); valid = true
valid = true; inputHandler.revive()
input_handler.revive(); resolverNode = LazyOptional.of { this }
resolver_grid = LazyOptional.of(() -> this);
} }
@Override override fun setRemoved() {
public void onPatternAdded(PatternState state) { super.setRemoved()
is_idling = false; matterNode.destroy(::MatterNetworkGraph)
} }
@Override override fun getDefaultDisplayName(): Component {
public void onPatternRemoved(PatternState state) { return NAME
is_idling = false;
} }
@Override override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu? {
public void onPatternUpdated(PatternState new_state, PatternState old_state) { return MatterScannerMenu(containerID, inventory, this)
is_idling = false;
} }
@Override override fun saveAdditional(nbt: CompoundTag) {
public void setRemoved() { super.saveAdditional(nbt)
super.setRemoved(); nbt.put("work_slots", input_slot.serializeNBT())
if (level != null && !level.isClientSide && grid != null)
grid.remove(this);
} }
@Override override fun load(nbt: CompoundTag) {
public void onNeighbourMatterCell(Level level, BlockPos pos, Direction direction, IMatterGridCell cell, BlockEntity entity) { input_slot.deserializeNBT(nbt["work_slots"])
is_idling = false; super.load(nbt)
} }
@Override override fun getBaseConsumption(): Fraction {
protected Component getDefaultDisplayName() { return BASE_CONSUMPTION
return NAME;
} }
@Nullable override fun onJobFinish(job: MachineJob): MachineJobStatus {
@Override val grid = matterNode.graph as MatterNetworkGraph? ?: return MachineJobStatus(false, 100)
public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply) {
return new MatterScannerMenu(containerID, inventory, this);
}
@Override val stack = job.stack()
public void saveAdditional(CompoundTag nbt) { if (stack.isEmpty || !MatterRegistry.hasMatterValue(stack)) return MachineJobStatus()
super.saveAdditional(nbt);
nbt.put("work_slots", input_slot.serializeNBT());
}
@Override val get_state = grid.findPatterns(stack.item)
public void load(CompoundTag nbt) { var find_state: PatternState? = null
input_slot.deserializeNBT(nbt.get("work_slots"));
super.load(nbt);
}
private static final Fraction BASE_CONSUMPTION = new Fraction("40"); for (state in get_state) {
if (state.item() === stack.item) {
@Override if (find_state == null && state.research_percent() < 1.0) {
@Nonnull find_state = state
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;
} else if (find_state != null && find_state.research_percent() < state.research_percent()) { } 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) { if (grid.insertPattern(new_state, false, false).status != PatternInsertStatus.Status.FAIL) {
new_state = new PatternState(find_state.id(), stack.getItem(), find_state.research_percent() + 0.2d); return MachineJobStatus()
} else { } 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 fun getNextJob(): MachineJob? {
@Override val grid = matterNode.graph as MatterNetworkGraph? ?: return null
protected MachineJob getNextJob() {
if (grid == null)
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)) val getState = grid.findPatterns(stack.item)
return null; var findState: PatternState? = null
Collection<PatternState> get_state = grid.findPatterns(stack.getItem()); for (state in getState) {
PatternState find_state = null; if (state.item() === stack.item && state.research_percent() < 1.0) {
findState = state
for (PatternState state : get_state) { } else if (state.item() === stack.item && state.research_percent() >= 1.0) {
if (state.item() == stack.getItem() && state.research_percent() < 1d) { return null
find_state = state;
} else if (state.item() == stack.getItem() && state.research_percent() >= 1d) {
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) { if (grid.insertPattern(new_state, false, true).status != PatternInsertStatus.Status.FAIL) {
new_state = new PatternState(find_state.id(), stack.getItem(), find_state.research_percent() + 0.2d); val copy = stack.copy()
} else { copy.count = 1
new_state = new PatternState(UUID.randomUUID(), stack.getItem(), 0.2d); 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) { return null
ItemStack copy = stack.copy(); }
copy.setCount(1);
stack.shrink(1); init {
input_slot.setChanged(); energy = MatteryMachineEnergyStorage(
return new MachineJob(copy, MatterRegistry.getMatterValue(copy).toDouble() * 35_000d); 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 companion object {
@Override private val NAME = TranslatableComponent("block.overdrive_that_matters.matter_scanner")
public IPatternStorage getPatternStorage() { private val BASE_CONSUMPTION = Fraction("40")
return null;
}
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 javax.annotation.ParametersAreNonnullByDefault
import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.BlockPos
import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.state.BlockState
import net.minecraft.core.Direction; import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage
import net.minecraft.nbt.CompoundTag; import ru.dbotthepony.mc.otm.container.MatteryContainer
import net.minecraft.network.chat.Component; import java.lang.Runnable
import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.world.item.ItemStack
import net.minecraft.world.entity.player.Inventory; import ru.dbotthepony.mc.otm.capability.MatteryCapability
import net.minecraft.world.entity.player.Player; import ru.dbotthepony.mc.otm.capability.matter.PatternState
import net.minecraft.world.inventory.AbstractContainerMenu; import ru.dbotthepony.mc.otm.block.BlockPatternStorage
import net.minecraft.world.item.ItemStack; import net.minecraft.nbt.CompoundTag
import net.minecraft.world.level.Level; import net.minecraftforge.common.util.LazyOptional
import net.minecraft.world.level.block.Block; import net.minecraftforge.items.CapabilityItemHandler
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.entity.player.Inventory
import net.minecraftforge.common.capabilities.Capability; import net.minecraft.world.entity.player.Player
import net.minecraftforge.common.util.LazyOptional; import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraftforge.items.CapabilityItemHandler; import ru.dbotthepony.mc.otm.menu.PatternStorageMenu
import net.minecraftforge.items.IItemHandler; import net.minecraft.MethodsReturnNonnullByDefault
import ru.dbotthepony.mc.otm.block.BlockPatternStorage; import net.minecraft.core.Direction
import ru.dbotthepony.mc.otm.capability.*; import net.minecraft.network.chat.Component
import ru.dbotthepony.mc.otm.capability.matter.*; import ru.dbotthepony.mc.otm.capability.matter.PatternInsertStatus
import ru.dbotthepony.mc.otm.container.MatteryContainerHandler; import net.minecraft.network.chat.TranslatableComponent
import ru.dbotthepony.mc.otm.matter.MatterGrid; import net.minecraft.server.level.ServerLevel
import ru.dbotthepony.mc.otm.Registry; import net.minecraft.world.level.Level
import ru.dbotthepony.mc.otm.container.MatteryContainer; import net.minecraft.world.level.block.Block
import ru.dbotthepony.mc.otm.menu.PatternStorageMenu; import net.minecraftforge.common.capabilities.Capability
import ru.dbotthepony.mc.otm.Registry
import javax.annotation.Nonnull; import ru.dbotthepony.mc.otm.graph.Graph6Node
import javax.annotation.Nullable; import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import javax.annotation.ParametersAreNonnullByDefault; import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import java.util.ArrayList; import ru.dbotthepony.mc.otm.ifHas
import java.util.Collection; import ru.dbotthepony.mc.otm.set
import java.util.ArrayList
@MethodsReturnNonnullByDefault @MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
public class BlockEntityPatternStorage extends BlockEntityMattery implements IMatterGridCell, IPatternStorage { class BlockEntityPatternStorage(p_155229_: BlockPos, p_155230_: BlockState) :
public BlockEntityPatternStorage(BlockPos p_155229_, BlockState p_155230_) { BlockEntityMattery(Registry.BlockEntities.PATTERN_STORAGE, p_155229_, p_155230_), IMatterGraphNode, IPatternStorage {
super(Registry.BlockEntities.PATTERN_STORAGE, p_155229_, p_155230_);
} 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 (grid != null && !ItemStack.isSameItemSameTags(new_state, old_state)) {
if (!old_state.isEmpty()) { if (!old_state.isEmpty) {
old_state.getCapability(MatteryCapability.PATTERN).ifPresent(cap -> cap.getStoredPatterns().forEach(grid::onPatternRemoved)); old_state.getCapability(MatteryCapability.PATTERN).ifPresent { cap: IPatternStorage ->
cap.storedPatterns.forEach { state: PatternState? -> grid.onPatternRemoved(state!!) }
}
} }
if (!new_state.isEmpty()) { if (!new_state.isEmpty) {
new_state.getCapability(MatteryCapability.PATTERN).ifPresent(cap -> cap.getStoredPatterns().forEach(grid::onPatternAdded)); 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 override fun getMaxStackSize(): Int {
public int getMaxStackSize() { return 1
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);
} }
} }
private final MatteryContainerHandler resolver_item = patterns.handler( private fun updateBlockstate() {
((slot, stack) -> stack.getCapability(MatteryCapability.PATTERN).isPresent()) val level = level ?: return
);
private MatterGrid grid; var state = blockState
@Override for (i in 0..7) {
public void saveAdditional(CompoundTag nbt) { state = state.setValue(
super.saveAdditional(nbt); BlockPatternStorage.PATTERN_STORAGE_DISKS_PROPS[i],
nbt.put("patterns", patterns.serializeNBT()); patterns.getItem(i).getCapability(MatteryCapability.PATTERN).isPresent
)
}
if (state !== blockState) {
level.setBlock(blockPos, state, Block.UPDATE_CLIENTS)
}
} }
@Override private val resolverItem =
public void load(CompoundTag nbt) { patterns.handler { slot: Int, stack: ItemStack -> stack.getCapability(MatteryCapability.PATTERN).isPresent }
super.load(nbt);
patterns.deserializeNBT(nbt.get("patterns")); override fun saveAdditional(nbt: CompoundTag) {
super.saveAdditional(nbt)
nbt["patterns"] = patterns.serializeNBT()
} }
@Override override fun load(nbt: CompoundTag) {
public void setLevel(Level p_155231_) { super.load(nbt)
super.setLevel(p_155231_);
if (grid == null) nbt.ifHas("patterns") {
MatterGrid.scheduleDiscoverNeighbours(this, getBlockPos(), p_155231_); patterns.deserializeNBT(it)
}
} }
@Nullable override fun setLevel(p_155231_: Level) {
@Override super.setLevel(p_155231_)
public MatterGrid getMatterGrid() {
return grid; if (p_155231_ is ServerLevel)
MatterNetworkGraph.discoverFull(this, node)
} }
@Nullable override fun getAsMatterNode(): Graph6Node<IMatterGraphNode> {
@Override return node
public IMatterHandler getMatterHandler() {
return null;
} }
@Nullable override fun getPatternHandler(): IPatternStorage {
@Override return this
public IPatternStorage getPatternStorage() {
return valid ? this : null;
} }
private boolean valid = true; private var valid = true
@Override override fun invalidateCaps() {
public boolean isValidMatterCell() { super.invalidateCaps()
return valid; valid = false
resolverItem.invalidate()
node.destroy(::MatterNetworkGraph)
} }
@Override override fun reviveCaps() {
public void setMatterGrid(MatterGrid grid) { super.reviveCaps()
this.grid = grid; valid = true
resolverItem.revive()
} }
@Override override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
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) {
if (valid) { if (valid) {
if (cap == MatteryCapability.PATTERN || cap == MatteryCapability.MATTER_CELL) if (cap === MatteryCapability.PATTERN) return resolverPatterns.cast()
return resolver.cast(); if (cap === MatteryCapability.MATTER_CELL) return resolverNode.cast()
if (cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return resolverItem.get().cast()
if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
return resolver_item.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 fun getDefaultDisplayName(): Component {
return NAME
@Override
protected Component getDefaultDisplayName() {
return NAME;
} }
@Nullable override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
@Override return PatternStorageMenu(containerID, inventory, this)
public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply) {
return new PatternStorageMenu(containerID, inventory, this);
} }
@Nonnull override fun getStoredPatterns(): Collection<PatternState> {
@Override val list = ArrayList<PatternState>()
public Collection<PatternState> getStoredPatterns() { patterns.consumeCapability(MatteryCapability.PATTERN) { capability: IPatternStorage -> list.addAll(capability.storedPatterns) }
ArrayList<PatternState> list = new ArrayList<>(); return list
patterns.consumeCapability(MatteryCapability.PATTERN, capability -> list.addAll(capability.getStoredPatterns()));
return ImmutableList.copyOf(list);
} }
@Override override fun getCapacity(): Int {
public int getCapacity() { var stored = 0L
long stored = 0;
for (var pattern : patterns.capabilityIterator(MatteryCapability.PATTERN)) { for (pattern in patterns.capabilityIterator(MatteryCapability.PATTERN))
stored += pattern.getCapacity(); 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 override fun getStored(): Int {
public int getStored() { var stored = 0L
long stored = 0;
for (var pattern : patterns.capabilityIterator(MatteryCapability.PATTERN)) { for (pattern in patterns.capabilityIterator(MatteryCapability.PATTERN))
stored += pattern.getStored(); 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 override fun setRemoved() {
public void setRemoved() { super.setRemoved()
super.setRemoved(); node.destroy(::MatterNetworkGraph)
if (level != null && !level.isClientSide && grid != null)
grid.remove(this);
} }
@Override override fun insertPattern(pattern: PatternState, only_update: Boolean, simulate: Boolean): PatternInsertStatus {
public PatternInsertStatus insertPattern(PatternState pattern, boolean only_update, boolean simulate) { for (storage in patterns.capabilityIterator(MatteryCapability.PATTERN)) {
for (IPatternStorage storage : patterns.capabilityIterator(MatteryCapability.PATTERN)) { val status = storage.insertPattern(pattern, only_update, simulate)
var status = storage.insertPattern(pattern, only_update, simulate);
if (status.status() != PatternInsertStatus.Status.FAIL) { if (status.status() != PatternInsertStatus.Status.FAIL) {
if (!simulate) { if (!simulate) {
setChanged(); setChanged()
if (grid != null) { val graph = node.graph as MatterNetworkGraph?
if (graph != null) {
if (status.status() == PatternInsertStatus.Status.INSERTED) { if (status.status() == PatternInsertStatus.Status.INSERTED) {
grid.onPatternAdded(status.new_state()); graph.onPatternAdded(status.new_state()!!)
} else { } 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

@ -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.Component
import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.client.screen.panels.*; import ru.dbotthepony.mc.otm.client.screen.panels.ButtonPanel
import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel; import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel; import ru.dbotthepony.mc.otm.client.screen.panels.SlotPanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel; import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel
import ru.dbotthepony.mc.otm.menu.MatterBottlerMenu; import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
import ru.dbotthepony.mc.otm.menu.slot.MatterySlot; import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
import ru.dbotthepony.mc.otm.menu.MatterBottlerMenu
import javax.annotation.Nullable; class MatterBottlerScreen(menu: MatterBottlerMenu, inventory: Inventory, title: Component) :
import java.util.List; MatteryScreen<MatterBottlerMenu>(menu, inventory, title) {
public class MatterBottlerScreen extends MatteryScreen<MatterBottlerMenu> { private var progress: ProgressGaugePanel? = null
public MatterBottlerScreen(MatterBottlerMenu menu, Inventory inventory, Component title) {
super(menu, inventory, title); 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 fun containerTick() {
@Override super.containerTick()
protected FramePanel makeMainFrame() {
var frame = super.makeMainFrame();
var mode = new ButtonPanel(this, frame, 0, 0, 100, 20, new TranslatableComponent("otm.matter_bottler.switch_mode")); progress?.flop = !menu.workFlow.value
mode.bindOnPress(menu::switchBottlerMode);
mode.setDock(Dock.TOP);
mode.asGrid(); // for auto alignment on center
return frame;
} }
} }

View File

@ -4,6 +4,7 @@ import net.minecraft.nbt.ByteArrayTag
import net.minecraft.nbt.StringTag import net.minecraft.nbt.StringTag
import net.minecraft.nbt.Tag import net.minecraft.nbt.Tag
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import org.apache.logging.log4j.LogManager
import java.math.BigDecimal import java.math.BigDecimal
import java.math.BigInteger import java.math.BigInteger
import java.math.MathContext 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_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 @JvmRecord
@Suppress("unused") @Suppress("unused")
@ -72,26 +263,21 @@ data class Fraction @JvmOverloads constructor(@JvmField val value: BigInteger, @
val c = divisor.signum() val c = divisor.signum()
if (a != b && a != c) { if (a != b && a != c) {
if (divisor == BigInteger.ZERO || divisor == BI_MINUS_ZERO) if (isZero(divisor))
return Fraction(-value, -divisor) return Fraction(-value, -divisor)
val mod = value % divisor val mod = value.divideAndRemainder(divisor)
if (mod == BigInteger.ZERO) if (isZero(mod[1]))
return Fraction(-value / -divisor, compact = compact) return Fraction(mod[0], compact = compact)
return Fraction(-value, -divisor) return Fraction(-value, -divisor)
} }
if (divisor == BigInteger.ZERO || divisor == BI_MINUS_ZERO) if (isZero(divisor))
return this return this
val mod = value % divisor return compactTwo(value, divisor, compact)
if (mod == BigInteger.ZERO)
return Fraction(value / divisor, compact = compact)
return this
} }
fun isZero(): Boolean { fun isZero(): Boolean {
@ -108,12 +294,7 @@ data class Fraction @JvmOverloads constructor(@JvmField val value: BigInteger, @
if (divisor == BigInteger.ZERO || divisor == BI_MINUS_ZERO) if (divisor == BigInteger.ZERO || divisor == BI_MINUS_ZERO)
return this return this
val mod = value % divisor return compactTwo(value, divisor, compact)
if (mod == BigInteger.ZERO)
return Fraction(value / divisor, compact = compact)
return this
} }
fun canonize(): Fraction { fun canonize(): Fraction {
@ -181,8 +362,8 @@ data class Fraction @JvmOverloads constructor(@JvmField val value: BigInteger, @
if (isNaN()) return this if (isNaN()) return this
if (divisor == other.divisor) { if (divisor == other.divisor) {
if (divisor == BigInteger.ONE) if (isOne(divisor))
return Fraction(value + other.value) return Fraction(value + other.value, divisor)
val new = value + other.value 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) if (divisor == BigInteger.ZERO || divisor == BI_MINUS_ZERO)
return Fraction(new, divisor) return Fraction(new, divisor)
val mod = new % divisor return compactTwo(new, divisor)
if (mod == BigInteger.ZERO)
return Fraction(new / divisor)
return Fraction(new, divisor)
} }
val new = value * other.divisor + other.value * 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) if (div == BigInteger.ZERO || div == BI_MINUS_ZERO)
return Fraction(new, div) return Fraction(new, div)
val mod = new % div return compactTwo(new, div)
if (mod == BigInteger.ZERO)
return Fraction(new / div)
return Fraction(new, div)
} }
operator fun plus(other: Fraction): Fraction { 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 { private fun minusCompact(other: Fraction): Fraction {
if (divisor == other.divisor) { if (divisor == other.divisor) {
if (divisor == BigInteger.ONE) if (isOne(divisor))
return Fraction(value - other.value) return Fraction(value - other.value, divisor)
val new = value - other.value 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) if (divisor == BigInteger.ZERO || divisor == BI_MINUS_ZERO)
return Fraction(new, divisor) return Fraction(new, divisor)
val mod = new % divisor return compactTwo(new, divisor)
if (mod == BigInteger.ZERO)
return Fraction(new / divisor)
return Fraction(new, divisor)
} }
val new = value * other.divisor - other.value * 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) if (div == BigInteger.ZERO || div == BI_MINUS_ZERO)
return Fraction(new, div) return Fraction(new, div)
val mod = new % div return compactTwo(new, div)
if (mod == BigInteger.ZERO)
return Fraction(new / div)
return Fraction(new, div)
} }
operator fun minus(other: Fraction): Fraction { 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) if (div == BigInteger.ZERO || div == BI_MINUS_ZERO)
return Fraction(new, div) return Fraction(new, div)
val mod = new % div return compactTwo(new, div)
if (mod == BigInteger.ZERO)
return Fraction(new / div)
return Fraction(new, div)
} }
operator fun times(other: Fraction): Fraction { 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) if (div == BigInteger.ZERO || div == BI_MINUS_ZERO)
return Fraction(new, div) return Fraction(new, div)
val mod = new % div return compactTwo(new, div)
if (mod == BigInteger.ZERO)
return Fraction(new / div)
return Fraction(new, div)
} }
operator fun div(other: Fraction): Fraction { operator fun div(other: Fraction): Fraction {
@ -423,13 +574,32 @@ data class Fraction @JvmOverloads constructor(@JvmField val value: BigInteger, @
fun toByteArray(): ByteArray { fun toByteArray(): ByteArray {
if (isNaN()) { 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 magValue = magnitude(value)
val bytesB = divisor.toByteArray() 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 { fun toInt(): Int {
@ -592,6 +762,8 @@ data class Fraction @JvmOverloads constructor(@JvmField val value: BigInteger, @
} }
companion object { companion object {
private val LOGGER = LogManager.getLogger()
@JvmField @JvmField
val ZERO = Fraction(BigInteger.ZERO) val ZERO = Fraction(BigInteger.ZERO)
@ -635,11 +807,27 @@ data class Fraction @JvmOverloads constructor(@JvmField val value: BigInteger, @
@JvmStatic @JvmStatic
fun fromByteArray(bytes: ByteArray): Fraction { fun fromByteArray(bytes: ByteArray): Fraction {
val bytesA = bytes.copyOfRange(1, 1 + bytes[0].toInt()) try {
val offsetB = 1 + bytes[0].toInt() val rangeA = unsignedInt(bytes[0]) or (unsignedInt(bytes[1]) shl 8)
val bytesB = bytes.copyOfRange(offsetB + 1, offsetB + 1 + bytes[offsetB].toInt()) 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 @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.SimpleContainer
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.inventory.ContainerData; import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.ItemStack; import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.Registry; import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterBottler
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.capability.matter.IMatterHandler
import ru.dbotthepony.mc.otm.capability.MatteryCapability; import ru.dbotthepony.mc.otm.menu.data.BooleanDataContainer
import ru.dbotthepony.mc.otm.menu.slot.MatterySlot; import ru.dbotthepony.mc.otm.menu.slot.MatterySlot
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget; import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget; import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget
import ru.dbotthepony.mc.otm.network.MatterBottlerSwitchPacket; import ru.dbotthepony.mc.otm.network.MatterBottlerSwitchPacket
import ru.dbotthepony.mc.otm.network.MatteryNetworking; import ru.dbotthepony.mc.otm.network.MatteryNetworking
import ru.dbotthepony.mc.otm.client.screen.UVWindingOrder;
public class MatterBottlerMenu extends PoweredMatteryMenu { class MatterBottlerMenu @JvmOverloads constructor(
public MatterBottlerMenu(int p_38852_, Inventory inventory) { p_38852_: Int,
this(p_38852_, inventory, null); inventory: Inventory,
} tile: BlockEntityMatterBottler? = null
) : PoweredMatteryMenu(
Registry.Menus.MATTER_BOTTLER, p_38852_, inventory, tile
) {
var workFlow = BooleanDataContainer()
public ContainerData work_flow = new ContainerData() { val progressWidget: ProgressGaugeWidget
private int value; val matterWidget: LevelGaugeWidget
val container = arrayOfNulls<MatterySlot>(6)
@Override init {
public int get(int i) { val container = tile?.container ?: SimpleContainer(6)
if (tile != null) {
return ((BlockEntityMatterBottler) tile).getWorkFlow() ? 1 : 0; 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 addDataSlots(workFlow)
public void set(int i, int i1) { addBatterySlot()
value = i1; addInventorySlots()
} }
@Override override fun broadcastChanges() {
public int getCount() { super.broadcastChanges()
return 1; workFlow.value = (tile as BlockEntityMatterBottler).workFlow
} }
};
public ProgressGaugeWidget progress; override fun getWorkingSlotStart(): Int {
public LevelGaugeWidget matter_widget; return 0
}
public MatterySlot[] work_slots = new MatterySlot[6]; override fun getWorkingSlotEnd(): Int {
return 7
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);
fun switchBottlerMode() {
if (tile == null) { if (tile == null) {
progress = new ProgressGaugeWidget(this); MatteryNetworking.CHANNEL.sendToServer(MatterBottlerSwitchPacket())
matter_widget = new LevelGaugeWidget(this);
} else { } else {
progress = new ProgressGaugeWidget(this, tile::getWorkProgress); (tile as BlockEntityMatterBottler).switchWorkFlow()
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();
} }
} }
} }

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

View File

@ -11,6 +11,7 @@ import net.minecraft.world.SimpleContainer
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.Registry import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.core.Fraction import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.matter.MatterRegistry import ru.dbotthepony.mc.otm.matter.MatterRegistry
import java.math.BigInteger import java.math.BigInteger
@ -38,8 +39,8 @@ class MatterScannerMenu @JvmOverloads constructor(
if (tile != null) { if (tile != null) {
progress = ProgressGaugeWidget(this, { tile.workProgress.toFloat() }) { tile.cantProcessJob() } progress = ProgressGaugeWidget(this, { tile.workProgress.toFloat() }) { tile.cantProcessJob() }
patterns = LevelGaugeWidget(this, patterns = LevelGaugeWidget(this,
{ Fraction(tile.matterGrid?.storedPatternCount?.toBigInteger() ?: BigInteger.ZERO) }, { Fraction(tile.getAsMatterGraph()?.getPatternCount()?.toBigInteger() ?: BigInteger.ZERO) },
{ Fraction(tile.matterGrid?.patternCapacity?.toBigInteger() ?: BigInteger.ZERO) }) { Fraction(tile.getAsMatterGraph()?.getPatternCapacity()?.toBigInteger() ?: BigInteger.ZERO) })
} else { } else {
progress = ProgressGaugeWidget(this) progress = ProgressGaugeWidget(this)
patterns = LevelGaugeWidget(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.SimpleContainer; import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Inventory; import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.Registry; import ru.dbotthepony.mc.otm.block.entity.BlockEntityPatternStorage
import ru.dbotthepony.mc.otm.block.entity.BlockEntityPatternStorage; import ru.dbotthepony.mc.otm.core.Fraction
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.slot.PatternSlot
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget; import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
public class PatternStorageMenu extends MatteryMenu { class PatternStorageMenu @JvmOverloads constructor(
public PatternStorageMenu(int p_38852_, Inventory inventory) { p_38852_: Int,
this(p_38852_, inventory, null); inventory: Inventory?,
} tile: BlockEntityPatternStorage? = null
) : MatteryMenu(
public PatternSlot[] pattern_slots = new PatternSlot[2 * 4]; Registry.Menus.PATTERN_STORAGE, p_38852_, inventory!!, tile
) {
public LevelGaugeWidget stored_this; val pattern_slots = arrayOfNulls<PatternSlot>(2 * 4)
public LevelGaugeWidget stored_grid; val stored_this: LevelGaugeWidget
val stored_grid: LevelGaugeWidget
public PatternStorageMenu(int p_38852_, Inventory inventory, BlockEntityPatternStorage tile) {
super(Registry.Menus.PATTERN_STORAGE, p_38852_, inventory, tile);
init {
if (tile == null) { if (tile == null) {
stored_this = new LevelGaugeWidget(this); stored_this = LevelGaugeWidget(this)
stored_grid = new LevelGaugeWidget(this); stored_grid = LevelGaugeWidget(this)
} else { } else {
stored_this = new LevelGaugeWidget(this, tile.getPatternStorage()); stored_this = LevelGaugeWidget(this, tile)
stored_grid = new LevelGaugeWidget(this, () -> { stored_grid = LevelGaugeWidget(this, {
if (tile.getMatterGrid() != null) { Fraction((tile.getAsMatterNode().graph as MatterNetworkGraph?)?.getPatternCount() ?: 0)
return new Fraction(tile.getMatterGrid().getStoredPatternCount()); }, {
} Fraction((tile.getAsMatterNode().graph as MatterNetworkGraph?)?.getPatternCapacity() ?: 0)
})
return Fraction.ZERO;
}, () -> {
if (tile.getMatterGrid() != null) {
return new Fraction(tile.getMatterGrid().getPatternCapacity());
}
return Fraction.ZERO;
});
} }
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 (row in 0..1) {
for (int column = 0; column < 4; column++) { for (column in 0..3) {
pattern_slots[row * 4 + column] = new PatternSlot(patterns, row * 4 + column, 48 + column * 20, 27 + row * 24); pattern_slots[row * 4 + column] = PatternSlot(patterns, row * 4 + column, 48 + column * 20, 27 + row * 24)
addSlot(pattern_slots[row * 4 + column]); addSlot(pattern_slots[row * 4 + column]!!)
} }
} }
addInventorySlots(); addInventorySlots()
} }
@Override override fun getWorkingSlotStart(): Int {
protected int getWorkingSlotStart() { return 0
return 0;
} }
@Override override fun getWorkingSlotEnd(): Int {
protected int getWorkingSlotEnd() { return 2 * 4
return 2 * 4;
} }
} }

View File

@ -1,26 +1,47 @@
package ru.dbotthepony.mc.otm.menu.data package ru.dbotthepony.mc.otm.menu.data
import net.minecraft.world.inventory.ContainerData import net.minecraft.world.inventory.ContainerData
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.core.Fraction import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.network.NetworkHelper import ru.dbotthepony.mc.otm.network.NetworkHelper
import java.util.zip.CRC32
class FractionDataContainer : ContainerData { class FractionDataContainer : ContainerData {
companion object { 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 _value: Fraction? = Fraction.ZERO
private var _value2: Fraction? = Fraction.ZERO
fun hasComputedValue(): Boolean { fun hasComputedValue(): Boolean {
return _value != null return _value != null
} }
private var mute = false
var value: Fraction var value: Fraction
get() { get() {
if (_value != null) if (_value != null)
return _value!! 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!! return _value!!
} }
set(value) { set(value) {
@ -31,7 +52,28 @@ class FractionDataContainer : ContainerData {
return 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) val buffer = ShortArray(NETWORK_PAYLOAD_SIZE)
@ -42,6 +84,7 @@ class FractionDataContainer : ContainerData {
override operator fun set(p_39285_: Int, p_39286_: Int) { override operator fun set(p_39285_: Int, p_39286_: Int) {
buffer[p_39285_] = p_39286_.toShort() buffer[p_39285_] = p_39286_.toShort()
if (_value != null) _value2 = _value
_value = null _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.Test
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import ru.dbotthepony.mc.otm.core.Fraction import ru.dbotthepony.mc.otm.core.Fraction
import java.lang.Math.floor
import java.math.BigDecimal import java.math.BigDecimal
import java.math.BigInteger import java.math.BigInteger
import kotlin.random.Random
object FractionTests { object FractionTests {
@Test @Test
@ -113,12 +115,121 @@ object FractionTests {
fun math() { fun math() {
assert((Fraction(1) / Fraction(1)) == Fraction(1)) assert((Fraction(1) / Fraction(1)) == Fraction(1))
assert((Fraction(2) / Fraction(1)) == Fraction(2, 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(4, 3) * Fraction(4, 5)))
assert((Fraction(4, 3) + Fraction(5, 4)) == Fraction(31, 12)) 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 @Test
@DisplayName("Fraction serialization test") @DisplayName("Fraction serialization test")
fun serialization() { fun serialization() {
@ -146,6 +257,26 @@ object FractionTests {
serialized = value.serializeNBT() serialized = value.serializeNBT()
assert(value.compareTo(Fraction.deserializeNBT(serialized)) == 0) 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 @Test