diff --git a/src/main/java/ru/dbotthepony/mc/otm/Registry.java b/src/main/java/ru/dbotthepony/mc/otm/Registry.java index 71b1ae4d7..065049d4f 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/Registry.java +++ b/src/main/java/ru/dbotthepony/mc/otm/Registry.java @@ -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 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 MATTER_CABLE = BlockEntityType.Builder.of(BlockEntityMatterCable::new, Blocks.MATTER_CABLE).build(null); public static final BlockEntityType PATTERN_STORAGE = BlockEntityType.Builder.of(BlockEntityPatternStorage::new, Blocks.PATTERN_STORAGE).build(null); public static final BlockEntityType MATTER_SCANNER = BlockEntityType.Builder.of(BlockEntityMatterScanner::new, Blocks.MATTER_SCANNER).build(null); + public static final BlockEntityType MATTER_PANEL = BlockEntityType.Builder.of(BlockEntityMatterPanel::new, Blocks.MATTER_PANEL).build(null); + public static final BlockEntityType 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> 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 MATTER_CAPACITOR_BANK = new MenuType<>(MatterCapacitorBankMenu::new); public static final MenuType PATTERN_STORAGE = new MenuType<>(PatternStorageMenu::new); public static final MenuType MATTER_SCANNER = new MenuType<>(MatterScannerMenu::new); + public static final MenuType MATTER_PANEL = new MenuType<>(MatterPanelMenu::new); + public static final MenuType 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> 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"); } diff --git a/src/main/java/ru/dbotthepony/mc/otm/block/BlockMatterPanel.java b/src/main/java/ru/dbotthepony/mc/otm/block/BlockMatterPanel.java new file mode 100644 index 000000000..f2ed74eb3 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/block/BlockMatterPanel.java @@ -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 FACING = EnumProperty.create( + "facing", + Direction.class); + + private ImmutableMap 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 builder) { + builder.add(FACING); + } + + @Nullable + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + return this.defaultBlockState().setValue(FACING, context.getClickedFace()); + } + +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/block/BlockMatterReplicator.java b/src/main/java/ru/dbotthepony/mc/otm/block/BlockMatterReplicator.java new file mode 100644 index 000000000..f4f0c20f1 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/block/BlockMatterReplicator.java @@ -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 BlockEntityTicker getTicker(Level p_153212_, BlockState p_153213_, BlockEntityType p_153214_) { + return p_153212_.isClientSide || p_153214_ != Registry.BlockEntities.MATTER_REPLICATOR ? null : BlockEntityMatteryPoweredWorker::basicTicker; + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterDecomposer.java b/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterDecomposer.java index 86c2cdcde..0fac88ffc 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterDecomposer.java +++ b/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterDecomposer.java @@ -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); } } diff --git a/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterPanel.java b/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterPanel.java new file mode 100644 index 000000000..9bb998965 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterPanel.java @@ -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 resolver = LazyOptional.of(() -> this); + + @Nonnull + @Override + public LazyOptional getCapability(@Nonnull Capability 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 tasks = new HashMap<>(); + + @Nonnull + @Override + public Collection getTasks() { + return tasks.values().stream().filter(task -> task.required() > 0).collect(Collectors.toList()); + } + + @Nonnull + @Override + public Collection 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(); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterReplicator.java b/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterReplicator.java new file mode 100644 index 000000000..be97b963a --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterReplicator.java @@ -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 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 resolver_self = LazyOptional.of(() -> this); + + @Nonnull + @Override + public LazyOptional getCapability(@Nonnull Capability 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; + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterScanner.java b/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterScanner.java index c62d556f3..b9187249e 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterScanner.java +++ b/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterScanner.java @@ -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 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; diff --git a/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatteryPoweredWorker.java b/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatteryPoweredWorker.java index 3b546a21a..7eec020f7 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatteryPoweredWorker.java +++ b/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatteryPoweredWorker.java @@ -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; } } } diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/IMatterGridCell.java b/src/main/java/ru/dbotthepony/mc/otm/capability/IMatterGridCell.java index d978e902f..1b511ef2a 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/capability/IMatterGridCell.java +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/IMatterGridCell.java @@ -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); } diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/IMatterTaskProvider.java b/src/main/java/ru/dbotthepony/mc/otm/capability/IMatterTaskProvider.java new file mode 100644 index 000000000..51c2939fa --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/IMatterTaskProvider.java @@ -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 getTasks(); + + /** + * @return immutable collection of all stored tasks, even fully allocated by workers + */ + @Nonnull + Collection 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(); +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/IPatternStorage.java b/src/main/java/ru/dbotthepony/mc/otm/capability/IPatternStorage.java index 6a37567f9..b6a46a986 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/capability/IPatternStorage.java +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/IPatternStorage.java @@ -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) 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) 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 getStoredPatterns(); + @Nonnull default Collection findPattern(Item item) { return findPattern((item2) -> item.equals(item2.item)); } + @Nonnull default Collection findPattern(Predicate predicate) { return getStoredPatterns().stream().filter(predicate).collect(Collectors.toList()); } diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/MatterTask.java b/src/main/java/ru/dbotthepony/mc/otm/capability/MatterTask.java new file mode 100644 index 000000000..4dca37f80 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/MatterTask.java @@ -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; + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/MatteryCapability.java b/src/main/java/ru/dbotthepony/mc/otm/capability/MatteryCapability.java index f39b22d78..620ea8f73 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/capability/MatteryCapability.java +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/MatteryCapability.java @@ -25,12 +25,16 @@ public class MatteryCapability { @CapabilityInject(IPatternStorage.class) public static Capability PATTERN = null; + @CapabilityInject(IMatterTaskProvider.class) + public static Capability 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); diff --git a/src/main/java/ru/dbotthepony/mc/otm/matter/MatterGrid.java b/src/main/java/ru/dbotthepony/mc/otm/matter/MatterGrid.java index 26b064d61..30c187a7e 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/matter/MatterGrid.java +++ b/src/main/java/ru/dbotthepony/mc/otm/matter/MatterGrid.java @@ -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()); } diff --git a/src/main/java/ru/dbotthepony/mc/otm/menu/MatterDecomposerMenu.java b/src/main/java/ru/dbotthepony/mc/otm/menu/MatterDecomposerMenu.java index 3f5c93572..0795ce7ac 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/menu/MatterDecomposerMenu.java +++ b/src/main/java/ru/dbotthepony/mc/otm/menu/MatterDecomposerMenu.java @@ -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); diff --git a/src/main/java/ru/dbotthepony/mc/otm/menu/MatterPanelMenu.java b/src/main/java/ru/dbotthepony/mc/otm/menu/MatterPanelMenu.java new file mode 100644 index 000000000..e71879bf2 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/menu/MatterPanelMenu.java @@ -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 patterns = new ArrayList<>(); + public int changeset = 0; + + public void networkStates(List 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; + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/menu/MatterReplicatorMenu.java b/src/main/java/ru/dbotthepony/mc/otm/menu/MatterReplicatorMenu.java new file mode 100644 index 000000000..100024184 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/menu/MatterReplicatorMenu.java @@ -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; + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/menu/MatterScannerMenu.java b/src/main/java/ru/dbotthepony/mc/otm/menu/MatterScannerMenu.java index b756d1e64..5d6305d68 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/menu/MatterScannerMenu.java +++ b/src/main/java/ru/dbotthepony/mc/otm/menu/MatterScannerMenu.java @@ -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); } diff --git a/src/main/java/ru/dbotthepony/mc/otm/menu/MatteryMenu.java b/src/main/java/ru/dbotthepony/mc/otm/menu/MatteryMenu.java index 6a5059f3e..f502386b8 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/menu/MatteryMenu.java +++ b/src/main/java/ru/dbotthepony/mc/otm/menu/MatteryMenu.java @@ -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; } diff --git a/src/main/java/ru/dbotthepony/mc/otm/menu/widget/AbstractWidget.java b/src/main/java/ru/dbotthepony/mc/otm/menu/widget/AbstractWidget.java index 90f3e5904..89568a971 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/menu/widget/AbstractWidget.java +++ b/src/main/java/ru/dbotthepony/mc/otm/menu/widget/AbstractWidget.java @@ -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 menu type + */ public abstract class AbstractWidget { public static final ResourceLocation TEXTURE = new ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets.png"); diff --git a/src/main/java/ru/dbotthepony/mc/otm/network/ClientPatternStateSendListPacketHandler.java b/src/main/java/ru/dbotthepony/mc/otm/network/ClientPatternStateSendListPacketHandler.java new file mode 100644 index 000000000..42fd6275b --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/network/ClientPatternStateSendListPacketHandler.java @@ -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 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); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java b/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java index d0ff337a5..cf568bff3 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java +++ b/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java @@ -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) + ); } } diff --git a/src/main/java/ru/dbotthepony/mc/otm/network/PatternReplicationRequestPacket.java b/src/main/java/ru/dbotthepony/mc/otm/network/PatternReplicationRequestPacket.java new file mode 100644 index 000000000..bb2819626 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/network/PatternReplicationRequestPacket.java @@ -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 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()); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/network/PatternStateSendListPacket.java b/src/main/java/ru/dbotthepony/mc/otm/network/PatternStateSendListPacket.java new file mode 100644 index 000000000..ef9a43779 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/network/PatternStateSendListPacket.java @@ -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 states) { + this.states.addAll(states); + } + + public PatternStateSendListPacket(int container_id, Collection states) { + this(states); + this.container_id = container_id; + } + + public int container_id; + public ArrayList 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 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; + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/MatterPanelScreen.java b/src/main/java/ru/dbotthepony/mc/otm/screen/MatterPanelScreen.java new file mode 100644 index 000000000..17103485a --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/MatterPanelScreen.java @@ -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 { + 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 getTooltipFromItem(ItemStack p_96556_) { + List 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); + } + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/MatterReplicatorScreen.java b/src/main/java/ru/dbotthepony/mc/otm/screen/MatterReplicatorScreen.java new file mode 100644 index 000000000..1929d24fd --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/MatterReplicatorScreen.java @@ -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 { + public MatterReplicatorScreen(MatterReplicatorMenu p_97741_, Inventory p_97742_, Component p_97743_) { + super(p_97741_, p_97742_, p_97743_); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/MatteryScreen.java b/src/main/java/ru/dbotthepony/mc/otm/screen/MatteryScreen.java index f7b7f1453..5d43d0435 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/screen/MatteryScreen.java +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/MatteryScreen.java @@ -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 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 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 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 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 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); } } } diff --git a/src/main/resources/assets/overdrive_that_matters/blockstates/matter_panel.json b/src/main/resources/assets/overdrive_that_matters/blockstates/matter_panel.json new file mode 100644 index 000000000..91d2d79bd --- /dev/null +++ b/src/main/resources/assets/overdrive_that_matters/blockstates/matter_panel.json @@ -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 + } + } +} diff --git a/src/main/resources/assets/overdrive_that_matters/lang/en_us.json b/src/main/resources/assets/overdrive_that_matters/lang/en_us.json index 328f86afb..cb77dd556 100644 --- a/src/main/resources/assets/overdrive_that_matters/lang/en_us.json +++ b/src/main/resources/assets/overdrive_that_matters/lang/en_us.json @@ -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", diff --git a/src/main/resources/assets/overdrive_that_matters/models/block/matter_panel.json b/src/main/resources/assets/overdrive_that_matters/models/block/matter_panel.json new file mode 100644 index 000000000..8b5bccd0a --- /dev/null +++ b/src/main/resources/assets/overdrive_that_matters/models/block/matter_panel.json @@ -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" } + } + } + ] +} diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/android_station.png b/src/main/resources/assets/overdrive_that_matters/textures/gui/android_station.png index b920ebcc0..debc0e4f0 100644 Binary files a/src/main/resources/assets/overdrive_that_matters/textures/gui/android_station.png and b/src/main/resources/assets/overdrive_that_matters/textures/gui/android_station.png differ diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/android_station.xcf b/src/main/resources/assets/overdrive_that_matters/textures/gui/android_station.xcf index 798fb9990..334dac1b8 100644 Binary files a/src/main/resources/assets/overdrive_that_matters/textures/gui/android_station.xcf and b/src/main/resources/assets/overdrive_that_matters/textures/gui/android_station.xcf differ diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/generic_machine.png b/src/main/resources/assets/overdrive_that_matters/textures/gui/generic_machine.png index 3abf7adc2..2469f6b1a 100644 Binary files a/src/main/resources/assets/overdrive_that_matters/textures/gui/generic_machine.png and b/src/main/resources/assets/overdrive_that_matters/textures/gui/generic_machine.png differ diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/generic_machine.xcf b/src/main/resources/assets/overdrive_that_matters/textures/gui/generic_machine.xcf index a71437516..bdfaeeb65 100644 Binary files a/src/main/resources/assets/overdrive_that_matters/textures/gui/generic_machine.xcf and b/src/main/resources/assets/overdrive_that_matters/textures/gui/generic_machine.xcf differ diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/matter_panel.png b/src/main/resources/assets/overdrive_that_matters/textures/gui/matter_panel.png new file mode 100644 index 000000000..58546a545 Binary files /dev/null and b/src/main/resources/assets/overdrive_that_matters/textures/gui/matter_panel.png differ diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/matter_panel.xcf b/src/main/resources/assets/overdrive_that_matters/textures/gui/matter_panel.xcf new file mode 100644 index 000000000..2bfbeef51 Binary files /dev/null and b/src/main/resources/assets/overdrive_that_matters/textures/gui/matter_panel.xcf differ