Pattern monitor and Matter replicator!

This commit is contained in:
DBotThePony 2021-08-17 13:35:11 +07:00
parent 25bc104421
commit 3b313ec162
Signed by: DBot
GPG Key ID: DCC23B5715498507
36 changed files with 1697 additions and 59 deletions

View File

@ -39,6 +39,8 @@ public class Registry {
public static final ResourceLocation MATTER_CABLE = new ResourceLocation(OverdriveThatMatters.MOD_ID, "matter_cable");
public static final ResourceLocation PATTERN_STORAGE = new ResourceLocation(OverdriveThatMatters.MOD_ID, "pattern_storage");
public static final ResourceLocation MATTER_SCANNER = new ResourceLocation(OverdriveThatMatters.MOD_ID, "matter_scanner");
public static final ResourceLocation MATTER_PANEL = new ResourceLocation(OverdriveThatMatters.MOD_ID, "matter_panel");
public static final ResourceLocation MATTER_REPLICATOR = new ResourceLocation(OverdriveThatMatters.MOD_ID, "matter_replicator");
public static final ResourceLocation ANDROID_CAPABILITY = new ResourceLocation(OverdriveThatMatters.MOD_ID, "android_capability");
@ -66,6 +68,8 @@ public class Registry {
public static final Block MATTER_CABLE = new BlockMatterCable();
public static final Block PATTERN_STORAGE = new BlockPatternStorage();
public static final Block MATTER_SCANNER = new BlockMatterScanner();
public static final Block MATTER_PANEL = new BlockMatterPanel();
public static final Block MATTER_REPLICATOR = new BlockMatterReplicator();
static {
ANDROID_STATION.setRegistryName(Names.ANDROID_STATION);
@ -75,6 +79,8 @@ public class Registry {
MATTER_CABLE.setRegistryName(Names.MATTER_CABLE);
PATTERN_STORAGE.setRegistryName(Names.PATTERN_STORAGE);
MATTER_SCANNER.setRegistryName(Names.MATTER_SCANNER);
MATTER_PANEL.setRegistryName(Names.MATTER_PANEL);
MATTER_REPLICATOR.setRegistryName(Names.MATTER_REPLICATOR);
}
public static void register(final RegistryEvent.Register<Block> event) {
@ -85,6 +91,8 @@ public class Registry {
event.getRegistry().register(MATTER_CABLE);
event.getRegistry().register(PATTERN_STORAGE);
event.getRegistry().register(MATTER_SCANNER);
event.getRegistry().register(MATTER_PANEL);
event.getRegistry().register(MATTER_REPLICATOR);
// OverdriveThatMatters.LOGGER.info("Registered blocks");
}
@ -98,6 +106,8 @@ public class Registry {
public static final Item MATTER_CABLE = new BlockItem(Blocks.MATTER_CABLE, new Item.Properties().stacksTo(64).tab(CreativeModeTab.TAB_MISC));
public static final Item PATTERN_STORAGE = new BlockItem(Blocks.PATTERN_STORAGE, new Item.Properties().stacksTo(64).tab(CreativeModeTab.TAB_MISC));
public static final Item MATTER_SCANNER = new BlockItem(Blocks.MATTER_SCANNER, new Item.Properties().stacksTo(64).tab(CreativeModeTab.TAB_MISC));
public static final Item MATTER_PANEL = new BlockItem(Blocks.MATTER_PANEL, new Item.Properties().stacksTo(64).tab(CreativeModeTab.TAB_MISC));
public static final Item MATTER_REPLICATOR = new BlockItem(Blocks.MATTER_REPLICATOR, new Item.Properties().stacksTo(64).tab(CreativeModeTab.TAB_MISC));
public static final ItemPill PILL_ANDROID = new ItemPill(ItemPill.PillType.BECOME_ANDROID);
public static final ItemPill PILL_HUMANE = new ItemPill(ItemPill.PillType.BECOME_HUMANE);
@ -122,6 +132,8 @@ public class Registry {
MATTER_CABLE.setRegistryName(Names.MATTER_CABLE);
PATTERN_STORAGE.setRegistryName(Names.PATTERN_STORAGE);
MATTER_SCANNER.setRegistryName(Names.MATTER_SCANNER);
MATTER_PANEL.setRegistryName(Names.MATTER_PANEL);
MATTER_REPLICATOR.setRegistryName(Names.MATTER_REPLICATOR);
PILL_ANDROID.setRegistryName(Names.PILL_ANDROID);
PILL_HUMANE.setRegistryName(Names.PILL_HUMANE);
@ -146,6 +158,8 @@ public class Registry {
event.getRegistry().register(MATTER_CABLE);
event.getRegistry().register(PATTERN_STORAGE);
event.getRegistry().register(MATTER_SCANNER);
event.getRegistry().register(MATTER_PANEL);
event.getRegistry().register(MATTER_REPLICATOR);
event.getRegistry().register(PILL_ANDROID);
event.getRegistry().register(PILL_HUMANE);
@ -173,6 +187,8 @@ public class Registry {
public static final BlockEntityType<BlockEntityMatterCable> MATTER_CABLE = BlockEntityType.Builder.of(BlockEntityMatterCable::new, Blocks.MATTER_CABLE).build(null);
public static final BlockEntityType<BlockEntityPatternStorage> PATTERN_STORAGE = BlockEntityType.Builder.of(BlockEntityPatternStorage::new, Blocks.PATTERN_STORAGE).build(null);
public static final BlockEntityType<BlockEntityMatterScanner> MATTER_SCANNER = BlockEntityType.Builder.of(BlockEntityMatterScanner::new, Blocks.MATTER_SCANNER).build(null);
public static final BlockEntityType<BlockEntityMatterPanel> MATTER_PANEL = BlockEntityType.Builder.of(BlockEntityMatterPanel::new, Blocks.MATTER_PANEL).build(null);
public static final BlockEntityType<BlockEntityMatterReplicator> MATTER_REPLICATOR = BlockEntityType.Builder.of(BlockEntityMatterReplicator::new, Blocks.MATTER_REPLICATOR).build(null);
static {
ANDROID_STATION.setRegistryName(Names.ANDROID_STATION);
@ -182,6 +198,8 @@ public class Registry {
MATTER_CABLE.setRegistryName(Names.MATTER_CABLE);
PATTERN_STORAGE.setRegistryName(Names.PATTERN_STORAGE);
MATTER_SCANNER.setRegistryName(Names.MATTER_SCANNER);
MATTER_PANEL.setRegistryName(Names.MATTER_PANEL);
MATTER_REPLICATOR.setRegistryName(Names.MATTER_REPLICATOR);
}
public static void register(final RegistryEvent.Register<BlockEntityType<?>> event) {
@ -192,6 +210,8 @@ public class Registry {
event.getRegistry().register(MATTER_CABLE);
event.getRegistry().register(PATTERN_STORAGE);
event.getRegistry().register(MATTER_SCANNER);
event.getRegistry().register(MATTER_PANEL);
event.getRegistry().register(MATTER_REPLICATOR);
// OverdriveThatMatters.LOGGER.info("Registered block entities");
}
@ -204,6 +224,8 @@ public class Registry {
public static final MenuType<MatterCapacitorBankMenu> MATTER_CAPACITOR_BANK = new MenuType<>(MatterCapacitorBankMenu::new);
public static final MenuType<PatternStorageMenu> PATTERN_STORAGE = new MenuType<>(PatternStorageMenu::new);
public static final MenuType<MatterScannerMenu> MATTER_SCANNER = new MenuType<>(MatterScannerMenu::new);
public static final MenuType<MatterPanelMenu> MATTER_PANEL = new MenuType<>(MatterPanelMenu::new);
public static final MenuType<MatterReplicatorMenu> MATTER_REPLICATOR = new MenuType<>(MatterReplicatorMenu::new);
static {
ANDROID_STATION.setRegistryName(Names.ANDROID_STATION);
@ -212,6 +234,8 @@ public class Registry {
MATTER_CAPACITOR_BANK.setRegistryName(Names.MATTER_CAPACITOR_BANK);
PATTERN_STORAGE.setRegistryName(Names.PATTERN_STORAGE);
MATTER_SCANNER.setRegistryName(Names.MATTER_SCANNER);
MATTER_PANEL.setRegistryName(Names.MATTER_PANEL);
MATTER_REPLICATOR.setRegistryName(Names.MATTER_REPLICATOR);
}
public static void register(final RegistryEvent.Register<MenuType<?>> event) {
@ -221,6 +245,8 @@ public class Registry {
event.getRegistry().register(MATTER_CAPACITOR_BANK);
event.getRegistry().register(PATTERN_STORAGE);
event.getRegistry().register(MATTER_SCANNER);
event.getRegistry().register(MATTER_PANEL);
event.getRegistry().register(MATTER_REPLICATOR);
// OverdriveThatMatters.LOGGER.info("Registered menus");
}
@ -232,6 +258,8 @@ public class Registry {
MenuScreens.register(MATTER_CAPACITOR_BANK, MatterCapacitorBankScreen::new);
MenuScreens.register(PATTERN_STORAGE, PatternStorageScreen::new);
MenuScreens.register(MATTER_SCANNER, MatterScannerScreen::new);
MenuScreens.register(MATTER_PANEL, MatterPanelScreen::new);
MenuScreens.register(MATTER_REPLICATOR, MatterReplicatorScreen::new);
// OverdriveThatMatters.LOGGER.info("Registered screens");
}

View File

@ -0,0 +1,115 @@
package ru.dbotthepony.mc.otm.block;
import com.google.common.collect.ImmutableMap;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterPanel;
import javax.annotation.Nullable;
public class BlockMatterPanel extends BlockMattery implements EntityBlock {
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
return new BlockEntityMatterPanel(blockPos, blockState);
}
public static final EnumProperty<Direction> FACING = EnumProperty.create(
"facing",
Direction.class);
private ImmutableMap<BlockState, VoxelShape> SHAPES;
public BlockMatterPanel() {
super();
registerDefaultState(this.getStateDefinition().any().setValue(FACING, Direction.SOUTH));
SHAPES = getShapeForEachState(blockstate -> {
return switch (blockstate.getValue(FACING)) {
case NORTH -> Shapes.box(
0.0d,
0.0d,
0.625d,
1.0d,
1.0d,
1.0d
);
case EAST -> Shapes.box(
0.0d,
0.0d,
0.0d,
0.375d,
1.0d,
1.0d
);
case WEST -> Shapes.box(
0.625d,
0.0d,
0.0d,
1.0d,
1.0d,
1.0d
);
case DOWN -> Shapes.box(
0.0d,
0.625d,
0.0d,
1.0d,
1.0d,
1.0d
);
case UP -> Shapes.box(
0.0d,
0.0d,
0.0d,
1.0d,
0.375d,
1.0d
);
default -> Shapes.box(
0.0d,
0.0d,
0.0d,
1.0d,
1.0d,
0.375d
);
};
});
}
@Override
public VoxelShape getShape(BlockState p_60555_, BlockGetter p_60556_, BlockPos p_60557_, CollisionContext p_60558_) {
return SHAPES.get(p_60555_);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(FACING);
}
@Nullable
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
return this.defaultBlockState().setValue(FACING, context.getClickedFace());
}
}

View File

@ -0,0 +1,28 @@
package ru.dbotthepony.mc.otm.block;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterReplicator;
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatteryPoweredWorker;
import javax.annotation.Nullable;
public class BlockMatterReplicator extends BlockMatteryRotatable implements EntityBlock {
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
return new BlockEntityMatterReplicator(blockPos, blockState);
}
@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level p_153212_, BlockState p_153213_, BlockEntityType<T> p_153214_) {
return p_153212_.isClientSide || p_153214_ != Registry.BlockEntities.MATTER_REPLICATOR ? null : BlockEntityMatteryPoweredWorker::basicTicker;
}
}

View File

@ -115,10 +115,10 @@ public class BlockEntityMatterDecomposer extends BlockEntityMatteryPoweredWorker
@Nonnull
@Override
protected MachineJobFinish onJobFinish(MachineJob job) {
protected MachineJobStatus onJobFinish(MachineJob job) {
BigDecimal matter_value = MatterRegistry.getMatterValue(job.stack());
matter.receiveMatterInner(matter_value, false);
return new MachineJobFinish();
return new MachineJobStatus();
}
@Nullable
@ -133,7 +133,7 @@ public class BlockEntityMatterDecomposer extends BlockEntityMatteryPoweredWorker
if (!matter_value.equals(BigDecimal.ZERO) && matter.canReceiveAll(matter_value)) {
stack.shrink(1);
return new MachineJob(copy, matter_value.doubleValue() * 35000d);
return new MachineJob(copy, matter_value.doubleValue() * 12_500d);
}
}

View File

@ -0,0 +1,199 @@
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.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.capability.IMatterGridCell;
import ru.dbotthepony.mc.otm.capability.IMatterTaskProvider;
import ru.dbotthepony.mc.otm.capability.MatterTask;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.matter.MatterGrid;
import ru.dbotthepony.mc.otm.menu.MatterPanelMenu;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import java.util.stream.Collectors;
public class BlockEntityMatterPanel extends BlockEntityMattery implements IMatterGridCell, IMatterTaskProvider {
public BlockEntityMatterPanel(BlockPos p_155229_, BlockState p_155230_) {
super(Registry.BlockEntities.MATTER_PANEL, p_155229_, p_155230_);
}
private static final TranslatableComponent NAME = new TranslatableComponent("block.overdrive_that_matters.matter_panel");
@Override
protected Component getDefaultDisplayName() {
return NAME;
}
@Nullable
@Override
public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply) {
return new MatterPanelMenu(containerID, inventory, this);
}
private boolean valid = true;
@Override
public void invalidateCaps() {
super.invalidateCaps();
valid = false;
}
@Override
public void reviveCaps() {
super.reviveCaps();
valid = true;
}
private final LazyOptional<BlockEntityMatterPanel> resolver = LazyOptional.of(() -> this);
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
if (valid && (cap == MatteryCapability.MATTER_CELL || cap == MatteryCapability.TASK))
return resolver.cast();
return super.getCapability(cap, side);
}
private MatterGrid grid;
@Override
public void setLevel(Level p_155231_) {
super.setLevel(p_155231_);
if (grid == null)
scheduleDiscoverNeighbours(getBlockPos(), p_155231_);
}
@Nullable
@Override
public MatterGrid getMatterGrid() {
return grid;
}
@Override
public boolean isValidMatterCell() {
return valid;
}
@Override
public void setMatterGrid(MatterGrid grid) {
this.grid = grid;
}
@Nullable
@Override
public IMatterTaskProvider getTaskProvider() {
return this;
}
private final HashMap<UUID, MatterTask> tasks = new HashMap<>();
@Nonnull
@Override
public Collection<MatterTask> getTasks() {
return tasks.values().stream().filter(task -> task.required() > 0).collect(Collectors.toList());
}
@Nonnull
@Override
public Collection<MatterTask> getAllTasks() {
return List.copyOf(tasks.values());
}
@Nullable
@Override
public MatterTask allocateTask(boolean simulate) {
for (var entry : tasks.entrySet()) {
if (entry.getValue().required() > 0) {
if (!simulate) {
tasks.put(entry.getKey(), entry.getValue().shrinkRequired(1));
}
return entry.getValue();
}
}
return null;
}
@Override
public void notifyTaskCompletion(MatterTask task) {
var get_task = tasks.get(task.id());
if (get_task == null) {
return;
}
get_task = get_task.shrinkInProgress(1);
if (get_task.required() == 0 && get_task.in_progress() == 0) {
tasks.remove(task.id());
} else {
tasks.put(task.id(), get_task);
}
}
@Override
public CompoundTag save(CompoundTag nbt) {
ListTag list = new ListTag();
for (MatterTask task : tasks.values()) {
list.add(task.serializeNBT());
}
nbt.put("tasks", list);
return super.save(nbt);
}
@Override
public void load(CompoundTag nbt) {
super.load(nbt);
tasks.clear();
ListTag list = nbt.getList("tasks", Tag.TAG_COMPOUND);
for (Tag tag : list) {
MatterTask task = MatterTask.deserializeNBT(tag);
if (task != null) {
tasks.put(task.id(), task);
}
}
}
@Nullable
@Override
public MatterTask getTask(UUID id) {
return tasks.get(id);
}
public MatterTask addTask(Item item, int how_much) {
var task = new MatterTask(UUID.randomUUID(), item, 0, 0, how_much);
tasks.put(task.id(), task);
return task;
}
@Override
public void dropAllTasks() {
tasks.clear();
}
}

View File

@ -0,0 +1,241 @@
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.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.capability.*;
import ru.dbotthepony.mc.otm.container.MatteryContainer;
import ru.dbotthepony.mc.otm.matter.MatterGrid;
import ru.dbotthepony.mc.otm.matter.MatterRegistry;
import ru.dbotthepony.mc.otm.menu.MatterReplicatorMenu;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.math.BigDecimal;
public class BlockEntityMatterReplicator extends BlockEntityMatteryPoweredWorker implements IMatterGridCell {
public BlockEntityMatterReplicator(BlockPos p_155229_, BlockState p_155230_) {
super(Registry.BlockEntities.MATTER_REPLICATOR, p_155229_, p_155230_);
energy = new MatteryMachineEnergyStorage(this, MatteryMachineEnergyStorage.MachineType.WORKER, new BigDecimal(200_000), new BigDecimal(4000), new BigDecimal(4000));
}
public final MatterHandlerCapability matter = new MatterHandlerCapability(this::setChanged, IMatterHandler.MatterDirection.RECEIVE, new BigDecimal(2));
// обычные запросы
public final MatteryContainer regular_slots = new MatteryContainer(this::setChanged, 3);
// запросы от matter replicator interface
public final MatteryContainer reserved_slots = new MatteryContainer(this::setChanged, 3);
private final LazyOptional<IItemHandler> resolve_handler = LazyOptional.of(() -> regular_slots.handler(
(slot, stack) -> false
));
private static final TranslatableComponent NAME = new TranslatableComponent("block.overdrive_that_matters.matter_replicator");
private static final BigDecimal BASE_CONSUMPTION = new BigDecimal(400);
@Override
protected Component getDefaultDisplayName() {
return NAME;
}
@Nullable
@Override
public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply) {
return new MatterReplicatorMenu(containerID, inventory, this);
}
@Nonnull
@Override
protected BigDecimal getBaseConsumption() {
return BASE_CONSUMPTION;
}
@Nonnull
@Override
protected MachineJobStatus onJobFinish(MachineJob job) {
if (!regular_slots.addItem(job.stack()).isEmpty()) {
if (grid != null) {
grid.notifyTaskCompletion(MatterTask.deserializeNBT(job.data().get("task")));
}
return new MachineJobStatus(false);
}
return new MachineJobStatus();
}
@Override
public void notifyTasksChanged() {
is_idling = false;
}
private static final double TICKS_PER_MTU = 20_000d;
private static final BigDecimal TICKS_PER_MTU_BD = new BigDecimal(20_000);
private static final double MTU_PER_TICK = 1d / 20_000d;
private static final BigDecimal MTU_PER_TICK_BD = BigDecimal.ONE.divide(TICKS_PER_MTU_BD, MatteryCapability.ROUND_RULES);
@Override
public void setLevel(Level p_155231_) {
super.setLevel(p_155231_);
if (grid == null)
scheduleDiscoverNeighbours(getBlockPos(), p_155231_);
}
@Nullable
@Override
protected MachineJob getNextJob() {
if (grid == null)
return null;
MatterTask task = grid.allocateTask(false);
if (task == null)
return null;
ItemStack stack = task.stack(1);
// ????????
if (!MatterRegistry.hasMatterValue(stack))
return null;
MachineJob job = new MachineJob(stack, MatterRegistry.getMatterValue(stack).doubleValue() * TICKS_PER_MTU);
job.data().put("task", task.serializeNBT());
return job;
}
private static final BigDecimal DRAIN_MULT = new BigDecimal(200);
@Override
protected MachineJobStatus onWorkTick(WorkTickContext context) {
BigDecimal drain_per_tick = MatterRegistry.getMatterValue(context.job().stack().getItem()).multiply(MTU_PER_TICK_BD, MatteryCapability.ROUND_RULES).multiply(context.work_speed(), MatteryCapability.ROUND_RULES);
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) {
// в тик требуется больше материи, чем её может хранить репликатор
BigDecimal to_extract = drain_per_tick.subtract(matter.extractMatterInner(drain_per_tick, true));
BigDecimal drain = grid.extractMatter(to_extract, true);
if (drain.compareTo(to_extract) < 0) {
// недостаточно материи в сети
return new MachineJobStatus(false, 200);
}
// достаточно материи в сети + внутри машины
matter.extractMatterInner(drain_per_tick, false);
grid.extractMatter(drain, false);
return new MachineJobStatus();
} else {
// в тик требуется меньше материи, чем её может хранить репликатор
// примем из сети недостающее количество бака материи, или 200 тиков репликации, что меньше
BigDecimal to_extract = matter.getMissingMatter().min(drain_per_tick.multiply(DRAIN_MULT));
BigDecimal drain = grid.extractMatter(to_extract, true);
if (drain.compareTo(BigDecimal.ZERO) == 0) {
// в сети нет материи
return new MachineJobStatus(false, 200);
}
BigDecimal received = matter.receiveMatterOuter(drain, false);
grid.extractMatter(received, false);
// получили материю, проверяем возможность работы
if (matter.extractMatterInner(drain_per_tick, false).compareTo(drain_per_tick) >= 0) {
return new MachineJobStatus();
} else {
// :(
return new MachineJobStatus(false, 200);
}
}
}
// в машине достаточно материи
matter.extractMatterInner(drain_per_tick, false);
return new MachineJobStatus();
}
@Override
public CompoundTag save(CompoundTag nbt) {
nbt.put("regular_slots", regular_slots.serializeNBT());
nbt.put("reserved_slots", reserved_slots.serializeNBT());
return super.save(nbt);
}
@Override
public void load(CompoundTag nbt) {
super.load(nbt);
regular_slots.deserializeNBT(nbt.get("regular_slots"));
reserved_slots.deserializeNBT(nbt.get("reserved_slots"));
}
private boolean valid = true;
@Override
public void invalidateCaps() {
super.invalidateCaps();
valid = false;
}
@Override
public void reviveCaps() {
super.reviveCaps();
valid = true;
}
private final LazyOptional<BlockEntityMatterReplicator> resolver_self = LazyOptional.of(() -> this);
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
if (valid) {
if (cap == MatteryCapability.MATTER_CELL)
return resolver_self.cast();
if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
return resolve_handler.cast();
}
return super.getCapability(cap, side);
}
private MatterGrid grid;
@Nullable
@Override
public MatterGrid getMatterGrid() {
return grid;
}
@Override
public boolean isValidMatterCell() {
return valid;
}
@Override
public void setMatterGrid(MatterGrid grid) {
this.grid = grid;
}
}

View File

@ -115,14 +115,14 @@ public class BlockEntityMatterScanner extends BlockEntityMatteryPoweredWorker im
@Nonnull
@Override
protected MachineJobFinish onJobFinish(MachineJob job) {
protected MachineJobStatus onJobFinish(MachineJob job) {
if (grid == null)
return new MachineJobFinish(false, 100);
return new MachineJobStatus(false, 100);
ItemStack stack = job.stack();
if (stack.isEmpty() || !MatterRegistry.hasMatterValue(stack))
return new MachineJobFinish();
return new MachineJobStatus();
Collection<IPatternStorage.PatternState> get_state = grid.findPattern(stack.getItem());
@ -148,10 +148,10 @@ public class BlockEntityMatterScanner extends BlockEntityMatteryPoweredWorker im
}
if (grid.insertPattern(new_state, false, false)) {
return new MachineJobFinish();
return new MachineJobStatus();
}
return new MachineJobFinish(false, 200);
return new MachineJobStatus(false, 200);
}
@Nullable
@ -189,7 +189,7 @@ public class BlockEntityMatterScanner extends BlockEntityMatteryPoweredWorker im
copy.setCount(1);
stack.shrink(1);
input_slot.setChanged();
return new MachineJob(copy, MatterRegistry.getMatterValue(copy).doubleValue() * 80000d);
return new MachineJob(copy, MatterRegistry.getMatterValue(copy).doubleValue() * 35_000d);
}
return null;

View File

@ -24,16 +24,16 @@ abstract public class BlockEntityMatteryPoweredWorker extends BlockEntityMattery
@Nonnull
protected abstract BigDecimal getBaseConsumption();
public record WorkTickContext(MachineJob job, BigDecimal required_power, BigDecimal extracted_power, double work_speed) {
public record WorkTickContext(MachineJob job, BigDecimal required_power, BigDecimal extracted_power, BigDecimal work_speed) {
}
public record MachineJobFinish(boolean finished, int throttle) {
public MachineJobFinish() {
public record MachineJobStatus(boolean valid, int throttle) {
public MachineJobStatus() {
this(true, 0);
}
public MachineJobFinish(boolean finished) {
public MachineJobStatus(boolean finished) {
this(finished, 0);
}
}
@ -90,7 +90,7 @@ abstract public class BlockEntityMatteryPoweredWorker extends BlockEntityMattery
}
protected double work_ticks = 0;
protected int throttle_job_finish = 0;
protected int throttle_ticks = 0;
protected MachineJob current_job;
// if is_idling is true, then workerLoop() does nothing
@ -101,8 +101,8 @@ abstract public class BlockEntityMatteryPoweredWorker extends BlockEntityMattery
return current_job;
}
public boolean cantFinishJob() {
return throttle_job_finish > 0;
public boolean cantProcessJob() {
return throttle_ticks > 0;
}
@Override
@ -141,23 +141,23 @@ abstract public class BlockEntityMatteryPoweredWorker extends BlockEntityMattery
* waiting on conditions to be met
*/
@Nonnull
abstract protected MachineJobFinish onJobFinish(MachineJob job);
abstract protected MachineJobStatus onJobFinish(MachineJob job);
/**
* @param context context for current job
* @return whenever machine can perform it
*/
protected boolean onWorkTick(WorkTickContext context) {
return true;
protected MachineJobStatus onWorkTick(WorkTickContext context) {
return new MachineJobStatus();
}
protected void workerLoop() {
if (is_idling) {
if (throttle_ticks > 0) {
throttle_ticks--;
return;
}
if (throttle_job_finish > 0) {
throttle_job_finish--;
if (is_idling) {
return;
}
@ -180,12 +180,16 @@ abstract public class BlockEntityMatteryPoweredWorker extends BlockEntityMattery
BigDecimal required_power = consumptionPerWork().multiply(current_job.power_consumption_multiplier);
BigDecimal extracted_power = energy.extractEnergyInner(required_power, true);
double work_speed = extracted_power.divide(required_power, MatteryCapability.ROUND_RULES).doubleValue();
BigDecimal work_speed = extracted_power.divide(required_power, MatteryCapability.ROUND_RULES);
if (!onWorkTick(new WorkTickContext(current_job, required_power, extracted_power, work_speed)))
MachineJobStatus status = onWorkTick(new WorkTickContext(current_job, required_power, extracted_power, work_speed));
if (!status.valid) {
throttle_ticks += status.throttle;
return;
}
double new_work_ticks = work_speed + work_ticks;
double new_work_ticks = work_speed.doubleValue() + work_ticks;
if (new_work_ticks > current_job.ticks_processing_time) {
work_ticks = current_job.ticks_processing_time;
@ -195,41 +199,46 @@ abstract public class BlockEntityMatteryPoweredWorker extends BlockEntityMattery
energy.extractEnergyInner(extracted_power, false);
if (work_ticks >= current_job.ticks_processing_time) {
MachineJobFinish status = onJobFinish(current_job);
MachineJobStatus finish = onJobFinish(current_job);
if (status.finished) {
if (finish.valid) {
current_job = null;
work_ticks = 0d;
} else {
throttle_job_finish += status.throttle;
throttle_ticks += finish.throttle;
}
}
}
} else {
if (!onWorkTick(new WorkTickContext(current_job, BigDecimal.ZERO, BigDecimal.ZERO, 1d)))
MachineJobStatus status = onWorkTick(new WorkTickContext(current_job, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ONE));
if (!status.valid) {
throttle_ticks += status.throttle;
return;
}
work_ticks += 1d;
if (work_ticks >= current_job.ticks_processing_time) {
MachineJobFinish status = onJobFinish(current_job);
MachineJobStatus finish = onJobFinish(current_job);
if (status.finished) {
if (finish.valid) {
current_job = null;
work_ticks = 0d;
} else {
throttle_job_finish += status.throttle;
throttle_ticks += finish.throttle;
}
}
}
} else {
MachineJobFinish status = onJobFinish(current_job);
MachineJobStatus finish = onJobFinish(current_job);
if (status.finished) {
if (finish.valid) {
current_job = null;
work_ticks = 0d;
} else {
throttle_job_finish += status.throttle;
throttle_ticks += finish.throttle;
}
}
}

View File

@ -24,6 +24,11 @@ public interface IMatterGridCell {
return null;
}
@Nullable
default IMatterTaskProvider getTaskProvider() {
return null;
}
boolean isValidMatterCell();
void setMatterGrid(MatterGrid grid);
@ -32,6 +37,10 @@ public interface IMatterGridCell {
}
default void notifyTasksChanged() {
}
default void scheduleDiscoverNeighbours(BlockPos pos, Level level) {
MatterGrid.scheduleDiscoverNeighbours(this, pos, level);
}

View File

@ -0,0 +1,52 @@
package ru.dbotthepony.mc.otm.capability;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.UUID;
public interface IMatterTaskProvider {
/**
* @return immutable collection of tasks that can be allocated by a worker
*/
@Nonnull
Collection<MatterTask> getTasks();
/**
* @return immutable collection of all stored tasks, even fully allocated by workers
*/
@Nonnull
Collection<MatterTask> getAllTasks();
/**
* Allocates (marks as work-in-progress) a task
* by incrementing it's in_progress by 1
* and shrinking required by 1
*
* If required == 0, it should not be returned by this method
* @param simulate whenever to change internal state
* @return MatterTask that should be performed, or null of no tasks available
*/
@Nullable
MatterTask allocateTask(boolean simulate);
/**
* Notify about task completion. If this provider indeed contain this task, it should
* shrink in_progress by 1
* If in_progress == 0 and required == 0, it should discard the task
* @param task task being completed. this method should ignore tasks that are not owned by it.
*/
void notifyTaskCompletion(MatterTask task);
/**
* @param id uuid of task
* @return MatterTask that this capability holds with this id, or null
*/
@Nullable
MatterTask getTask(UUID id);
/**
* Destroys all tasks this capability contains
*/
void dropAllTasks();
}

View File

@ -1,8 +1,12 @@
package ru.dbotthepony.mc.otm.capability;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.item.Item;
import net.minecraftforge.registries.ForgeRegistry;
import net.minecraftforge.registries.RegistryManager;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@ -17,17 +21,38 @@ public interface IPatternStorage {
public boolean equals(PatternState state) {
return state.item == this.item && state.research_percent == this.research_percent;
}
public void write(FriendlyByteBuf buffer) {
buffer.writeInt(((ForgeRegistry<Item>) RegistryManager.ACTIVE.getRegistry(Item.class)).getID(item));
buffer.writeDouble(research_percent);
}
@Nullable
public static PatternState read(FriendlyByteBuf buffer) {
int item = buffer.readInt();
double percent = buffer.readDouble();
Item get_item = ((ForgeRegistry<Item>) RegistryManager.ACTIVE.getRegistry(Item.class)).getValue(item);
if (get_item == null)
return null;
return new PatternState(get_item, percent);
}
}
/**
* @return unmodifiable collection of stored patterns
*/
@Nonnull
Collection<PatternState> getStoredPatterns();
@Nonnull
default Collection<PatternState> findPattern(Item item) {
return findPattern((item2) -> item.equals(item2.item));
}
@Nonnull
default Collection<PatternState> findPattern(Predicate<PatternState> predicate) {
return getStoredPatterns().stream().filter(predicate).collect(Collectors.toList());
}

View File

@ -0,0 +1,77 @@
package ru.dbotthepony.mc.otm.capability;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.common.util.INBTSerializable;
import net.minecraftforge.registries.RegistryManager;
import javax.annotation.Nullable;
import java.util.Objects;
import java.util.UUID;
public record MatterTask(UUID id, Item item, int in_progress, int finished, int required) {
public MatterTask(UUID id, Item item, int in_progress, int finished, int required) {
this.id = id;
this.item = item;
this.in_progress = Math.max(0, in_progress);
this.finished = Math.max(0, finished);
this.required = Math.max(0, required);
}
public ItemStack stack() {
return new ItemStack(item, 1);
}
public ItemStack stack(int amount) {
return new ItemStack(item, amount);
}
public int total() {
return in_progress + finished + required;
}
public MatterTask shrinkRequired(int amount) {
return new MatterTask(id, item, in_progress + amount, finished, required - amount);
}
public MatterTask shrinkInProgress(int amount) {
return new MatterTask(id, item, in_progress - amount, finished + amount, required);
}
public CompoundTag serializeNBT() {
CompoundTag tag = new CompoundTag();
tag.putLong("id_l", id.getLeastSignificantBits());
tag.putLong("id_u", id.getMostSignificantBits());
tag.putString("item", Objects.requireNonNull(item.getRegistryName()).toString());
tag.putInt("in_progress", in_progress);
tag.putInt("finished", finished);
tag.putInt("required", required);
return tag;
}
@Nullable
public static MatterTask deserializeNBT(@Nullable Tag nbt) {
if (nbt == null)
return null;
if (nbt instanceof CompoundTag tag) {
Item get_item = RegistryManager.ACTIVE.getRegistry(Item.class).getValue(new ResourceLocation(tag.getString("item")));
if (get_item != null)
return new MatterTask(
new UUID(tag.getLong("id_u"), tag.getLong("id_l")),
get_item,
tag.getInt("in_progress"),
tag.getInt("finished"),
tag.getInt("required")
);
}
return null;
}
}

View File

@ -25,12 +25,16 @@ public class MatteryCapability {
@CapabilityInject(IPatternStorage.class)
public static Capability<IPatternStorage> PATTERN = null;
@CapabilityInject(IMatterTaskProvider.class)
public static Capability<IMatterTaskProvider> TASK = null;
public static void register() {
CapabilityManager.INSTANCE.register(IAndroidCapability.class);
CapabilityManager.INSTANCE.register(IMatteryEnergyStorage.class);
CapabilityManager.INSTANCE.register(IMatterHandler.class);
CapabilityManager.INSTANCE.register(IPatternStorage.class);
CapabilityManager.INSTANCE.register(IMatterGridCell.class);
CapabilityManager.INSTANCE.register(IMatterTaskProvider.class);
}
public static final MathContext ROUND_RULES = new MathContext(32, RoundingMode.HALF_DOWN);

View File

@ -8,9 +8,7 @@ import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fmlserverevents.FMLServerStartedEvent;
import net.minecraftforge.fmlserverevents.FMLServerStoppingEvent;
import ru.dbotthepony.mc.otm.capability.IMatterGridCell;
import ru.dbotthepony.mc.otm.capability.IMatterHandler;
import ru.dbotthepony.mc.otm.capability.IPatternStorage;
import ru.dbotthepony.mc.otm.capability.*;
import javax.annotation.Nullable;
import java.math.BigDecimal;
@ -283,6 +281,50 @@ public class MatterGrid {
return null;
}
public boolean hasPatternState(IPatternStorage.PatternState state) {
for (IMatterGridCell cell : cells) {
IPatternStorage storage = cell.getPatternStorage();
if (storage != null) {
if (storage.hasExactPattern(state)) {
return true;
}
}
}
return false;
}
@Nullable
public MatterTask allocateTask(boolean simulate) {
for (IMatterGridCell cell : cells) {
IMatterTaskProvider tasks = cell.getTaskProvider();
if (tasks != null) {
MatterTask allocated = tasks.allocateTask(simulate);
if (allocated != null) {
return allocated;
}
}
}
return null;
}
@Nullable
public MatterTask notifyTaskCompletion(MatterTask task) {
for (IMatterGridCell cell : cells) {
IMatterTaskProvider tasks = cell.getTaskProvider();
if (tasks != null) {
tasks.notifyTaskCompletion(task);
}
}
return null;
}
public void notifyPatternsChanged() {
for (IMatterGridCell cell : cells)
cell.notifyPatternsChanged();
@ -305,6 +347,9 @@ public class MatterGrid {
cells.remove(entity);
entity.setMatterGrid(null);
if (cells.size() == 0)
NETWORKS.remove(this);
// OverdriveThatMatters.LOGGER.debug("Untracking {} in {}. Tracking {} in total", entity, this, entities.size());
}

View File

@ -43,7 +43,7 @@ public class MatterDecomposerMenu extends PoweredMatteryMenu {
progress_widget = new ProgressGaugeWidget<>(this, 61 + 18 + 3, 36);
} else {
matter_widget = new MatterLevelWidget<>(this, 22, 14, tile.getCapability(MatteryCapability.MATTER).resolve().get());
progress_widget = new ProgressGaugeWidget<>(this, 61 + 18 + 3, 36, () -> (float) tile.getWorkProgress(), tile::cantFinishJob);
progress_widget = new ProgressGaugeWidget<>(this, 61 + 18 + 3, 36, () -> (float) tile.getWorkProgress(), tile::cantProcessJob);
}
addBatterySlot(14);

View File

@ -0,0 +1,95 @@
package ru.dbotthepony.mc.otm.menu;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraftforge.fmllegacy.network.PacketDistributor;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterPanel;
import ru.dbotthepony.mc.otm.capability.IPatternStorage;
import ru.dbotthepony.mc.otm.network.MatteryNetworking;
import ru.dbotthepony.mc.otm.network.PatternStateSendListPacket;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class MatterPanelMenu extends MatteryMenu {
public MatterPanelMenu(int p_38852_, Inventory inventory) {
this(p_38852_, inventory, null);
}
public MatterPanelMenu(int p_38852_, Inventory inventory, BlockEntityMatterPanel tile) {
super(Registry.Menus.MATTER_PANEL, p_38852_, inventory, tile);
}
@Override
public void broadcastFullState() {
super.broadcastFullState();
sendPatternsToClient();
}
private boolean initial_send = false;
@Override
public void broadcastChanges() {
super.broadcastChanges();
if (!initial_send)
sendPatternsToClient();
}
public ArrayList<IPatternStorage.PatternState> patterns = new ArrayList<>();
public int changeset = 0;
public void networkStates(List<IPatternStorage.PatternState> list) {
changeset++;
patterns.clear();
patterns.addAll(list);
}
public void requestReplication(ServerPlayer ply, IPatternStorage.PatternState state, int how_much) {
if (tile == null)
return;
var grid = ((BlockEntityMatterPanel) tile).getMatterGrid();
if (grid == null)
return;
if (!grid.hasPatternState(state)) {
OverdriveThatMatters.LOGGER.error("Received replication request from {} of {}, but can't find it nowhere", ply, state);
return;
}
OverdriveThatMatters.LOGGER.debug("add task: {}", ((BlockEntityMatterPanel) tile).addTask(state.item(), how_much));
}
public void sendPatternsToClient() {
if (inventory.player.level.isClientSide) {
initial_send = true;
return;
}
if (tile != null) {
var grid = ((BlockEntityMatterPanel) tile).getMatterGrid();
if (grid != null) {
initial_send = true;
MatteryNetworking.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) inventory.player), new PatternStateSendListPacket(containerId, grid.getStoredPatterns()));
}
}
}
@Override
protected int getWorkingSlotStart() {
return 0;
}
@Override
protected int getWorkingSlotEnd() {
return 0;
}
}

View File

@ -0,0 +1,52 @@
package ru.dbotthepony.mc.otm.menu;
import net.minecraft.world.Container;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntity;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterReplicator;
import ru.dbotthepony.mc.otm.matter.MatterRegistry;
import ru.dbotthepony.mc.otm.menu.MatteryMenu;
import ru.dbotthepony.mc.otm.menu.slot.BatterySlot;
import ru.dbotthepony.mc.otm.menu.slot.MachineOutputSlot;
import ru.dbotthepony.mc.otm.menu.slot.SlotAutoRenderable;
import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget;
import javax.annotation.Nullable;
public class MatterReplicatorMenu extends PoweredMatteryMenu {
public MatterReplicatorMenu(int p_38852_, Inventory inventory) {
this(p_38852_, inventory, null);
}
public MatterReplicatorMenu(int p_38852_, Inventory inventory, BlockEntityMatterReplicator tile) {
super(Registry.Menus.MATTER_REPLICATOR, p_38852_, inventory, tile);
Container container = tile != null ? tile.regular_slots : new SimpleContainer(3);
for (int i = 0; i < container.getContainerSize(); i++)
addSlot(new MachineOutputSlot(container, i, 64 + 18 * i, 38, true, false));
if (tile != null) {
new ProgressGaugeWidget<>(this, 38, 38, () -> (float) tile.getWorkProgress(), tile::cantProcessJob);
} else {
new ProgressGaugeWidget<>(this, 38, 38);
}
addBatterySlot();
addInventorySlots();
}
@Override
protected int getWorkingSlotStart() {
return 0;
}
@Override
protected int getWorkingSlotEnd() {
return 7;
}
}

View File

@ -28,7 +28,7 @@ public class MatterScannerMenu extends PoweredMatteryMenu {
});
if (tile != null) {
new ProgressGaugeWidget<>(this, 88, 38, () -> (float) tile.getWorkProgress(), tile::cantFinishJob);
new ProgressGaugeWidget<>(this, 88, 38, () -> (float) tile.getWorkProgress(), tile::cantProcessJob);
} else {
new ProgressGaugeWidget<>(this, 88, 38);
}

View File

@ -117,6 +117,13 @@ public abstract class MatteryMenu extends AbstractContainerMenu {
// if TRUE, iteration order is end_slot_index -> start_slot_index
// if FALSE iteration order is start_slot_index -> end_slot_index
int start = getWorkingSlotStart();
int end = getWorkingSlotEnd();
if (start == end) {
return ItemStack.EMPTY;
}
ItemStack moved = ItemStack.EMPTY;
Slot get_slot = this.slots.get(slot_index);
@ -130,7 +137,7 @@ public abstract class MatteryMenu extends AbstractContainerMenu {
if (!moveItemStackTo(slot_item, inventory_slot_index_start, inventory_slot_index_end + 1, false)) {
return ItemStack.EMPTY;
}
} else if (!moveItemStackTo(slot_item, getWorkingSlotStart(), getWorkingSlotEnd(), false)) {
} else if (!moveItemStackTo(slot_item, start, end, false)) {
// Moving FROM inventory TO machine
return ItemStack.EMPTY;
}

View File

@ -11,6 +11,14 @@ import javax.annotation.Nonnull;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
/**
* This widget class implement *shared* code
* meaning these widgets are created inside Menu, not inside Screen
* and these widgets are supposed to move data between server to client
*
* this is why this is different from Minecraft's clientside only widgets
* @param <T> menu type
*/
public abstract class AbstractWidget<T extends MatteryMenu> {
public static final ResourceLocation TEXTURE = new ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets.png");

View File

@ -0,0 +1,29 @@
package ru.dbotthepony.mc.otm.network;
import net.minecraft.client.Minecraft;
import net.minecraftforge.fmllegacy.network.NetworkEvent;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.menu.MatterPanelMenu;
import java.util.function.Supplier;
public class ClientPatternStateSendListPacketHandler {
public static void handlePacket(PatternStateSendListPacket packet, Supplier<NetworkEvent.Context> context) {
if (Minecraft.getInstance().player.containerMenu == null) {
OverdriveThatMatters.LOGGER.error("Receive pattern state list for {}, but nothing is open!", packet.container_id);
return;
}
if (Minecraft.getInstance().player.containerMenu.containerId != packet.container_id) {
OverdriveThatMatters.LOGGER.error("Receive pattern state list for {}, but {} is open! ({})", packet.container_id, Minecraft.getInstance().player.containerMenu.containerId, Minecraft.getInstance().player.containerMenu);
return;
}
if (!(Minecraft.getInstance().player.containerMenu instanceof MatterPanelMenu menu)) {
OverdriveThatMatters.LOGGER.error("Receive pattern state list for {}, but it is wrong type!", packet.container_id);
return;
}
menu.networkStates(packet.states);
}
}

View File

@ -29,5 +29,23 @@ public class MatteryNetworking {
AndroidCapabilityChangePacket::handleMessage,
Optional.of(NetworkDirection.PLAY_TO_CLIENT)
);
CHANNEL.registerMessage(
next_network_id++,
PatternStateSendListPacket.class,
PatternStateSendListPacket::encodeNetwork,
PatternStateSendListPacket::decodeNetwork,
PatternStateSendListPacket::handleMessage,
Optional.of(NetworkDirection.PLAY_TO_CLIENT)
);
CHANNEL.registerMessage(
next_network_id++,
PatternReplicationRequestPacket.class,
PatternReplicationRequestPacket::encodeNetwork,
PatternReplicationRequestPacket::decodeNetwork,
PatternReplicationRequestPacket::handleMessage,
Optional.of(NetworkDirection.PLAY_TO_SERVER)
);
}
}

View File

@ -0,0 +1,45 @@
package ru.dbotthepony.mc.otm.network;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fmllegacy.network.NetworkEvent;
import ru.dbotthepony.mc.otm.capability.IPatternStorage;
import ru.dbotthepony.mc.otm.menu.MatterPanelMenu;
import java.util.function.Supplier;
public record PatternReplicationRequestPacket(IPatternStorage.PatternState state, int how_much) {
public PatternReplicationRequestPacket(IPatternStorage.PatternState state, int how_much) {
this.state = state;
this.how_much = Math.max(1, Math.min(99999, how_much));
}
public void encodeNetwork(FriendlyByteBuf buffer) {
state.write(buffer);
buffer.writeInt(how_much);
}
public void handleMessage(Supplier<NetworkEvent.Context> context) {
context.get().setPacketHandled(true);
context.get().enqueueWork(() -> {
if (state == null)
return;
var ply = context.get().getSender();
if (ply.containerMenu == null)
return;
if (!(ply.containerMenu instanceof MatterPanelMenu))
return;
((MatterPanelMenu) ply.containerMenu).requestReplication(ply, state, how_much);
});
}
public static PatternReplicationRequestPacket decodeNetwork(FriendlyByteBuf buffer) {
return new PatternReplicationRequestPacket(IPatternStorage.PatternState.read(buffer), buffer.readInt());
}
}

View File

@ -0,0 +1,62 @@
package ru.dbotthepony.mc.otm.network;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fmllegacy.network.NetworkEvent;
import ru.dbotthepony.mc.otm.capability.IPatternStorage;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Supplier;
public class PatternStateSendListPacket {
public PatternStateSendListPacket() {
}
public PatternStateSendListPacket(Collection<IPatternStorage.PatternState> states) {
this.states.addAll(states);
}
public PatternStateSendListPacket(int container_id, Collection<IPatternStorage.PatternState> states) {
this(states);
this.container_id = container_id;
}
public int container_id;
public ArrayList<IPatternStorage.PatternState> states = new ArrayList<>();
public void encodeNetwork(FriendlyByteBuf buffer) {
buffer.writeInt(container_id);
buffer.writeInt(states.size());
for (var state : states) {
state.write(buffer);
}
}
public void handleMessage(Supplier<NetworkEvent.Context> context) {
context.get().setPacketHandled(true);
context.get().enqueueWork(() -> {
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ClientPatternStateSendListPacketHandler.handlePacket(this, context));
});
}
public static PatternStateSendListPacket decodeNetwork(FriendlyByteBuf buffer) {
var packet = new PatternStateSendListPacket();
packet.container_id = buffer.readInt();
int size = buffer.readInt();
for (int i = 0; i < size; i++) {
var state = IPatternStorage.PatternState.read(buffer);
if (state != null) {
packet.states.add(state);
}
}
return packet;
}
}

View File

@ -0,0 +1,424 @@
package ru.dbotthepony.mc.otm.screen;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.capability.IPatternStorage;
import ru.dbotthepony.mc.otm.menu.MatterPanelMenu;
import ru.dbotthepony.mc.otm.network.MatteryNetworking;
import ru.dbotthepony.mc.otm.network.PatternReplicationRequestPacket;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.List;
import static org.lwjgl.opengl.GL11.GL_ALWAYS;
import static org.lwjgl.opengl.GL11.GL_LESS;
public class MatterPanelScreen extends MatteryScreen<MatterPanelMenu> {
private static final int modal_width = 213;
private static final int modal_height = 110;
protected static final ResourceLocation CONTAINER = new ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/matter_panel.png");
protected ResourceLocation CONTAINER_BACKGROUND() {
return CONTAINER;
}
public MatterPanelScreen(MatterPanelMenu p_97741_, Inventory p_97742_, Component p_97743_) {
super(p_97741_, p_97742_, p_97743_);
imageWidth = 176;
imageHeight = 187;
titleLabelY = 5;
}
private IPatternStorage.PatternState open_pattern;
private EditBox input_amount;
private Button inc_8;
private Button inc_64;
private Button inc_256;
private Button dec_8;
private Button dec_64;
private Button dec_256;
private Button send;
private Button cancel;
private IPatternStorage.PatternState hovered_pattern;
private double dragger_position = 0;
@Override
protected void init() {
super.init();
int x = (width - modal_width) / 2;
int y = (height - modal_height) / 2;
int top_level = 15;
int button_width = 40;
int right = 5 + button_width;
int box_width = modal_width - 5 - 5 - 30;
inc_8 = new Button(x + modal_width - right, y + top_level, button_width, 20, new TranslatableComponent("otm.container.matter_panel.increase_by", 8), (btn) -> onChangeAmountPress(8));
right += 2 + button_width;
inc_64 = new Button(x + modal_width - right, y + top_level, button_width, 20, new TranslatableComponent("otm.container.matter_panel.increase_by", 64), (btn) -> onChangeAmountPress(64));
right += 2 + button_width;
inc_256 = new Button(x + modal_width - right, y + top_level, button_width, 20, new TranslatableComponent("otm.container.matter_panel.increase_by", 256), (btn) -> onChangeAmountPress(256));
right = 5 + button_width;
top_level += 24;
input_amount = new EditBox(font, x + modal_width - 5 - box_width, y + top_level, box_width, 16, new TranslatableComponent("otm.container.matter_panel.number_input"));
input_amount.setMaxLength(6);
input_amount.setValue("1");
input_amount.visible = false;
top_level += 20;
dec_8 = new Button(x + modal_width - right, y + top_level, button_width, 20, new TranslatableComponent("otm.container.matter_panel.decrease_by", 8), (btn) -> onChangeAmountPress(-8));
right += 2 + button_width;
dec_64 = new Button(x + modal_width - right, y + top_level, button_width, 20, new TranslatableComponent("otm.container.matter_panel.decrease_by", 64), (btn) -> onChangeAmountPress(-64));
right += 2 + button_width;
dec_256 = new Button(x + modal_width - right, y + top_level, button_width, 20, new TranslatableComponent("otm.container.matter_panel.decrease_by", 256), (btn) -> onChangeAmountPress(-256));
top_level += 24;
right = 5 + button_width;
cancel = new Button(x + modal_width - right, y + top_level, button_width, 20, new TranslatableComponent("otm.container.matter_panel.cancel"), (btn) -> onCancel());
right += 2 + button_width;
send = new Button(x + modal_width - right, y + top_level, button_width, 20, new TranslatableComponent("otm.container.matter_panel.send"), (btn) -> onSend());
inc_8.visible = false;
inc_64.visible = false;
inc_256.visible = false;
dec_8.visible = false;
dec_64.visible = false;
dec_256.visible = false;
send.visible = false;
cancel.visible = false;
addWidget(input_amount);
addWidget(inc_8);
addWidget(inc_64);
addWidget(inc_256);
addWidget(dec_8);
addWidget(dec_64);
addWidget(dec_256);
addWidget(send);
addWidget(cancel);
}
private void onChangeAmountPress(int amount) {
int value = 1;
try {
value = Integer.parseInt(input_amount.getValue());
} catch (Exception ignored) {
}
input_amount.setValue(Integer.toString(Math.max(1, Math.min(99999, value + amount))));
}
private void onSend() {
int value = 1;
try {
value = Integer.parseInt(input_amount.getValue());
} catch (Exception ignored) {
}
MatteryNetworking.CHANNEL.sendToServer(new PatternReplicationRequestPacket(open_pattern, value));
open_pattern = null;
}
private void onCancel() {
open_pattern = null;
}
@Override
protected void containerTick() {
super.containerTick();
input_amount.tick();
}
@Override
public void resize(Minecraft p_96575_, int p_96576_, int p_96577_) {
var input_amount = this.input_amount;
super.resize(p_96575_, p_96576_, p_96577_);
if (input_amount != null) {
this.input_amount.setValue(input_amount.getValue());
}
}
@Override
protected void renderForeground(PoseStack stack, int mouseX, int mouseY, float p_98421_) {
if (open_pattern != null) {
RenderSystem.disableDepthTest();
input_amount.render(stack, mouseX, mouseY, p_98421_);
input_amount.visible = true;
inc_8.render(stack, mouseX, mouseY, p_98421_);
inc_8.visible = true;
inc_64.render(stack, mouseX, mouseY, p_98421_);
inc_64.visible = true;
inc_256.render(stack, mouseX, mouseY, p_98421_);
inc_256.visible = true;
dec_8.visible = true;
dec_64.visible = true;
dec_256.visible = true;
send.visible = true;
cancel.visible = true;
dec_8.render(stack, mouseX, mouseY, p_98421_);
dec_64.render(stack, mouseX, mouseY, p_98421_);
dec_256.render(stack, mouseX, mouseY, p_98421_);
dec_8.render(stack, mouseX, mouseY, p_98421_);
send.render(stack, mouseX, mouseY, p_98421_);
cancel.render(stack, mouseX, mouseY, p_98421_);
} else {
input_amount.visible = false;
inc_8.visible = false;
inc_64.visible = false;
inc_256.visible = false;
send.visible = false;
cancel.visible = false;
dec_8.visible = false;
dec_64.visible = false;
dec_256.visible = false;
}
}
@Override
protected void renderLabels(PoseStack p_97808_, int p_97809_, int p_97810_) {}
@Nonnull
@Override
public List<Component> getTooltipFromItem(ItemStack p_96556_) {
List<Component> get_list = super.getTooltipFromItem(p_96556_);
if (hovered_pattern != null) {
get_list.add(new TranslatableComponent("otm.item.pattern.research", String.format("%.2f", hovered_pattern.research_percent() * 100d)).withStyle(ChatFormatting.AQUA));
}
return get_list;
}
@Override
protected void renderTooltip(PoseStack pose, int mouseX, int mouseY) {
if (open_pattern != null) {
int x = (width - modal_width) / 2 + 7;
int y = input_amount.y + 1;
if (mouseX >= x && mouseX <= x + 16 && mouseY >= y && mouseY <= y + 16) {
this.renderTooltip(pose, new ItemStack(open_pattern.item(), 1), mouseX, mouseY);
return;
}
} else if (hovered_pattern != null) {
this.renderTooltip(pose, new ItemStack(hovered_pattern.item(), 1), mouseX, mouseY);
return;
}
super.renderTooltip(pose, mouseX, mouseY);
}
private void openPattern(IPatternStorage.PatternState state) {
open_pattern = state;
input_amount.setValue("1");
scrolling = false;
}
@Override
public boolean mouseClicked(double mouse_x, double mouse_y, int p_97750_) {
if (hovered_pattern != null && open_pattern == null) {
openPattern(hovered_pattern);
return true;
}
double div_scroll = menu.patterns.size() < 1 ? 1 : menu.patterns.size() - 1;
int scroll_x = leftPos + 157;
int scroll_y = topPos + 20 + (int) ((dragger_position / maxScroll()) * 145);
if (maxScroll() > 0 && mouse_x >= scroll_x && scroll_x + 12 >= mouse_x && mouse_y >= scroll_y && scroll_y + 15 >= mouse_y) {
scrolling = true;
} else {
scrolling = false;
}
return super.mouseClicked(mouse_x, mouse_y, p_97750_);
}
@Override
public boolean mouseReleased(double p_97812_, double p_97813_, int p_97814_) {
scrolling = false;
return super.mouseReleased(p_97812_, p_97813_, p_97814_);
}
@Override
public boolean mouseScrolled(double mouse_x, double mouse_y, double scroll) {
if (open_pattern != null) {
return true;
}
if (super.mouseScrolled(mouse_x, mouse_y, scroll)) {
return true;
}
dragger_position = Math.max(0, Math.min(maxScroll(), dragger_position - scroll));
return true;
}
@Override
public boolean mouseDragged(double mouse_x, double mouse_y, int flag, double drag_x, double drag_y) {
if (scrolling && maxScroll() > 0) {
if (mouse_y < topPos + 20) {
dragger_position = 0;
} else if (mouse_y > topPos + 20 + 160) {
dragger_position = maxScroll();
} else {
dragger_position = maxScroll() * (mouse_y - topPos - 20) / 160d;
}
}
return super.mouseDragged(mouse_x, mouse_y, flag, drag_x, drag_y);
}
private boolean scrolling = false;
private int maxScroll() {
if (menu.patterns.size() < 16) {
return 0;
}
return (int) Math.floor(menu.patterns.size() / 8d - 2d);
}
@Override
protected void renderBg(PoseStack pose, float p_97788_, int mouseX, int mouseY) {
super.renderBg(pose, p_97788_, mouseX, mouseY);
RenderSystem.setShader(GameRenderer::getPositionTexShader);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
RenderSystem.setShaderTexture(0, CONTAINER_BACKGROUND());
if (maxScroll() > 0) {
if (scrolling) {
blit(pose, leftPos + 157, topPos + 20 + (int) ((dragger_position / maxScroll()) * 145), 188, 0, 12, 15);
} else {
blit(pose, leftPos + 157, topPos + 20 + (int) ((dragger_position / maxScroll()) * 145), 176, 0, 12, 15);
}
} else {
blit(pose, leftPos + 157, topPos + 20, 176, 0, 12, 15);
}
this.font.draw(pose, this.title, (float) (leftPos + this.titleLabelX), (float) (topPos + this.titleLabelY), 4210752);
hovered_pattern = null;
int cells_width = 8;
int cells_height = 9;
int render_x = leftPos + 10;
int render_y = topPos + 20;
int cell_x = 0;
int cell_y = 0;
RenderSystem.enableDepthTest();
for (int index = ((int) dragger_position) * 9; index < menu.patterns.size(); index++) {
var state = menu.patterns.get(index);
var itemstack = new ItemStack(state.item(), 1);
// player, itemstack, x, y, ??????????
this.itemRenderer.renderAndDecorateItem(this.minecraft.player, itemstack, render_x, render_y, -1);
// font, itemstack, x, y, string
this.itemRenderer.renderGuiItemDecorations(this.font, itemstack, render_x, render_y, null);
if (hovered_pattern == null && mouseX >= render_x && mouseX <= render_x + 16 && mouseY >= render_y && mouseY <= render_y + 16) {
hovered_pattern = state;
}
cell_x++;
render_x += 18;
if (cell_x >= cells_width) {
render_x = leftPos + 10;
render_y += 18;
cell_x = 0;
cell_y++;
if (cell_y >= cells_height)
break;
}
}
if (open_pattern != null) {
RenderSystem.depthFunc(GL_ALWAYS);
this.renderBackground(pose);
RenderSystem.setShader(GameRenderer::getPositionTexShader);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
RenderSystem.setShaderTexture(0, CONTAINER_BACKGROUND());
// PoseStack, x, y, image_start_x, image_start_y, rect_size_x, rect_size_y
int x = (width - modal_width) / 2;
int y = (height - modal_height) / 2;
// заголовок
int dy = 0;
this.blit(pose, x, y, 0, 188, modal_width, 4);
dy += 4;
for (; dy < modal_height - 10; dy += 5)
this.blit(pose, x, y + dy, 0, 192, modal_width, 5);
this.blit(pose, x, y + dy, 0, 197, modal_width, 4);
this.blit(pose, x + 6, input_amount.y, 176, 15, 18, 18);
var itemstack = new ItemStack(open_pattern.item(), 1);
RenderSystem.enableDepthTest();
// player, itemstack, x, y, ??????????
this.itemRenderer.renderAndDecorateItem(this.minecraft.player, itemstack, x + 7, input_amount.y + 1, 100);
// font, itemstack, x, y, string
this.itemRenderer.renderGuiItemDecorations(this.font, itemstack, 0, 0, null);
this.font.draw(pose, new TranslatableComponent("otm.container.matter_panel.label"), (float) (x + 6), (float) (y + 5), 4210752);
this.font.draw(pose, new TranslatableComponent("otm.item.pattern.line", itemstack.getDisplayName(), String.format("%.2f", open_pattern.research_percent() * 100d)), (float) (x + 6), (float) (cancel.y), ChatFormatting.AQUA.getColor());
RenderSystem.depthFunc(GL_LESS);
}
}
}

View File

@ -0,0 +1,11 @@
package ru.dbotthepony.mc.otm.screen;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory;
import ru.dbotthepony.mc.otm.menu.MatterReplicatorMenu;
public class MatterReplicatorScreen extends MatteryScreen<MatterReplicatorMenu> {
public MatterReplicatorScreen(MatterReplicatorMenu p_97741_, Inventory p_97742_, Component p_97743_) {
super(p_97741_, p_97742_, p_97743_);
}
}

View File

@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.screen;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.gui.components.Widget;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.network.chat.Component;
@ -24,9 +25,6 @@ public class MatteryScreen<T extends MatteryMenu> extends AbstractContainerScree
return CONTAINER_BASE;
}
protected int render_x;
protected int render_y;
public MatteryScreen(T p_97741_, Inventory p_97742_, Component p_97743_) {
super(p_97741_, p_97742_, p_97743_);
@ -43,7 +41,7 @@ public class MatteryScreen<T extends MatteryMenu> extends AbstractContainerScree
if (this.hoveredSlot == null && menu.getCarried().isEmpty()) {
for (AbstractWidget widget : menu.widget_list) {
if (widget.renderTooltip(this, pose, render_x, render_y, mouseX, mouseY)) {
if (widget.renderTooltip(this, pose, leftPos, topPos, mouseX, mouseY)) {
return;
}
}
@ -51,30 +49,32 @@ public class MatteryScreen<T extends MatteryMenu> extends AbstractContainerScree
}
@Override
public void render(PoseStack p_98418_, int mouseX, int mouseY, float p_98421_) {
render_x = (width - imageWidth) / 2;
render_y = (height - imageHeight) / 2;
public void render(PoseStack pose, int mouseX, int mouseY, float p_98421_) {
for (AbstractWidget<?> widget : menu.widget_list) {
widget.updateIsHovered(render_x, render_y, mouseX, mouseY);
widget.updateIsHovered(leftPos, topPos, mouseX, mouseY);
}
this.renderBackground(p_98418_);
super.render(p_98418_, mouseX, mouseY, p_98421_);
this.renderTooltip(p_98418_, mouseX, mouseY);
this.renderBackground(pose);
super.render(pose, mouseX, mouseY, p_98421_);
this.renderForeground(pose, mouseX, mouseY, p_98421_);
this.renderTooltip(pose, mouseX, mouseY);
}
protected void renderRegularSlot(PoseStack pose, int x, int y) {
this.blit(pose, render_x + x - 1, render_y + y - 1, 0, 96, 18, 18);
this.blit(pose, leftPos + x - 1, topPos + y - 1, 0, 96, 18, 18);
}
protected void renderOutputSlot(PoseStack pose, int x, int y) {
this.blit(pose, render_x + x - 5, render_y + y - 5, 18, 96, 26, 26);
this.blit(pose, leftPos + x - 5, topPos + y - 5, 18, 96, 26, 26);
}
protected void renderBatterySlot(PoseStack pose, int x, int y) {
renderRegularSlot(pose, x, y);
this.blit(pose, render_x + x - 1, render_y + y - 1, 0, 114, 18, 18);
this.blit(pose, leftPos + x - 1, topPos + y - 1, 0, 114, 18, 18);
}
protected void renderForeground(PoseStack stack, int mouseX, int mouseY, float p_98421_) {
}
@Override
@ -83,7 +83,7 @@ public class MatteryScreen<T extends MatteryMenu> extends AbstractContainerScree
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
RenderSystem.setShaderTexture(0, CONTAINER_BACKGROUND());
// PoseStack, x, y, image_start_x, image_start_y, rect_size_x, rect_size_y
this.blit(pose, render_x, render_y, 0, 0, this.imageWidth, this.imageHeight);
this.blit(pose, leftPos, topPos, 0, 0, this.imageWidth, this.imageHeight);
RenderSystem.setShader(GameRenderer::getPositionTexShader);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
@ -106,7 +106,7 @@ public class MatteryScreen<T extends MatteryMenu> extends AbstractContainerScree
}
for (AbstractWidget widget : menu.widget_list) {
widget.renderBackground(this, pose, render_x, render_y, mouseX, mouseY);
widget.renderBackground(this, pose, leftPos, topPos, mouseX, mouseY);
}
}
}

View File

@ -0,0 +1,27 @@
{
"variants": {
"facing=south": {
"model": "overdrive_that_matters:block/matter_panel"
},
"facing=up": {
"model": "overdrive_that_matters:block/matter_panel",
"x": 90
},
"facing=down": {
"model": "overdrive_that_matters:block/matter_panel",
"x": 180
},
"facing=west": {
"model": "overdrive_that_matters:block/matter_panel",
"y": 90
},
"facing=north": {
"model": "overdrive_that_matters:block/matter_panel",
"y": 180
},
"facing=east": {
"model": "overdrive_that_matters:block/matter_panel",
"y": 270
}
}
}

View File

@ -7,7 +7,7 @@
"otm.gui.power.name": "MtE",
"otm.gui.progress_widget": "Progress: %s%%",
"otm.gui.progress_widget_stuck": "The machine can't finish it's work, check configuration",
"otm.gui.progress_widget_stuck": "The machine can not work, check configuration",
"otm.gui.matter.percentage_level": "Matter level: %s%%",
"otm.gui.matter.format": "Matter: %s",
@ -21,6 +21,7 @@
"otm.item.pattern.stored": "Stored patterns: %s / %s",
"otm.item.pattern.line": "%s [%s%%]",
"otm.item.pattern.research": "Researched: %s%%",
"otm.item.matter.infinite": "Stored matter: Infinity / Infinity",
"otm.item.matter.normal": "Stored matter: %s / %s",
@ -54,6 +55,16 @@
"block.overdrive_that_matters.matter_cable": "Matter network cable",
"block.overdrive_that_matters.pattern_storage": "Pattern storage",
"block.overdrive_that_matters.matter_scanner": "Matter scanner",
"block.overdrive_that_matters.matter_panel": "Pattern monitor",
"block.overdrive_that_matters.matter_replicator": "Matter replicator",
"otm.container.matter_panel.number_input": "Input replication task count",
"otm.container.matter_panel.increase_by": "+%s",
"otm.container.matter_panel.decrease_by": "-%s",
"otm.container.matter_panel.send": "Send",
"otm.container.matter_panel.cancel": "Cancel",
"otm.container.matter_panel.label": "Replication request",
"item.overdrive_that_matters.pill_android": "Android pill",
"item.overdrive_that_matters.pill_humane": "Humane pill",

View File

@ -0,0 +1,17 @@
{
"parent": "block/block",
"elements": [
{
"from": [ 0, 0, 0 ],
"to": [ 16, 16, 6 ],
"faces": {
"down": { "texture": "#side" },
"up": { "texture": "#side" },
"north": { "texture": "#back" },
"south": { "texture": "#front" },
"west": { "texture": "#side" },
"east": { "texture": "#side" }
}
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB