Storage system initial commit
This commit is contained in:
parent
7ff41bbda2
commit
56a45b9ad3
@ -1,15 +1,22 @@
|
||||
package ru.dbotthepony.mc.otm;
|
||||
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.item.CreativeModeTab;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.InterModComms;
|
||||
import net.minecraftforge.fml.LogicalSide;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent;
|
||||
import net.minecraftforge.fml.event.lifecycle.InterModProcessEvent;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||
import net.minecraftforge.fmlserverevents.FMLServerStartedEvent;
|
||||
import net.minecraftforge.fmlserverevents.FMLServerStoppingEvent;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import ru.dbotthepony.mc.otm.block.entity.BlockEntityBlackHole;
|
||||
@ -25,7 +32,12 @@ import ru.dbotthepony.mc.otm.matter.MatterGrid;
|
||||
import ru.dbotthepony.mc.otm.matter.MatterRegistry;
|
||||
import ru.dbotthepony.mc.otm.network.MatteryNetworking;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
// The value here should match an entry in the META-INF/mods.toml file
|
||||
@ -39,6 +51,67 @@ public class OverdriveThatMatters {
|
||||
|
||||
public static CreativeModeTab CREATIVE_TAB;
|
||||
|
||||
private static final WeakHashMap<Level, Set<Supplier<Boolean>>> tick_until = new WeakHashMap<>();
|
||||
private static final WeakHashMap<Level, ArrayList<Consumer<Level>>> tick_once = new WeakHashMap<>();
|
||||
|
||||
@SubscribeEvent
|
||||
public void onServerStarting(FMLServerStartedEvent event) {
|
||||
tick_until.clear();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onServerStopping(FMLServerStoppingEvent event) {
|
||||
tick_until.clear();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onPreTick(TickEvent.WorldTickEvent event) {
|
||||
if (event.phase != TickEvent.Phase.START || event.side != LogicalSide.SERVER)
|
||||
return;
|
||||
|
||||
var set = tick_until.get(event.world);
|
||||
|
||||
if (set != null) {
|
||||
ArrayList<Supplier<Boolean>> invalid = new ArrayList<>();
|
||||
|
||||
for (var ticker : set) {
|
||||
if (ticker.get()) {
|
||||
invalid.add(ticker);
|
||||
}
|
||||
}
|
||||
|
||||
if (invalid.size() != 0) {
|
||||
for (Supplier<Boolean> cell : invalid) {
|
||||
set.remove(cell);
|
||||
}
|
||||
}
|
||||
|
||||
if (set.size() == 0) {
|
||||
tick_until.remove(event.world);
|
||||
}
|
||||
}
|
||||
|
||||
var list = tick_once.get(event.world);
|
||||
|
||||
if (list != null) {
|
||||
ArrayList<Supplier<Boolean>> invalid = new ArrayList<>();
|
||||
|
||||
for (var ticker : list) {
|
||||
ticker.accept(event.world);
|
||||
}
|
||||
|
||||
tick_once.remove(event.world);
|
||||
}
|
||||
}
|
||||
|
||||
public static void tickUntil(Level level, Supplier<Boolean> ticker) {
|
||||
tick_until.computeIfAbsent(level, (k) -> new HashSet<>()).add(ticker);
|
||||
}
|
||||
|
||||
public static void tickOnce(Level level, Consumer<Level> ticker) {
|
||||
tick_once.computeIfAbsent(level, (k) -> new ArrayList<>()).add(ticker);
|
||||
}
|
||||
|
||||
public OverdriveThatMatters() {
|
||||
// Register the setup method for modloading
|
||||
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup);
|
||||
|
@ -107,6 +107,8 @@ public class Registry {
|
||||
public static final ResourceLocation MATTER_REPLICATOR = new ResourceLocation(OverdriveThatMatters.MOD_ID, "matter_replicator");
|
||||
public static final ResourceLocation MATTER_BOTTLER = new ResourceLocation(OverdriveThatMatters.MOD_ID, "matter_bottler");
|
||||
public static final ResourceLocation DRIVE_VIEWER = new ResourceLocation(OverdriveThatMatters.MOD_ID, "drive_viewer");
|
||||
public static final ResourceLocation DRIVE_RACK = new ResourceLocation(OverdriveThatMatters.MOD_ID, "drive_rack");
|
||||
public static final ResourceLocation ITEM_MONITOR = new ResourceLocation(OverdriveThatMatters.MOD_ID, "item_monitor");
|
||||
|
||||
public static final ResourceLocation BLACK_HOLE = new ResourceLocation(OverdriveThatMatters.MOD_ID, "black_hole");
|
||||
public static final ResourceLocation CARGO_CRATE = new ResourceLocation(OverdriveThatMatters.MOD_ID, "cargo_crate");
|
||||
@ -238,6 +240,8 @@ public class Registry {
|
||||
public static final BlockMatterBottler MATTER_BOTTLER = new BlockMatterBottler();
|
||||
public static final BlockDriveViewer DRIVE_VIEWER = new BlockDriveViewer();
|
||||
public static final BlockCargoCrate CARGO_CRATE = new BlockCargoCrate();
|
||||
public static final BlockDriveRack DRIVE_RACK = new BlockDriveRack();
|
||||
public static final BlockItemMonitor ITEM_MONITOR = new BlockItemMonitor();
|
||||
|
||||
public static final BlockBlackHole BLACK_HOLE = new BlockBlackHole();
|
||||
|
||||
@ -313,6 +317,8 @@ public class Registry {
|
||||
DRIVE_VIEWER.setRegistryName(Names.DRIVE_VIEWER);
|
||||
BLACK_HOLE.setRegistryName(Names.BLACK_HOLE);
|
||||
CARGO_CRATE.setRegistryName(Names.CARGO_CRATE);
|
||||
DRIVE_RACK.setRegistryName(Names.DRIVE_RACK);
|
||||
ITEM_MONITOR.setRegistryName(Names.ITEM_MONITOR);
|
||||
|
||||
TRITANIUM_BLOCK.setRegistryName(Names.TRITANIUM_BLOCK);
|
||||
TRITANIUM_STRIPED_BLOCK.setRegistryName(Names.TRITANIUM_STRIPED_BLOCK);
|
||||
@ -340,6 +346,8 @@ public class Registry {
|
||||
event.getRegistry().register(TRITANIUM_ORE);
|
||||
event.getRegistry().register(DEEPSLATE_TRITANIUM_ORE);
|
||||
event.getRegistry().register(TRITANIUM_RAW_BLOCK);
|
||||
event.getRegistry().register(DRIVE_RACK);
|
||||
event.getRegistry().register(ITEM_MONITOR);
|
||||
|
||||
for (var crate : CRATES) {
|
||||
event.getRegistry().register(crate);
|
||||
@ -365,6 +373,8 @@ public class Registry {
|
||||
public static final Item TRITANIUM_ORE = new BlockItem(Blocks.TRITANIUM_ORE, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
|
||||
public static final Item DEEPSLATE_TRITANIUM_ORE = new BlockItem(Blocks.DEEPSLATE_TRITANIUM_ORE, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
|
||||
public static final Item TRITANIUM_RAW_BLOCK = new BlockItem(Blocks.TRITANIUM_RAW_BLOCK, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
|
||||
public static final Item DRIVE_RACK = new BlockItem(Blocks.DRIVE_RACK, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
|
||||
public static final Item ITEM_MONITOR = new BlockItem(Blocks.ITEM_MONITOR, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
|
||||
|
||||
public static final Item TRITANIUM_ORE_CLUMP = new Item(new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
|
||||
public static final Item TRITANIUM_INGOT = new Item(new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
|
||||
@ -436,6 +446,8 @@ public class Registry {
|
||||
DRIVE_VIEWER.setRegistryName(Names.DRIVE_VIEWER);
|
||||
BLACK_HOLE.setRegistryName(Names.BLACK_HOLE);
|
||||
CARGO_CRATE.setRegistryName(Names.CARGO_CRATE);
|
||||
DRIVE_RACK.setRegistryName(Names.DRIVE_RACK);
|
||||
ITEM_MONITOR.setRegistryName(Names.ITEM_MONITOR);
|
||||
|
||||
TRITANIUM_ORE.setRegistryName(Names.TRITANIUM_ORE);
|
||||
DEEPSLATE_TRITANIUM_ORE.setRegistryName(Names.DEEPSLATE_TRITANIUM_ORE);
|
||||
@ -500,6 +512,8 @@ public class Registry {
|
||||
event.getRegistry().register(DRIVE_VIEWER);
|
||||
event.getRegistry().register(BLACK_HOLE);
|
||||
event.getRegistry().register(CARGO_CRATE);
|
||||
event.getRegistry().register(DRIVE_RACK);
|
||||
event.getRegistry().register(ITEM_MONITOR);
|
||||
|
||||
event.getRegistry().register(TRITANIUM_ORE);
|
||||
event.getRegistry().register(DEEPSLATE_TRITANIUM_ORE);
|
||||
@ -571,6 +585,8 @@ public class Registry {
|
||||
public static final BlockEntityType<BlockEntityDriveViewer> DRIVE_VIEWER = BlockEntityType.Builder.of(BlockEntityDriveViewer::new, Blocks.DRIVE_VIEWER).build(null);
|
||||
public static final BlockEntityType<BlockEntityBlackHole> BLACK_HOLE = BlockEntityType.Builder.of(BlockEntityBlackHole::new, Blocks.BLACK_HOLE).build(null);
|
||||
public static final BlockEntityType<BlockEntityCargoCrate> CARGO_CRATE = BlockEntityType.Builder.of(BlockEntityCargoCrate::new, Blocks.CARGO_CRATE).build(null);
|
||||
public static final BlockEntityType<BlockEntityDriveRack> DRIVE_RACK = BlockEntityType.Builder.of(BlockEntityDriveRack::new, Blocks.DRIVE_RACK).build(null);
|
||||
public static final BlockEntityType<BlockEntityItemMonitor> ITEM_MONITOR = BlockEntityType.Builder.of(BlockEntityItemMonitor::new, Blocks.ITEM_MONITOR).build(null);
|
||||
|
||||
static {
|
||||
ANDROID_STATION.setRegistryName(Names.ANDROID_STATION);
|
||||
@ -586,6 +602,8 @@ public class Registry {
|
||||
DRIVE_VIEWER.setRegistryName(Names.DRIVE_VIEWER);
|
||||
BLACK_HOLE.setRegistryName(Names.BLACK_HOLE);
|
||||
CARGO_CRATE.setRegistryName(Names.CARGO_CRATE);
|
||||
DRIVE_RACK.setRegistryName(Names.DRIVE_RACK);
|
||||
ITEM_MONITOR.setRegistryName(Names.ITEM_MONITOR);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
@ -603,6 +621,8 @@ public class Registry {
|
||||
event.getRegistry().register(DRIVE_VIEWER);
|
||||
event.getRegistry().register(BLACK_HOLE);
|
||||
event.getRegistry().register(CARGO_CRATE);
|
||||
event.getRegistry().register(DRIVE_RACK);
|
||||
event.getRegistry().register(ITEM_MONITOR);
|
||||
|
||||
// OverdriveThatMatters.LOGGER.info("Registered block entities");
|
||||
}
|
||||
@ -846,6 +866,8 @@ public class Registry {
|
||||
public static final MenuType<MatterBottlerMenu> MATTER_BOTTLER = new MenuType<>(MatterBottlerMenu::new);
|
||||
public static final MenuType<DriveViewerMenu> DRIVE_VIEWER = new MenuType<>(DriveViewerMenu::new);
|
||||
public static final MenuType<CargoCrateMenu> CARGO_CRATE = new MenuType<>(CargoCrateMenu::new);
|
||||
public static final MenuType<DriveRackMenu> DRIVE_RACK = new MenuType<>(DriveRackMenu::new);
|
||||
public static final MenuType<ItemMonitorMenu> ITEM_MONITOR = new MenuType<>(ItemMonitorMenu::new);
|
||||
|
||||
static {
|
||||
ANDROID_STATION.setRegistryName(Names.ANDROID_STATION);
|
||||
@ -859,6 +881,8 @@ public class Registry {
|
||||
MATTER_BOTTLER.setRegistryName(Names.MATTER_BOTTLER);
|
||||
DRIVE_VIEWER.setRegistryName(Names.DRIVE_VIEWER);
|
||||
CARGO_CRATE.setRegistryName(Names.CARGO_CRATE);
|
||||
DRIVE_RACK.setRegistryName(Names.DRIVE_RACK);
|
||||
ITEM_MONITOR.setRegistryName(Names.ITEM_MONITOR);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
@ -874,6 +898,8 @@ public class Registry {
|
||||
event.getRegistry().register(MATTER_BOTTLER);
|
||||
event.getRegistry().register(DRIVE_VIEWER);
|
||||
event.getRegistry().register(CARGO_CRATE);
|
||||
event.getRegistry().register(DRIVE_RACK);
|
||||
event.getRegistry().register(ITEM_MONITOR);
|
||||
|
||||
// OverdriveThatMatters.LOGGER.info("Registered menus");
|
||||
}
|
||||
@ -891,6 +917,8 @@ public class Registry {
|
||||
MenuScreens.register(MATTER_BOTTLER, MatterBottlerScreen::new);
|
||||
MenuScreens.register(DRIVE_VIEWER, DriveViewerScreen::new);
|
||||
MenuScreens.register(CARGO_CRATE, CargoCrateScreen::new);
|
||||
MenuScreens.register(DRIVE_RACK, DriveRackScreen::new);
|
||||
MenuScreens.register(ITEM_MONITOR, ItemMonitorScreen::new);
|
||||
|
||||
// OverdriveThatMatters.LOGGER.info("Registered screens");
|
||||
}
|
||||
|
@ -0,0 +1,17 @@
|
||||
package ru.dbotthepony.mc.otm.block;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.block.EntityBlock;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import ru.dbotthepony.mc.otm.block.entity.BlockEntityDriveRack;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class BlockDriveRack extends BlockMatteryRotatable implements EntityBlock {
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
|
||||
return new BlockEntityDriveRack(blockPos, blockState);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package ru.dbotthepony.mc.otm.block;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.block.EntityBlock;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import ru.dbotthepony.mc.otm.block.entity.BlockEntityItemMonitor;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class BlockItemMonitor extends BlockMatteryRotatable implements EntityBlock {
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
|
||||
return new BlockEntityItemMonitor(blockPos, blockState);
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.TranslatableComponent;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.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.OverdriveThatMatters;
|
||||
import ru.dbotthepony.mc.otm.Registry;
|
||||
import ru.dbotthepony.mc.otm.capability.AbstractStorageGridCell;
|
||||
import ru.dbotthepony.mc.otm.capability.IStorageGridCell;
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage;
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer;
|
||||
import ru.dbotthepony.mc.otm.menu.DriveRackMenu;
|
||||
import ru.dbotthepony.mc.otm.storage.IStorageIdentity;
|
||||
import ru.dbotthepony.mc.otm.storage.ItemStackObject;
|
||||
import ru.dbotthepony.mc.otm.storage.StorageItemView;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public class BlockEntityDriveRack extends BlockEntityMatteryPowered {
|
||||
public BlockEntityDriveRack(BlockPos p_155229_, BlockState p_155230_) {
|
||||
super(Registry.BlockEntities.DRIVE_RACK, p_155229_, p_155230_);
|
||||
energy = new MatteryMachineEnergyStorage(this, MatteryMachineEnergyStorage.MachineType.WORKER, new BigDecimal(80_000));
|
||||
}
|
||||
|
||||
public final MatteryContainer drives = new MatteryContainer(this::setChanged, 4) {
|
||||
@Override
|
||||
public void setChanged(int slot, ItemStack new_state, ItemStack old_state) {
|
||||
super.setChanged(slot, new_state, old_state);
|
||||
|
||||
/*old_state.getCapability(MatteryCapability.DRIVE).ifPresent((drive) -> {
|
||||
drive.removeListenerAuto(cell.computeIfAbsent(ItemStackObject.class, StorageItemView::new));
|
||||
});
|
||||
|
||||
new_state.getCapability(MatteryCapability.DRIVE).ifPresent((drive) -> {
|
||||
drive.addListenerAuto(cell.computeIfAbsent(ItemStackObject.class, StorageItemView::new));
|
||||
});*/
|
||||
|
||||
old_state.getCapability(MatteryCapability.DRIVE).ifPresent(cell::removeStorageComponent);
|
||||
new_state.getCapability(MatteryCapability.DRIVE).ifPresent(cell::addStorageComponent);
|
||||
}
|
||||
};
|
||||
|
||||
public final AbstractStorageGridCell cell = new AbstractStorageGridCell();
|
||||
|
||||
@Override
|
||||
public void load(CompoundTag nbt) {
|
||||
super.load(nbt);
|
||||
drives.deserializeNBT(nbt.getCompound("drives"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag save(CompoundTag nbt) {
|
||||
nbt.put("drives", drives.serializeNBT());
|
||||
return super.save(nbt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLevel(Level p_155231_) {
|
||||
super.setLevel(p_155231_);
|
||||
|
||||
cell.scheduleDiscoverNeighbours(p_155231_, getBlockPos());
|
||||
}
|
||||
|
||||
private static final TranslatableComponent NAME = new TranslatableComponent("block.overdrive_that_matters.drive_rack");
|
||||
|
||||
@Override
|
||||
protected Component getDefaultDisplayName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply) {
|
||||
return new DriveRackMenu(containerID, inventory, this);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
|
||||
if (cap == MatteryCapability.STORAGE_CELL) {
|
||||
return cell.get().cast();
|
||||
}
|
||||
|
||||
return super.getCapability(cap, side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCaps() {
|
||||
super.invalidateCaps();
|
||||
cell.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reviveCaps() {
|
||||
super.reviveCaps();
|
||||
cell.revive();
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.TranslatableComponent;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.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.AbstractStorageGridCell;
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage;
|
||||
import ru.dbotthepony.mc.otm.menu.ItemMonitorMenu;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class BlockEntityItemMonitor extends BlockEntityMatteryPowered {
|
||||
public BlockEntityItemMonitor(BlockPos p_155229_, BlockState p_155230_) {
|
||||
super(Registry.BlockEntities.ITEM_MONITOR, p_155229_, p_155230_);
|
||||
energy = new MatteryMachineEnergyStorage(this, MatteryMachineEnergyStorage.MachineType.WORKER, new BigDecimal(80_000));
|
||||
}
|
||||
|
||||
public final AbstractStorageGridCell cell = new AbstractStorageGridCell();
|
||||
|
||||
private static final TranslatableComponent NAME = new TranslatableComponent("block.overdrive_that_matters.item_storage_viewer");
|
||||
|
||||
@Override
|
||||
protected Component getDefaultDisplayName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply) {
|
||||
return new ItemMonitorMenu(containerID, inventory, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLevel(Level p_155231_) {
|
||||
super.setLevel(p_155231_);
|
||||
|
||||
cell.scheduleDiscoverNeighbours(p_155231_, getBlockPos());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
|
||||
if (cap == MatteryCapability.STORAGE_CELL) {
|
||||
return cell.get().cast();
|
||||
}
|
||||
|
||||
return super.getCapability(cap, side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCaps() {
|
||||
super.invalidateCaps();
|
||||
cell.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reviveCaps() {
|
||||
super.reviveCaps();
|
||||
cell.revive();
|
||||
}
|
||||
}
|
@ -72,7 +72,7 @@ public class BlockEntityMatterReplicator extends BlockEntityMatteryWorker implem
|
||||
@Nonnull
|
||||
@Override
|
||||
protected MachineJobStatus onJobFinish(MachineJob job) {
|
||||
if (!regular_slots.addItem(job.stack()).isEmpty()) {
|
||||
if (!regular_slots.fullyAddItem(job.stack())) {
|
||||
return new MachineJobStatus(false, 20);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,101 @@
|
||||
package ru.dbotthepony.mc.otm.capability;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
|
||||
import ru.dbotthepony.mc.otm.storage.IStorageIdentity;
|
||||
import ru.dbotthepony.mc.otm.storage.IStorageObject;
|
||||
import ru.dbotthepony.mc.otm.storage.StorageGrid;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public class AbstractStorageGridCell implements IStorageGridCell {
|
||||
private LazyOptional<IStorageGridCell> resolver = LazyOptional.of(() -> this);
|
||||
private boolean valid = true;
|
||||
protected final ArrayList<IStorageIdentity<?>> components = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public List<? extends IStorageIdentity<?>> getComponents() {
|
||||
return Collections.unmodifiableList(components);
|
||||
}
|
||||
|
||||
public <T extends IStorageObject, U extends IStorageIdentity<T>> U computeIfAbsent(Class<T> identity, Supplier<U> provider) {
|
||||
for (var component : components) {
|
||||
if (component.storageIdentity() == identity) {
|
||||
return (U) component;
|
||||
}
|
||||
}
|
||||
|
||||
var factory = provider.get();
|
||||
addStorageComponent(factory);
|
||||
return factory;
|
||||
}
|
||||
|
||||
public void addStorageComponent(IStorageIdentity<?> component) {
|
||||
for (var component1 : components) {
|
||||
if (component == component1 || component1.storageIdentity() == component.storageIdentity()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
detachStorage();
|
||||
components.add(component);
|
||||
attachStorage();
|
||||
}
|
||||
|
||||
public void removeStorageComponent(IStorageIdentity<?> component) {
|
||||
for (var component1 : components) {
|
||||
if (component == component1 || component1.storageIdentity() == component.storageIdentity()) {
|
||||
detachStorage();
|
||||
components.remove(component1);
|
||||
attachStorage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
if (!valid)
|
||||
return;
|
||||
|
||||
valid = false;
|
||||
resolver.invalidate();
|
||||
}
|
||||
|
||||
public void revive() {
|
||||
if (valid)
|
||||
return;
|
||||
|
||||
valid = true;
|
||||
resolver = LazyOptional.of(() -> this);
|
||||
}
|
||||
|
||||
public LazyOptional<IStorageGridCell> get() {
|
||||
return valid ? resolver : LazyOptional.empty();
|
||||
}
|
||||
|
||||
protected StorageGrid storage_grid;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public StorageGrid getStorageGrid() {
|
||||
return storage_grid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStorageGrid(StorageGrid grid) {
|
||||
OverdriveThatMatters.LOGGER.info("Set grid {} {}", this, grid);
|
||||
storage_grid = grid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidStorageCell() {
|
||||
return valid;
|
||||
}
|
||||
}
|
@ -0,0 +1,126 @@
|
||||
package ru.dbotthepony.mc.otm.capability;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
|
||||
import ru.dbotthepony.mc.otm.storage.IStorageIdentity;
|
||||
import ru.dbotthepony.mc.otm.storage.StorageGrid;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.util.List;
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public interface IStorageGridCell {
|
||||
/**
|
||||
* Return all providers that this cell can store. Or nothing, if it is not a storage.
|
||||
*
|
||||
* If you don't know what you are going to store, return empty list, then, when you make up your
|
||||
* mind by either player tweaking settings or something,
|
||||
* call helper method detachStorage();
|
||||
* add whatever going to end up in getComponents();
|
||||
* add helper method attachStorage();
|
||||
*
|
||||
* Failing to do it in this order will cause IllegalStateException
|
||||
*
|
||||
* @return a list of all providers, inheriting IStorageIdentity, or an empty list
|
||||
*/
|
||||
List<? extends IStorageIdentity<?>> getComponents();
|
||||
|
||||
default List<? extends IStorageIdentity<?>> getComponentsForView() {
|
||||
return getComponents();
|
||||
}
|
||||
|
||||
default List<? extends IStorageIdentity<?>> getComponentsForInterfaces() {
|
||||
return getComponents();
|
||||
}
|
||||
|
||||
default List<? extends IStorageIdentity<?>> getComponentsForExporters() {
|
||||
return getComponents();
|
||||
}
|
||||
|
||||
default void detachStorage() {
|
||||
var grid = getStorageGrid();
|
||||
|
||||
if (grid != null) {
|
||||
grid.detach(this);
|
||||
}
|
||||
}
|
||||
|
||||
default void attachStorage() {
|
||||
var grid = getStorageGrid();
|
||||
|
||||
if (grid != null) {
|
||||
grid.attach(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
StorageGrid getStorageGrid();
|
||||
void setStorageGrid(@Nullable StorageGrid grid);
|
||||
boolean isValidStorageCell();
|
||||
|
||||
default void scheduleDiscoverNeighbours(Level level, BlockPos pos) {
|
||||
if (level instanceof ServerLevel)
|
||||
StorageGrid.scheduleDiscoverNeighbours(this, level, pos);
|
||||
}
|
||||
|
||||
default boolean connectOrCreateStorageGrid(Level level, BlockPos pos) {
|
||||
return connectOrCreateStorageGrid(level, pos, false);
|
||||
}
|
||||
|
||||
default void onNeighbourStorageCell(Level level, BlockPos pos, Direction direction, IStorageGridCell cell) {
|
||||
|
||||
}
|
||||
|
||||
default boolean connectOrCreateStorageGrid(Level level, BlockPos pos, boolean force) {
|
||||
OverdriveThatMatters.LOGGER.info("Discover {}", this);
|
||||
if (getStorageGrid() != null && !force)
|
||||
return true;
|
||||
|
||||
boolean full_discovery = true;
|
||||
|
||||
for (Direction direction : Direction.values()) {
|
||||
BlockPos offset = pos.offset(direction.getNormal());
|
||||
|
||||
// level.getBlockEntity can drink big cup of deadlocks
|
||||
LevelChunk get_chunk = level.getChunkSource().getChunkNow(SectionPos.blockToSectionCoord(offset.getX()), SectionPos.blockToSectionCoord(offset.getZ()));
|
||||
|
||||
if (get_chunk == null) {
|
||||
full_discovery = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
BlockEntity get_entity = get_chunk.getBlockEntity(offset);
|
||||
|
||||
if (get_entity != null && get_entity.getCapability(MatteryCapability.STORAGE_CELL, direction.getOpposite()).isPresent()) {
|
||||
var cell = get_entity.getCapability(MatteryCapability.STORAGE_CELL, direction.getOpposite()).resolve().get();
|
||||
var grid = cell.getStorageGrid();
|
||||
|
||||
if (grid != null && grid != getStorageGrid()) {
|
||||
if (getStorageGrid() == null) {
|
||||
grid.add(this);
|
||||
} else {
|
||||
grid.merge(getStorageGrid());
|
||||
}
|
||||
}
|
||||
|
||||
if (cell.isValidStorageCell())
|
||||
onNeighbourStorageCell(level, pos, direction, cell);
|
||||
}
|
||||
}
|
||||
|
||||
if (getStorageGrid() == null) {
|
||||
new StorageGrid().add(this);
|
||||
}
|
||||
|
||||
return full_discovery;
|
||||
}
|
||||
}
|
@ -32,6 +32,9 @@ public class MatteryCapability {
|
||||
@CapabilityInject(IMatteryDrive.class)
|
||||
public static Capability<IMatteryDrive> DRIVE = null;
|
||||
|
||||
@CapabilityInject(IStorageGridCell.class)
|
||||
public static Capability<IStorageGridCell> STORAGE_CELL = null;
|
||||
|
||||
public static void register() {
|
||||
CapabilityManager.INSTANCE.register(IAndroidCapability.class);
|
||||
CapabilityManager.INSTANCE.register(IMatteryEnergyStorage.class);
|
||||
@ -40,6 +43,7 @@ public class MatteryCapability {
|
||||
CapabilityManager.INSTANCE.register(IMatterGridCell.class);
|
||||
CapabilityManager.INSTANCE.register(IMatterTaskProvider.class);
|
||||
CapabilityManager.INSTANCE.register(IMatteryDrive.class);
|
||||
CapabilityManager.INSTANCE.register(IStorageGridCell.class);
|
||||
}
|
||||
|
||||
public static final MathContext ROUND_RULES = new MathContext(32, RoundingMode.HALF_DOWN);
|
||||
|
@ -6,6 +6,7 @@ import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.common.util.INBTSerializable;
|
||||
import ru.dbotthepony.mc.otm.menu.DriveViewerMenu;
|
||||
import ru.dbotthepony.mc.otm.storage.*;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
@ -16,7 +17,7 @@ import java.util.function.Predicate;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
public interface IMatteryDrive {
|
||||
public interface IMatteryDrive extends IStorageComponent<ItemStackObject> {
|
||||
record StoredStack(ItemStack stack, UUID id) {};
|
||||
|
||||
List<StoredStack> getItems();
|
||||
@ -39,9 +40,6 @@ public interface IMatteryDrive {
|
||||
|
||||
ItemStack getItem(UUID id);
|
||||
|
||||
void addListener(IItemViewListener listener);
|
||||
void removeListener(IItemViewListener listener);
|
||||
|
||||
int getStoredCount();
|
||||
int getCapacity();
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package ru.dbotthepony.mc.otm.capability.drive;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
@ -9,11 +10,19 @@ import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraftforge.registries.RegistryManager;
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
|
||||
import ru.dbotthepony.mc.otm.storage.IStorageListener;
|
||||
import ru.dbotthepony.mc.otm.storage.IStorageTuple;
|
||||
import ru.dbotthepony.mc.otm.storage.ItemStackObject;
|
||||
import ru.dbotthepony.mc.otm.storage.StorageTuple;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public class MatteryDrive implements IMatteryDrive {
|
||||
protected final HashMap<Item, List<StoredStack>> items = new HashMap<>();
|
||||
protected final HashMap<UUID, StoredStack> items_by_id = new HashMap<>();
|
||||
@ -115,33 +124,6 @@ public class MatteryDrive implements IMatteryDrive {
|
||||
return build_list;
|
||||
}
|
||||
|
||||
protected final ArrayList<IItemViewListener> listeners = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void addListener(IItemViewListener listener) {
|
||||
if (listeners.contains(listener))
|
||||
return;
|
||||
|
||||
listeners.add(listener);
|
||||
|
||||
for (var list : this.items.values()) {
|
||||
for (var state : list) {
|
||||
listener.addViewItem(state.stack(), state.id());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(IItemViewListener listener) {
|
||||
if (listeners.remove(listener)) {
|
||||
for (var list : this.items.values()) {
|
||||
for (var state : list) {
|
||||
listener.removeViewItem(state.id());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack getItem(UUID id) {
|
||||
@ -165,8 +147,8 @@ public class MatteryDrive implements IMatteryDrive {
|
||||
state.stack().grow(max_insert);
|
||||
stored += max_insert;
|
||||
|
||||
for (var listener : listeners) {
|
||||
listener.changeViewItem(state.id(), state.stack().getCount());
|
||||
for (var listener : listeners2) {
|
||||
listener.changeObject(state.id(), new BigDecimal(state.stack().getCount()));
|
||||
}
|
||||
|
||||
markDirty();
|
||||
@ -192,8 +174,8 @@ public class MatteryDrive implements IMatteryDrive {
|
||||
listing.add(state);
|
||||
items_by_id.put(state.id(), state);
|
||||
|
||||
for (var listener : listeners) {
|
||||
listener.addViewItem(state.stack(), state.id());
|
||||
for (var listener : listeners2) {
|
||||
listener.addObject(new ItemStackObject(state.stack()), state.id(), this);
|
||||
}
|
||||
|
||||
markDirty();
|
||||
@ -204,6 +186,12 @@ public class MatteryDrive implements IMatteryDrive {
|
||||
return copy_item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStackObject insertObject(ItemStackObject obj, boolean simulate) {
|
||||
var get = insertItem(obj.stack(), simulate);
|
||||
return get.isEmpty() ? ItemStackObject.EMPTY : new ItemStackObject(get);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack extractItem(UUID id, int amount, boolean obey_stack_size, boolean simulate) {
|
||||
@ -229,8 +217,8 @@ public class MatteryDrive implements IMatteryDrive {
|
||||
listing.remove(get);
|
||||
different_stacks--;
|
||||
|
||||
for (var listener : listeners) {
|
||||
listener.removeViewItem(get.id());
|
||||
for (var listener : listeners2) {
|
||||
listener.removeObject(get.id());
|
||||
}
|
||||
|
||||
if (listing.size() == 0) {
|
||||
@ -242,8 +230,8 @@ public class MatteryDrive implements IMatteryDrive {
|
||||
get.stack().shrink(extract);
|
||||
|
||||
if (get.stack().getCount() != 0) {
|
||||
for (var listener : listeners) {
|
||||
listener.changeViewItem(get.id(), get.stack().getCount());
|
||||
for (var listener : listeners2) {
|
||||
listener.changeObject(get.id(), new BigDecimal(get.stack().getCount()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,4 +322,51 @@ public class MatteryDrive implements IMatteryDrive {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<ItemStackObject> storageIdentity() {
|
||||
return ItemStackObject.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStackObject getStoredObject(UUID id) {
|
||||
var get = getItem(id);
|
||||
return get.isEmpty() ? ItemStackObject.EMPTY : new ItemStackObject(get);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStackObject extractObject(UUID id, BigDecimal amount, boolean simulate) {
|
||||
var get = extractItem(id, amount.intValue(), simulate);
|
||||
return get.isEmpty() ? ItemStackObject.EMPTY : new ItemStackObject(get);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IStorageTuple<ItemStackObject>> getStorageObjects() {
|
||||
int amount = 0;
|
||||
|
||||
for (var listing : items.values())
|
||||
amount += listing.size();
|
||||
|
||||
var list = new ArrayList<IStorageTuple<ItemStackObject>>(amount);
|
||||
|
||||
for (var listing : items.values()) {
|
||||
for (var stack : listing) {
|
||||
list.add(new StorageTuple<>(stack.id(), new ItemStackObject(stack.stack())));
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
protected final HashSet<IStorageListener<ItemStackObject>> listeners2 = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public boolean addListener(IStorageListener<ItemStackObject> listener) {
|
||||
return listeners2.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeListener(IStorageListener<ItemStackObject> listener) {
|
||||
return listeners2.remove(listener);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,33 @@
|
||||
package ru.dbotthepony.mc.otm.client.screen;
|
||||
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.FlexGridPanel;
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.SlotPanel;
|
||||
import ru.dbotthepony.mc.otm.menu.DriveRackMenu;
|
||||
import ru.dbotthepony.mc.otm.menu.slot.MatterySlot;
|
||||
import ru.dbotthepony.mc.otm.menu.widget.GaugeWidget;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class DriveRackScreen extends MatteryScreen<DriveRackMenu> implements MatteryScreen.IMatteryScreenGaugeGetter, MatteryScreen.IMatteryScreenBatteryGetter, MatteryScreen.IMatteryScreenGridBased {
|
||||
public DriveRackScreen(DriveRackMenu menu, Inventory inventory, Component title) {
|
||||
super(menu, inventory, title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GaugeWidget> getGauges() {
|
||||
return List.of(menu.battery_widget);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MatterySlot> getBatterySlots() {
|
||||
return List.of(menu.battery_slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createGridPanels(FlexGridPanel grid) {
|
||||
for (var slot : menu.drives)
|
||||
new SlotPanel<>(this, grid, slot);
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ import net.minecraft.world.inventory.ClickType;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import ru.dbotthepony.mc.otm.item.ItemPortableCondensationDrive;
|
||||
import ru.dbotthepony.mc.otm.menu.DriveViewerMenu;
|
||||
import ru.dbotthepony.mc.otm.menu.data.InteractPacket;
|
||||
import ru.dbotthepony.mc.otm.menu.slot.MatterySlot;
|
||||
import ru.dbotthepony.mc.otm.menu.widget.GaugeWidget;
|
||||
import ru.dbotthepony.mc.otm.network.MatteryNetworking;
|
||||
@ -116,12 +117,8 @@ public class DriveViewerScreen extends MatteryScreen<DriveViewerMenu> implements
|
||||
@Override
|
||||
protected boolean mouseClickedInner(double mouse_x, double mouse_y, int mouse_click_type) {
|
||||
int findex = index + scroll_bar.getScroll(GRID_WIDTH);
|
||||
var list = menu.view.getItems();
|
||||
var action = mouse_click_type == InputConstants.MOUSE_BUTTON_LEFT ? ClickAction.PRIMARY : ClickAction.SECONDARY;
|
||||
menu.view.mouseClick(findex, mouse_click_type);
|
||||
|
||||
var type = mouse_click_type == InputConstants.MOUSE_BUTTON_MIDDLE ? ClickType.CLONE : hasShiftDown() ? ClickType.QUICK_MOVE : ClickType.PICKUP;
|
||||
|
||||
MatteryNetworking.send(new DriveViewerMenu.InteractPacket(menu.containerId, findex >= list.size() ? -1 : list.get(findex).id(), type, action));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@ -163,7 +160,7 @@ public class DriveViewerScreen extends MatteryScreen<DriveViewerMenu> implements
|
||||
@Override
|
||||
protected boolean mouseReleasedInner(double mouse_x, double mouse_y, int flag) {
|
||||
if (clicking)
|
||||
MatteryNetworking.send(new DriveViewerMenu.FilterSetPacket(menu.containerId, index, menu.getCarried()));
|
||||
MatteryNetworking.send(null, new DriveViewerMenu.FilterSetPacket(menu.containerId, index, menu.getCarried()));
|
||||
|
||||
clicking = false;
|
||||
|
||||
@ -197,7 +194,7 @@ public class DriveViewerScreen extends MatteryScreen<DriveViewerMenu> implements
|
||||
var filter = menu.getFilter();
|
||||
|
||||
if (filter != null) {
|
||||
MatteryNetworking.send(new DriveViewerMenu.FilterSwitchPacket(menu.containerId, DriveViewerMenu.FilterSwitch.MATCH_NBT, !filter.match_nbt));
|
||||
MatteryNetworking.send(null, new DriveViewerMenu.FilterSwitchPacket(menu.containerId, DriveViewerMenu.FilterSwitch.MATCH_NBT, !filter.match_nbt));
|
||||
disableFor(20);
|
||||
}
|
||||
}
|
||||
@ -225,7 +222,7 @@ public class DriveViewerScreen extends MatteryScreen<DriveViewerMenu> implements
|
||||
var filter = menu.getFilter();
|
||||
|
||||
if (filter != null) {
|
||||
MatteryNetworking.send(new DriveViewerMenu.FilterSwitchPacket(menu.containerId, DriveViewerMenu.FilterSwitch.MATCH_TAG, !filter.match_tag));
|
||||
MatteryNetworking.send(null, new DriveViewerMenu.FilterSwitchPacket(menu.containerId, DriveViewerMenu.FilterSwitch.MATCH_TAG, !filter.match_tag));
|
||||
disableFor(20);
|
||||
}
|
||||
}
|
||||
@ -253,7 +250,7 @@ public class DriveViewerScreen extends MatteryScreen<DriveViewerMenu> implements
|
||||
var filter = menu.getFilter();
|
||||
|
||||
if (filter != null) {
|
||||
MatteryNetworking.send(new DriveViewerMenu.FilterSwitchPacket(menu.containerId, DriveViewerMenu.FilterSwitch.BLACKLIST, !filter.blacklist));
|
||||
MatteryNetworking.send(null, new DriveViewerMenu.FilterSwitchPacket(menu.containerId, DriveViewerMenu.FilterSwitch.BLACKLIST, !filter.blacklist));
|
||||
disableFor(20);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,97 @@
|
||||
package ru.dbotthepony.mc.otm.client.screen;
|
||||
|
||||
import com.mojang.blaze3d.platform.InputConstants;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.TranslatableComponent;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.inventory.ClickAction;
|
||||
import net.minecraft.world.inventory.ClickType;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.*;
|
||||
import ru.dbotthepony.mc.otm.item.ItemPortableCondensationDrive;
|
||||
import ru.dbotthepony.mc.otm.menu.DriveViewerMenu;
|
||||
import ru.dbotthepony.mc.otm.menu.ItemMonitorMenu;
|
||||
import ru.dbotthepony.mc.otm.menu.data.InteractPacket;
|
||||
import ru.dbotthepony.mc.otm.menu.slot.MatterySlot;
|
||||
import ru.dbotthepony.mc.otm.menu.widget.GaugeWidget;
|
||||
import ru.dbotthepony.mc.otm.network.MatteryNetworking;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ItemMonitorScreen extends MatteryScreen<ItemMonitorMenu> implements MatteryScreen.IMatteryScreenGaugeGetter, MatteryScreen.IMatteryScreenBatteryGetter {
|
||||
public static final int FRAME_WIDTH = 210;
|
||||
public static final int FRAME_HEIGHT = 110;
|
||||
|
||||
public static final int GRID_WIDTH = 9;
|
||||
public static final int GRID_HEIGHT = 5;
|
||||
|
||||
public ItemMonitorScreen(ItemMonitorMenu menu, Inventory inventory, Component title) {
|
||||
super(menu, inventory, title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GaugeWidget> getGauges() {
|
||||
return List.of(menu.battery_widget);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MatterySlot> getBatterySlots() {
|
||||
return List.of(menu.battery_slot);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected FramePanel makeMainFrame() {
|
||||
var frame = new FramePanel(this, null, 0, 0, FRAME_WIDTH, FRAME_HEIGHT, getTitle());
|
||||
|
||||
autoAttachToFrame(frame);
|
||||
|
||||
var grid = new GridPanel(this, frame, 0, 0, 0, 0, GRID_WIDTH, GRID_HEIGHT);
|
||||
grid.setDock(Dock.FILL);
|
||||
grid.setDockMargin(2, 2, 2, 2);
|
||||
|
||||
var scroll_bar = new ScrollBarPanel(this, frame, 0, 0, 0);
|
||||
scroll_bar.setDock(Dock.RIGHT);
|
||||
scroll_bar.setupRowMultiplier(() -> {
|
||||
return menu.view.getItems().size() / GRID_WIDTH;
|
||||
});
|
||||
|
||||
for (int i = 0; i < GRID_WIDTH * GRID_HEIGHT; i++) {
|
||||
final int index = i;
|
||||
|
||||
new AbstractSlotPanel(this, grid, 0, 0) {
|
||||
@Nonnull
|
||||
@Override
|
||||
protected ItemStack getItemStack() {
|
||||
int findex = index + scroll_bar.getScroll(menu.view.getItems().size() / GRID_WIDTH);
|
||||
|
||||
var list = menu.view.getItems();
|
||||
|
||||
if (findex >= list.size()) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
return list.get(findex).stack();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean mouseScrolledInner(double mouse_x, double mouse_y, double scroll) {
|
||||
return scroll_bar.mouseScrolledInner(mouse_x, mouse_y, scroll);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean mouseClickedInner(double mouse_x, double mouse_y, int mouse_click_type) {
|
||||
int findex = index + scroll_bar.getScroll(GRID_WIDTH);
|
||||
menu.view.mouseClick(findex, mouse_click_type);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
}
|
@ -1,20 +1,40 @@
|
||||
package ru.dbotthepony.mc.otm.container;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.world.SimpleContainer;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class MatteryContainer extends SimpleContainer {
|
||||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public class MatteryContainer implements Container, Iterable<ItemStack> {
|
||||
protected final Runnable watcher;
|
||||
protected int ignore_change_notifications = 0;
|
||||
protected final int size;
|
||||
protected final ItemStack[] slots;
|
||||
protected final ItemStack[] tracked_slots;
|
||||
|
||||
public MatteryContainer(Runnable watcher, int size) {
|
||||
this.size = size;
|
||||
|
||||
slots = new ItemStack[this.size];
|
||||
tracked_slots = new ItemStack[this.size];
|
||||
Arrays.fill(slots, ItemStack.EMPTY);
|
||||
Arrays.fill(tracked_slots, ItemStack.EMPTY);
|
||||
|
||||
this.watcher = watcher;
|
||||
}
|
||||
|
||||
public void startIgnore() {
|
||||
ignore_change_notifications++;
|
||||
@ -24,11 +44,6 @@ public class MatteryContainer extends SimpleContainer {
|
||||
ignore_change_notifications--;
|
||||
}
|
||||
|
||||
public MatteryContainer(Runnable watcher, int i) {
|
||||
super(i);
|
||||
this.watcher = watcher;
|
||||
}
|
||||
|
||||
public MatteryContainer of(@Nullable CompoundTag tag) {
|
||||
if (tag == null)
|
||||
return this;
|
||||
@ -55,10 +70,13 @@ public class MatteryContainer extends SimpleContainer {
|
||||
|
||||
// нам не интересен размер
|
||||
|
||||
if (tag.get("items") instanceof ListTag list)
|
||||
for (int i = 0; i < Math.min(list.size(), getContainerSize()); i++)
|
||||
if (list.get(i) instanceof CompoundTag get_tag)
|
||||
if (tag.get("items") instanceof ListTag list) {
|
||||
for (int i = 0; i < Math.min(list.size(), getContainerSize()); i++) {
|
||||
if (list.get(i) instanceof CompoundTag get_tag) {
|
||||
setItem(i, ItemStack.of(get_tag));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ignore_change_notifications--;
|
||||
setChanged();
|
||||
@ -83,11 +101,6 @@ public class MatteryContainer extends SimpleContainer {
|
||||
}
|
||||
}
|
||||
|
||||
public MatteryContainer(Runnable watcher, ItemStack... p_19152_) {
|
||||
super(p_19152_);
|
||||
this.watcher = watcher;
|
||||
}
|
||||
|
||||
public ContainerIteratorItemStack stackIterator() {
|
||||
return new ContainerIteratorItemStack(this);
|
||||
}
|
||||
@ -104,17 +117,9 @@ public class MatteryContainer extends SimpleContainer {
|
||||
capabilityIterator(cap).consume(consumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChanged() {
|
||||
if (ignore_change_notifications > 0)
|
||||
return;
|
||||
|
||||
super.setChanged();
|
||||
watcher.run();
|
||||
}
|
||||
|
||||
public void setChanged(int slot, ItemStack new_state, ItemStack old_state) {
|
||||
setChanged();
|
||||
if (ignore_change_notifications == 0)
|
||||
watcher.run();
|
||||
}
|
||||
|
||||
public CompoundTag serializeNBT() {
|
||||
@ -157,16 +162,6 @@ public class MatteryContainer extends SimpleContainer {
|
||||
return false;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface MatteryContainerInsertValidator {
|
||||
boolean apply(int slot, @Nonnull ItemStack stack);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface MatteryContainerExtractValidator {
|
||||
boolean apply(int slot, int amount, @Nonnull ItemStack stack);
|
||||
}
|
||||
|
||||
protected MatteryContainerHandler handler;
|
||||
|
||||
public IItemHandler handler(MatteryContainerInsertValidator insert_validator, MatteryContainerExtractValidator extract_validator) {
|
||||
@ -194,114 +189,165 @@ public class MatteryContainer extends SimpleContainer {
|
||||
return getMaxStackSize();
|
||||
}
|
||||
|
||||
static class MatteryContainerHandler implements IItemHandler {
|
||||
private final MatteryContainer container;
|
||||
private final MatteryContainerInsertValidator insert_validator;
|
||||
private final MatteryContainerExtractValidator extract_validator;
|
||||
public ItemStack addItem(ItemStack stack, int start, int end, boolean simulate) {
|
||||
if (stack.isEmpty() || start < 0 || end > size || start >= end)
|
||||
return ItemStack.EMPTY;
|
||||
|
||||
MatteryContainerHandler(MatteryContainer container, MatteryContainerInsertValidator insert_validator, MatteryContainerExtractValidator extract_validator) {
|
||||
this.container = container;
|
||||
this.insert_validator = insert_validator;
|
||||
this.extract_validator = extract_validator;
|
||||
}
|
||||
var copy = stack.copy();
|
||||
|
||||
MatteryContainerHandler(MatteryContainer container) {
|
||||
this(container, (slot, stack) -> true, (slot, amount, stack) -> true);
|
||||
}
|
||||
// двигаем в одинаковые слоты
|
||||
for (int slot = start; slot < end; slot++) {
|
||||
if (ItemStack.isSameItemSameTags(slots[slot], copy)) {
|
||||
var this_stack = slots[slot];
|
||||
int slot_limit = Math.min(getMaxStackSize(slot), this_stack.getMaxStackSize());
|
||||
|
||||
MatteryContainerHandler(MatteryContainer container, MatteryContainerInsertValidator insert_validator) {
|
||||
this(container, insert_validator, (slot, amount, stack) -> true);
|
||||
}
|
||||
if (this_stack.getCount() < slot_limit) {
|
||||
int new_count = Math.min(this_stack.getCount() + copy.getCount(), slot_limit);
|
||||
int diff = new_count - this_stack.getCount();
|
||||
|
||||
@Override
|
||||
public int getSlots() {
|
||||
return container.getContainerSize();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack getStackInSlot(int slot) {
|
||||
return container.getItem(slot);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate) {
|
||||
if (!insert_validator.apply(slot, stack))
|
||||
return stack;
|
||||
|
||||
ItemStack self_stack = container.getItem(slot);
|
||||
|
||||
if (self_stack.isEmpty()) {
|
||||
if (!simulate) {
|
||||
var copy = stack.copy();
|
||||
container.setChanged(slot, copy, ItemStack.EMPTY);
|
||||
container.setItem(slot, copy);
|
||||
}
|
||||
|
||||
return ItemStack.EMPTY;
|
||||
} else if (self_stack.isStackable() && self_stack.getMaxStackSize() > self_stack.getCount() && ItemStack.isSameItemSameTags(self_stack, stack)) {
|
||||
int new_count = Math.min(self_stack.getMaxStackSize(), self_stack.getCount() + stack.getCount());
|
||||
int diff = new_count - self_stack.getCount();
|
||||
|
||||
if (diff != 0) {
|
||||
if (!simulate) {
|
||||
ItemStack copy_self = self_stack.copy();
|
||||
self_stack.grow(diff);
|
||||
container.setChanged(slot, self_stack, copy_self);
|
||||
var old = this_stack.copy();
|
||||
this_stack.setCount(new_count);
|
||||
tracked_slots[slot] = this_stack.copy();
|
||||
setChanged(slot, this_stack, old);
|
||||
}
|
||||
|
||||
ItemStack copy = stack.copy();
|
||||
copy.shrink(diff);
|
||||
|
||||
if (copy.isEmpty()) {
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// двигаем в пустые слоты
|
||||
for (int slot = start; slot < end; slot++) {
|
||||
if (slots[slot].isEmpty()) {
|
||||
int diff = Math.min(copy.getCount(), Math.min(getMaxStackSize(slot), copy.getMaxStackSize()));
|
||||
|
||||
if (!simulate) {
|
||||
var put_copy = copy.copy();
|
||||
put_copy.setCount(diff);
|
||||
tracked_slots[slot] = put_copy.copy();
|
||||
setChanged(slot, put_copy, ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
copy.shrink(diff);
|
||||
|
||||
if (copy.isEmpty()) {
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack extractItem(int slot, int amount, boolean simulate) {
|
||||
if (amount == 0)
|
||||
return ItemStack.EMPTY;
|
||||
return copy;
|
||||
}
|
||||
|
||||
if (amount < 0)
|
||||
throw new IllegalArgumentException("Can not extract negative amount of items");
|
||||
public ItemStack addItem(ItemStack stack, boolean simulate) {
|
||||
return addItem(stack, 0, size, simulate);
|
||||
}
|
||||
|
||||
ItemStack self_stack = container.getItem(slot);
|
||||
public ItemStack addItem(ItemStack stack) {
|
||||
return addItem(stack, 0, size, false);
|
||||
}
|
||||
|
||||
if (self_stack.isEmpty())
|
||||
return ItemStack.EMPTY;
|
||||
public boolean fullyAddItem(ItemStack stack) {
|
||||
if (!addItem(stack, 0, size, true).isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!extract_validator.apply(slot, amount, self_stack))
|
||||
return ItemStack.EMPTY;
|
||||
return addItem(stack, 0, size, false).isEmpty();
|
||||
}
|
||||
|
||||
int minimal = Math.min(amount, self_stack.getCount());
|
||||
ItemStack copy = self_stack.copy();
|
||||
copy.setCount(minimal);
|
||||
public boolean fullyAddItem(ItemStack stack, int start, int end) {
|
||||
if (!addItem(stack, start, end, true).isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!simulate) {
|
||||
ItemStack copy_self = self_stack.copy();
|
||||
self_stack.shrink(minimal);
|
||||
container.setChanged(slot, self_stack, copy_self);
|
||||
return addItem(stack, start, end, false).isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContainerSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
for (var stack : slots)
|
||||
if (!stack.isEmpty())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItem(int slot) {
|
||||
return slots[slot];
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack removeItem(int slot, int amount) {
|
||||
if (amount <= 0 || slot < 0 || slot >= size || slots[slot].isEmpty())
|
||||
return ItemStack.EMPTY;
|
||||
|
||||
var old = slots[slot].copy();
|
||||
var split = slots[slot].split(amount);
|
||||
tracked_slots[slot] = slots[slot].copy();
|
||||
setChanged(slot, slots[slot].isEmpty() ? ItemStack.EMPTY : slots[slot], old);
|
||||
|
||||
return split;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack removeItemNoUpdate(int slot) {
|
||||
var old = slots[slot];
|
||||
slots[slot] = ItemStack.EMPTY;
|
||||
tracked_slots[slot] = ItemStack.EMPTY;
|
||||
return old;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItem(int slot, ItemStack stack) {
|
||||
if (slots[slot].isEmpty() && stack.isEmpty() || stack == slots[slot])
|
||||
return;
|
||||
|
||||
var old = slots[slot];
|
||||
slots[slot] = stack;
|
||||
tracked_slots[slot] = stack.copy();
|
||||
setChanged(slot, stack, old);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChanged() {
|
||||
for (int slot = 0; slot < size; slot++) {
|
||||
if (!ItemStack.isSameItemSameTags(slots[slot], tracked_slots[slot])) {
|
||||
setChanged(slot, slots[slot], tracked_slots[slot]);
|
||||
tracked_slots[slot] = slots[slot].copy();
|
||||
// mojang соси))0)0))0)))))0)
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlotLimit(int slot) {
|
||||
return container.getMaxStackSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemValid(int slot, @Nonnull ItemStack stack) {
|
||||
return insert_validator.apply(slot, stack);
|
||||
}
|
||||
|
||||
MatteryContainerHandler cloneOf(MatteryContainer container) {
|
||||
return new MatteryContainerHandler(container, insert_validator, extract_validator);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stillValid(Player player) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearContent() {
|
||||
for (int slot = 0; slot < size; slot++) {
|
||||
if (!slots[slot].isEmpty()) {
|
||||
setChanged(slot, ItemStack.EMPTY, slots[slot]);
|
||||
}
|
||||
}
|
||||
|
||||
Arrays.fill(tracked_slots, ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<ItemStack> iterator() {
|
||||
return Arrays.stream(slots).iterator();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
package ru.dbotthepony.mc.otm.container;
|
||||
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface MatteryContainerExtractValidator {
|
||||
boolean apply(int slot, int amount, @Nonnull ItemStack stack);
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
package ru.dbotthepony.mc.otm.container;
|
||||
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
class MatteryContainerHandler implements IItemHandler {
|
||||
private final MatteryContainer container;
|
||||
private final MatteryContainerInsertValidator insert_validator;
|
||||
private final MatteryContainerExtractValidator extract_validator;
|
||||
|
||||
MatteryContainerHandler(MatteryContainer container, MatteryContainerInsertValidator insert_validator, MatteryContainerExtractValidator extract_validator) {
|
||||
this.container = container;
|
||||
this.insert_validator = insert_validator;
|
||||
this.extract_validator = extract_validator;
|
||||
}
|
||||
|
||||
MatteryContainerHandler(MatteryContainer container) {
|
||||
this(container, (slot, stack) -> true, (slot, amount, stack) -> true);
|
||||
}
|
||||
|
||||
MatteryContainerHandler(MatteryContainer container, MatteryContainerInsertValidator insert_validator) {
|
||||
this(container, insert_validator, (slot, amount, stack) -> true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlots() {
|
||||
return container.getContainerSize();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack getStackInSlot(int slot) {
|
||||
return container.getItem(slot);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate) {
|
||||
if (!insert_validator.apply(slot, stack))
|
||||
return stack;
|
||||
|
||||
ItemStack self_stack = container.getItem(slot);
|
||||
|
||||
if (self_stack.isEmpty()) {
|
||||
if (!simulate) {
|
||||
var copy = stack.copy();
|
||||
container.setChanged(slot, copy, ItemStack.EMPTY);
|
||||
container.setItem(slot, copy);
|
||||
}
|
||||
|
||||
return ItemStack.EMPTY;
|
||||
} else if (self_stack.isStackable() && self_stack.getMaxStackSize() > self_stack.getCount() && ItemStack.isSameItemSameTags(self_stack, stack)) {
|
||||
int new_count = Math.min(self_stack.getMaxStackSize(), self_stack.getCount() + stack.getCount());
|
||||
int diff = new_count - self_stack.getCount();
|
||||
|
||||
if (diff != 0) {
|
||||
if (!simulate) {
|
||||
ItemStack copy_self = self_stack.copy();
|
||||
self_stack.grow(diff);
|
||||
container.setChanged(slot, self_stack, copy_self);
|
||||
}
|
||||
|
||||
ItemStack copy = stack.copy();
|
||||
copy.shrink(diff);
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack extractItem(int slot, int amount, boolean simulate) {
|
||||
if (amount == 0)
|
||||
return ItemStack.EMPTY;
|
||||
|
||||
if (amount < 0)
|
||||
throw new IllegalArgumentException("Can not extract negative amount of items");
|
||||
|
||||
ItemStack self_stack = container.getItem(slot);
|
||||
|
||||
if (self_stack.isEmpty())
|
||||
return ItemStack.EMPTY;
|
||||
|
||||
if (!extract_validator.apply(slot, amount, self_stack))
|
||||
return ItemStack.EMPTY;
|
||||
|
||||
int minimal = Math.min(amount, self_stack.getCount());
|
||||
ItemStack copy = self_stack.copy();
|
||||
copy.setCount(minimal);
|
||||
|
||||
if (!simulate) {
|
||||
ItemStack copy_self = self_stack.copy();
|
||||
self_stack.shrink(minimal);
|
||||
container.setChanged(slot, self_stack, copy_self);
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlotLimit(int slot) {
|
||||
return container.getMaxStackSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemValid(int slot, @Nonnull ItemStack stack) {
|
||||
return insert_validator.apply(slot, stack);
|
||||
}
|
||||
|
||||
MatteryContainerHandler cloneOf(MatteryContainer container) {
|
||||
return new MatteryContainerHandler(container, insert_validator, extract_validator);
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package ru.dbotthepony.mc.otm.container;
|
||||
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface MatteryContainerInsertValidator {
|
||||
boolean apply(int slot, @Nonnull ItemStack stack);
|
||||
}
|
@ -4,18 +4,13 @@ import com.google.common.collect.ImmutableList;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.Level;
|
||||
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.OverdriveThatMatters;
|
||||
import ru.dbotthepony.mc.otm.capability.*;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class MatterGrid implements IMatterGridListener {
|
||||
public static final Set<MatterGrid> NETWORKS = new HashSet<>();
|
||||
@ -23,48 +18,8 @@ public class MatterGrid implements IMatterGridListener {
|
||||
private final Set<IMatterGridCell> cells = new HashSet<>();
|
||||
private final Set<IMatterGridListener> listeners = new HashSet<>();
|
||||
|
||||
private static final WeakHashMap<Level, Set<Supplier<Boolean>>> discovering_neighbours = new WeakHashMap<>();
|
||||
|
||||
public static void scheduleDiscoverNeighbours(IMatterGridCell cell, BlockPos pos, Level level) {
|
||||
discovering_neighbours.computeIfAbsent(level, (key) -> new HashSet<>()).add(() -> !cell.isValidMatterCell() || cell.connectOrCreateMatterGrid(pos, level, true));
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onServerStarting(FMLServerStartedEvent event) {
|
||||
discovering_neighbours.clear();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onServerStopping(FMLServerStoppingEvent event) {
|
||||
discovering_neighbours.clear();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void discoverNeighbours(TickEvent.WorldTickEvent event) {
|
||||
if (event.phase != TickEvent.Phase.START)
|
||||
return;
|
||||
|
||||
var set = discovering_neighbours.get(event.world);
|
||||
|
||||
if (set != null) {
|
||||
ArrayList<Supplier<Boolean>> invalid = new ArrayList<>();
|
||||
|
||||
for (Supplier<Boolean> cell : set) {
|
||||
if (cell.get()) {
|
||||
invalid.add(cell);
|
||||
}
|
||||
}
|
||||
|
||||
if (invalid.size() != 0) {
|
||||
for (Supplier<Boolean> cell : invalid) {
|
||||
set.remove(cell);
|
||||
}
|
||||
}
|
||||
|
||||
if (set.size() == 0) {
|
||||
discovering_neighbours.remove(event.world);
|
||||
}
|
||||
}
|
||||
OverdriveThatMatters.tickUntil(level, () -> !cell.isValidMatterCell() || cell.connectOrCreateMatterGrid(pos, level, true));
|
||||
}
|
||||
|
||||
public MatterGrid() {
|
||||
|
51
src/main/java/ru/dbotthepony/mc/otm/menu/DriveRackMenu.java
Normal file
51
src/main/java/ru/dbotthepony/mc/otm/menu/DriveRackMenu.java
Normal file
@ -0,0 +1,51 @@
|
||||
package ru.dbotthepony.mc.otm.menu;
|
||||
|
||||
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.BlockEntityDriveRack;
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
|
||||
import ru.dbotthepony.mc.otm.menu.slot.MatterySlot;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class DriveRackMenu extends PoweredMatteryMenu {
|
||||
public DriveRackMenu(int p_38852_, Inventory inventory) {
|
||||
this(p_38852_, inventory, null);
|
||||
}
|
||||
|
||||
public final MatterySlot[] drives = new MatterySlot[4];
|
||||
|
||||
public DriveRackMenu(int p_38852_, Inventory inventory, BlockEntityDriveRack tile) {
|
||||
super(Registry.Menus.DRIVE_RACK, p_38852_, inventory, tile);
|
||||
|
||||
var container = tile != null ? tile.drives : new SimpleContainer(4);
|
||||
|
||||
for (int i = 0; i < container.getContainerSize(); i++) {
|
||||
drives[i] = new MatterySlot(container, i) {
|
||||
@Override
|
||||
public boolean mayPlace(ItemStack p_40231_) {
|
||||
return p_40231_.getCapability(MatteryCapability.DRIVE).isPresent();
|
||||
}
|
||||
};
|
||||
|
||||
addSlot(drives[i]);
|
||||
}
|
||||
|
||||
addBatterySlot();
|
||||
addInventorySlots();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getWorkingSlotStart() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getWorkingSlotEnd() {
|
||||
return 5;
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.menu;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.SimpleContainer;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
@ -12,28 +11,30 @@ import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.energy.CapabilityEnergy;
|
||||
import net.minecraftforge.fmllegacy.network.NetworkEvent;
|
||||
import net.minecraftforge.fmllegacy.network.PacketDistributor;
|
||||
import ru.dbotthepony.mc.otm.Registry;
|
||||
import ru.dbotthepony.mc.otm.block.entity.BlockEntityDriveViewer;
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
|
||||
import ru.dbotthepony.mc.otm.capability.drive.IItemViewListener;
|
||||
import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive;
|
||||
import ru.dbotthepony.mc.otm.item.ItemPortableCondensationDrive;
|
||||
import ru.dbotthepony.mc.otm.menu.data.INetworkedItemViewSupplier;
|
||||
import ru.dbotthepony.mc.otm.menu.data.InteractPacket;
|
||||
import ru.dbotthepony.mc.otm.menu.data.NetworkedItemView;
|
||||
import ru.dbotthepony.mc.otm.menu.slot.MatterySlot;
|
||||
import ru.dbotthepony.mc.otm.network.MatteryNetworking;
|
||||
import ru.dbotthepony.mc.otm.network.SetCarriedPacket;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class DriveViewerMenu extends PoweredMatteryMenu {
|
||||
public NetworkedItemView view;
|
||||
public class DriveViewerMenu extends PoweredMatteryMenu implements INetworkedItemViewSupplier {
|
||||
public final NetworkedItemView view;
|
||||
public MatterySlot drive_slot;
|
||||
protected IMatteryDrive last_drive;
|
||||
public IMatteryDrive last_drive;
|
||||
|
||||
@Override
|
||||
public NetworkedItemView getNetworkedItemView() {
|
||||
return view;
|
||||
}
|
||||
|
||||
public DriveViewerMenu(int containerID, Inventory inventory) {
|
||||
this(containerID, inventory, null);
|
||||
@ -51,9 +52,27 @@ public class DriveViewerMenu extends PoweredMatteryMenu {
|
||||
}
|
||||
};
|
||||
|
||||
addSlot(drive_slot);
|
||||
view = new NetworkedItemView();
|
||||
view = new NetworkedItemView(inventory.player, this, tile == null) {
|
||||
@Override
|
||||
public int calculateIOAmount(int desired_amount) {
|
||||
if (tile != null)
|
||||
return tile.getIOItemCount(desired_amount, true);
|
||||
|
||||
return super.calculateIOAmount(desired_amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doneIOAmount(int done_amount) {
|
||||
if (tile != null) {
|
||||
tile.getIOItemCount(done_amount, false);
|
||||
return;
|
||||
}
|
||||
|
||||
super.doneIOAmount(done_amount);
|
||||
}
|
||||
};
|
||||
|
||||
addSlot(drive_slot);
|
||||
addBatterySlot();
|
||||
addInventorySlots();
|
||||
}
|
||||
@ -66,35 +85,18 @@ public class DriveViewerMenu extends PoweredMatteryMenu {
|
||||
var get = ((BlockEntityDriveViewer) tile).drive_slot.getItem(0);
|
||||
|
||||
if (get.isEmpty()) {
|
||||
if (last_drive != null) {
|
||||
last_drive.removeListener(view);
|
||||
view.clear();
|
||||
}
|
||||
|
||||
last_drive = null;
|
||||
} else {
|
||||
var get_cap = get.getCapability(MatteryCapability.DRIVE).resolve();
|
||||
|
||||
if (get_cap.isEmpty()) {
|
||||
if (last_drive != null) {
|
||||
last_drive.removeListener(view);
|
||||
view.clear();
|
||||
}
|
||||
|
||||
last_drive = null;
|
||||
} else {
|
||||
if (last_drive != get_cap.get()) {
|
||||
if (last_drive != null)
|
||||
last_drive.removeListener(view);
|
||||
|
||||
view.clear();
|
||||
get_cap.get().addListener(view);
|
||||
}
|
||||
|
||||
last_drive = get_cap.get();
|
||||
}
|
||||
}
|
||||
|
||||
view.setComponent(last_drive);
|
||||
view.network();
|
||||
}
|
||||
}
|
||||
@ -119,109 +121,6 @@ public class DriveViewerMenu extends PoweredMatteryMenu {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a virtual, slotless container for Player's interaction with.
|
||||
*/
|
||||
public class NetworkedItemView implements IItemViewListener {
|
||||
public record NetworkedItem(int id, ItemStack stack, UUID id_upstream) {
|
||||
public NetworkedItem(int id, ItemStack stack) {
|
||||
this(id, stack, null);
|
||||
}
|
||||
}
|
||||
|
||||
protected int next_stack_id = 0;
|
||||
|
||||
protected final HashMap<Integer, NetworkedItem> state = new HashMap<>();
|
||||
protected final HashMap<UUID, NetworkedItem> upstream_state = new HashMap<>();
|
||||
protected final ArrayList<Object> backlog = new ArrayList<>();
|
||||
|
||||
private List<NetworkedItem> view_cache;
|
||||
|
||||
public void clearCache() {
|
||||
view_cache = null;
|
||||
}
|
||||
|
||||
public List<NetworkedItem> getItems() {
|
||||
if (view_cache != null)
|
||||
return view_cache;
|
||||
|
||||
return view_cache = List.copyOf(state.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addViewItem(ItemStack stack, UUID id_upstream) {
|
||||
if (upstream_state.containsKey(id_upstream))
|
||||
throw new IllegalStateException("Already tracking ItemStack with upstream id " + id_upstream + "!");
|
||||
|
||||
var state = new NetworkedItem(next_stack_id++, stack.copy(), id_upstream);
|
||||
this.state.put(state.id, state);
|
||||
this.upstream_state.put(id_upstream, state);
|
||||
|
||||
if (tile != null) {
|
||||
backlog.add(new StackAddPacket(containerId, state.id, stack));
|
||||
}
|
||||
|
||||
clearCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeViewItem(UUID id_upstream, int new_count) {
|
||||
var get = upstream_state.get(id_upstream);
|
||||
|
||||
if (get == null)
|
||||
throw new IllegalStateException("Unknown ItemStack with upstream id " + id_upstream + "!");
|
||||
|
||||
get.stack.setCount(new_count);
|
||||
|
||||
if (tile != null) {
|
||||
backlog.add(new StackChangePacket(containerId, get.id, new_count));
|
||||
}
|
||||
|
||||
clearCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeViewItem(UUID id_upstream) {
|
||||
var get = upstream_state.get(id_upstream);
|
||||
|
||||
if (get == null)
|
||||
throw new IllegalStateException("Unknown ItemStack with upstream id " + id_upstream + "!");
|
||||
|
||||
upstream_state.remove(id_upstream);
|
||||
state.remove(get.id);
|
||||
|
||||
if (tile != null) {
|
||||
backlog.add(new StackRemovePacket(containerId, get.id));
|
||||
}
|
||||
|
||||
clearCache();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
clearCache();
|
||||
upstream_state.clear();
|
||||
state.clear();
|
||||
|
||||
if (tile != null) {
|
||||
backlog.clear();
|
||||
backlog.add(new ClearPacket(containerId));
|
||||
}
|
||||
}
|
||||
|
||||
public void network() {
|
||||
if (tile == null)
|
||||
throw new IllegalStateException("Not a server");
|
||||
|
||||
var consumer = PacketDistributor.PLAYER.with(() -> (ServerPlayer) ply);
|
||||
|
||||
for (var packet : backlog) {
|
||||
MatteryNetworking.CHANNEL.send(consumer, packet);
|
||||
}
|
||||
|
||||
backlog.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack quickMoveStack(Player ply, int slot_index) {
|
||||
var slot = slots.get(slot_index);
|
||||
@ -276,283 +175,6 @@ public class DriveViewerMenu extends PoweredMatteryMenu {
|
||||
return copy;
|
||||
}
|
||||
|
||||
public record InteractPacket(int id, int stack_id, ClickType click, ClickAction action) {
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeInt(id);
|
||||
buffer.writeInt(stack_id);
|
||||
buffer.writeEnum(click);
|
||||
buffer.writeEnum(action);
|
||||
}
|
||||
|
||||
public static InteractPacket read(FriendlyByteBuf buffer) {
|
||||
var id = buffer.readInt();
|
||||
var stack = buffer.readInt();
|
||||
var click = buffer.readEnum(ClickType.class);
|
||||
var action = buffer.readEnum(ClickAction.class);
|
||||
return new InteractPacket(id, stack, click, action);
|
||||
}
|
||||
|
||||
public void play(Supplier<NetworkEvent.Context> context) {
|
||||
context.get().setPacketHandled(true);
|
||||
context.get().enqueueWork(() -> {
|
||||
var ply = context.get().getSender();
|
||||
|
||||
if (ply.containerMenu instanceof DriveViewerMenu menu) {
|
||||
var view = menu.containerId == id ? menu.view : null;
|
||||
|
||||
if (view == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ply.resetLastActionTime();
|
||||
|
||||
if (menu.last_drive == null)
|
||||
return;
|
||||
|
||||
var tile = (BlockEntityDriveViewer) menu.tile;
|
||||
|
||||
if (click == ClickType.QUICK_MOVE && stack_id > -1) {
|
||||
if (!tile.canIOItems())
|
||||
return;
|
||||
|
||||
var get_state = view.state.get(stack_id);
|
||||
|
||||
if (get_state == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int amount = tile.getIOItemCount(action == ClickAction.PRIMARY ? get_state.stack.getMaxStackSize() : Math.max(1, get_state.stack.getMaxStackSize() / 2), true);
|
||||
var extracted = menu.last_drive.extractItem(get_state.id_upstream, amount, true);
|
||||
|
||||
if (!extracted.isEmpty()) {
|
||||
var move = menu.quickMoveToInventory(extracted, false);
|
||||
|
||||
if (move.remaining().getCount() != extracted.getCount()) {
|
||||
menu.last_drive.extractItem(get_state.id_upstream, extracted.getCount() - move.remaining().getCount(), false);
|
||||
tile.getIOItemCount(extracted.getCount() - move.remaining().getCount(), false);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (click == ClickType.CLONE) {
|
||||
if (stack_id < 0 || !ply.getAbilities().instabuild)
|
||||
return;
|
||||
|
||||
var get_state = view.state.get(stack_id);
|
||||
|
||||
if (get_state == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var copy = get_state.stack.copy();
|
||||
copy.setCount(Math.min(copy.getCount(), copy.getMaxStackSize()));
|
||||
|
||||
menu.setCarried(copy);
|
||||
MatteryNetworking.send(ply, new SetCarriedPacket(menu.getCarried()));
|
||||
menu.setRemoteCarried(menu.getCarried().copy());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tile.canIOItems())
|
||||
return;
|
||||
|
||||
if (!menu.getCarried().isEmpty() && click != ClickType.QUICK_MOVE) {
|
||||
// try to put
|
||||
if (action == ClickAction.PRIMARY) {
|
||||
var carried = menu.getCarried();
|
||||
int amount = tile.getIOItemCount(carried.getCount(), true);
|
||||
|
||||
if (amount == carried.getCount()) {
|
||||
var leftover = menu.last_drive.insertItem(menu.getCarried(), false);
|
||||
menu.setCarried(leftover);
|
||||
tile.getIOItemCount(amount - leftover.getCount(), false);
|
||||
|
||||
MatteryNetworking.send(ply, new SetCarriedPacket(menu.getCarried()));
|
||||
menu.setRemoteCarried(menu.getCarried().copy());
|
||||
} else if (amount != 0) {
|
||||
var copy = carried.copy();
|
||||
copy.setCount(amount);
|
||||
|
||||
var leftover = menu.last_drive.insertItem(copy, false);
|
||||
tile.getIOItemCount(amount - leftover.getCount(), false);
|
||||
|
||||
leftover.setCount(carried.getCount() - amount + leftover.getCount());
|
||||
menu.setCarried(leftover);
|
||||
|
||||
MatteryNetworking.send(ply, new SetCarriedPacket(menu.getCarried()));
|
||||
menu.setRemoteCarried(menu.getCarried().copy());
|
||||
}
|
||||
} else {
|
||||
var copy = menu.getCarried().copy();
|
||||
copy.setCount(1);
|
||||
|
||||
if (tile.getIOItemCount(1, true) == 1 && menu.last_drive.insertItem(copy, false).isEmpty()) {
|
||||
menu.getCarried().shrink(1);
|
||||
tile.getIOItemCount(1, false);
|
||||
MatteryNetworking.send(ply, new SetCarriedPacket(menu.getCarried()));
|
||||
menu.setRemoteCarried(menu.getCarried().copy());
|
||||
}
|
||||
}
|
||||
} else if (stack_id > -1) {
|
||||
var get_state = view.state.get(stack_id);
|
||||
|
||||
if (get_state == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int amount = tile.getIOItemCount(action == ClickAction.PRIMARY ? get_state.stack.getMaxStackSize() : Math.max(1, get_state.stack.getMaxStackSize() / 2), true);
|
||||
|
||||
var extracted = menu.last_drive.extractItem(get_state.id_upstream, amount, false);
|
||||
|
||||
tile.getIOItemCount(extracted.getCount(), false);
|
||||
menu.setCarried(extracted);
|
||||
MatteryNetworking.send(ply, new SetCarriedPacket(menu.getCarried()));
|
||||
menu.setRemoteCarried(menu.getCarried().copy());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public record ClearPacket(int id) {
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeInt(id);
|
||||
}
|
||||
|
||||
public static ClearPacket read(FriendlyByteBuf buffer) {
|
||||
return new ClearPacket(buffer.readInt());
|
||||
}
|
||||
|
||||
public void play(Supplier<NetworkEvent.Context> context) {
|
||||
context.get().setPacketHandled(true);
|
||||
context.get().enqueueWork(() -> {
|
||||
var get = Minecraft.getInstance().player.containerMenu instanceof DriveViewerMenu menu && menu.containerId == id ? menu.view : null;
|
||||
|
||||
if (get == null) {
|
||||
throw new IllegalStateException("No such item tracker with id " + id);
|
||||
}
|
||||
|
||||
get.clear();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public record StackAddPacket(int id, int stack_id, ItemStack stack) {
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeInt(id);
|
||||
buffer.writeInt(stack_id);
|
||||
buffer.writeRegistryId(stack.getItem());
|
||||
buffer.writeInt(stack.getCount());
|
||||
buffer.writeBoolean(stack.getTag() != null);
|
||||
|
||||
if (stack.getTag() != null)
|
||||
buffer.writeNbt(stack.getShareTag());
|
||||
}
|
||||
|
||||
public static StackAddPacket read(FriendlyByteBuf buffer) {
|
||||
var id = buffer.readInt();
|
||||
var stack = buffer.readInt();
|
||||
var item = buffer.readRegistryIdSafe(Item.class);
|
||||
var count = buffer.readInt();
|
||||
|
||||
var state = new ItemStack(item, count);
|
||||
|
||||
if (buffer.readBoolean())
|
||||
state.readShareTag(buffer.readNbt());
|
||||
|
||||
return new StackAddPacket(id, stack, state);
|
||||
}
|
||||
|
||||
public void play(Supplier<NetworkEvent.Context> context) {
|
||||
context.get().setPacketHandled(true);
|
||||
context.get().enqueueWork(() -> {
|
||||
var get = Minecraft.getInstance().player.containerMenu instanceof DriveViewerMenu menu && menu.containerId == id ? menu.view : null;
|
||||
|
||||
if (get == null) {
|
||||
throw new IllegalStateException("No such item tracker with id " + id);
|
||||
}
|
||||
|
||||
if (get.state.containsKey(stack_id)) {
|
||||
throw new IllegalStateException("Item tracker " + id + " already has stack with id of " + stack_id);
|
||||
}
|
||||
|
||||
get.state.put(stack_id, new NetworkedItemView.NetworkedItem(stack_id, stack));
|
||||
get.clearCache();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public record StackChangePacket(int id, int stack_id, int new_count) {
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeInt(id);
|
||||
buffer.writeInt(stack_id);
|
||||
buffer.writeInt(new_count);
|
||||
}
|
||||
|
||||
public static StackChangePacket read(FriendlyByteBuf buffer) {
|
||||
var id = buffer.readInt();
|
||||
var stack_id = buffer.readInt();
|
||||
var new_count = buffer.readInt();
|
||||
|
||||
return new StackChangePacket(id, stack_id, new_count);
|
||||
}
|
||||
|
||||
public void play(Supplier<NetworkEvent.Context> context) {
|
||||
context.get().setPacketHandled(true);
|
||||
context.get().enqueueWork(() -> {
|
||||
var get = Minecraft.getInstance().player.containerMenu instanceof DriveViewerMenu menu && menu.containerId == id ? menu.view : null;
|
||||
|
||||
if (get == null) {
|
||||
throw new IllegalStateException("No such item tracker with id " + id);
|
||||
}
|
||||
|
||||
var get_state = get.state.get(stack_id);
|
||||
|
||||
if (get_state == null) {
|
||||
throw new IllegalStateException("Item tracker " + id + " has no stack with id of " + stack_id);
|
||||
}
|
||||
|
||||
get_state.stack.setCount(new_count);
|
||||
get.clearCache();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public record StackRemovePacket(int id, int stack_id) {
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeInt(id);
|
||||
buffer.writeInt(stack_id);
|
||||
}
|
||||
|
||||
public static StackRemovePacket read(FriendlyByteBuf buffer) {
|
||||
var id = buffer.readInt();
|
||||
var stack_id = buffer.readInt();
|
||||
|
||||
return new StackRemovePacket(id, stack_id);
|
||||
}
|
||||
|
||||
public void play(Supplier<NetworkEvent.Context> context) {
|
||||
context.get().setPacketHandled(true);
|
||||
context.get().enqueueWork(() -> {
|
||||
var get = Minecraft.getInstance().player.containerMenu instanceof DriveViewerMenu menu && menu.containerId == id ? menu.view : null;
|
||||
|
||||
if (get == null) {
|
||||
throw new IllegalStateException("No such item tracker with id " + id);
|
||||
}
|
||||
|
||||
var get_state = get.state.remove(stack_id);
|
||||
|
||||
if (get_state == null) {
|
||||
throw new IllegalStateException("Item tracker " + id + " has no stack with id of " + stack_id);
|
||||
}
|
||||
|
||||
get.clearCache();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public enum FilterSwitch {
|
||||
MATCH_NBT,
|
||||
MATCH_TAG,
|
||||
|
@ -0,0 +1,58 @@
|
||||
package ru.dbotthepony.mc.otm.menu;
|
||||
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
|
||||
import ru.dbotthepony.mc.otm.Registry;
|
||||
import ru.dbotthepony.mc.otm.block.entity.BlockEntityDriveRack;
|
||||
import ru.dbotthepony.mc.otm.block.entity.BlockEntityItemMonitor;
|
||||
import ru.dbotthepony.mc.otm.menu.data.INetworkedItemViewSupplier;
|
||||
import ru.dbotthepony.mc.otm.menu.data.InteractPacket;
|
||||
import ru.dbotthepony.mc.otm.menu.data.NetworkedItemView;
|
||||
import ru.dbotthepony.mc.otm.storage.ItemStackObject;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class ItemMonitorMenu extends PoweredMatteryMenu implements INetworkedItemViewSupplier {
|
||||
public final NetworkedItemView view;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public NetworkedItemView getNetworkedItemView() {
|
||||
return view;
|
||||
}
|
||||
|
||||
public ItemMonitorMenu(int p_38852_, Inventory inventory) {
|
||||
this(p_38852_, inventory, null);
|
||||
}
|
||||
|
||||
public ItemMonitorMenu(int p_38852_, Inventory inventory, BlockEntityItemMonitor tile) {
|
||||
super(Registry.Menus.ITEM_MONITOR, p_38852_, inventory, tile);
|
||||
|
||||
view = new NetworkedItemView(inventory.player, this, tile == null);
|
||||
|
||||
if (tile != null) {
|
||||
OverdriveThatMatters.LOGGER.info("{}", tile.cell.getStorageGrid().global_item_view.getCombinedItemList());
|
||||
view.setComponent(tile.cell.getStorageGrid().getVirtualComponent(ItemStackObject.class));
|
||||
}
|
||||
|
||||
addBatterySlot();
|
||||
addInventorySlots();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastChanges() {
|
||||
super.broadcastChanges();
|
||||
|
||||
view.network();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getWorkingSlotStart() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getWorkingSlotEnd() {
|
||||
return 1;
|
||||
}
|
||||
}
|
@ -18,10 +18,10 @@ import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public abstract class MatteryMenu extends AbstractContainerMenu {
|
||||
protected BlockEntity tile;
|
||||
public final BlockEntity tile;
|
||||
|
||||
protected Inventory inventory;
|
||||
protected Player ply;
|
||||
public final Inventory inventory;
|
||||
public final Player ply;
|
||||
|
||||
public final ArrayList<AbstractWidget> mattery_widgets = new ArrayList<>();
|
||||
public final ArrayList<MatterySlot> inventory_slots = new ArrayList<>();
|
||||
@ -43,13 +43,13 @@ public abstract class MatteryMenu extends AbstractContainerMenu {
|
||||
}
|
||||
|
||||
protected MatteryMenu(@Nullable MenuType<?> p_38851_, int p_38852_, Inventory inventory) {
|
||||
super(p_38851_, p_38852_);
|
||||
this.inventory = inventory;
|
||||
this.ply = inventory.player;
|
||||
this(p_38851_, p_38852_, inventory, null);
|
||||
}
|
||||
|
||||
protected MatteryMenu(@Nullable MenuType<?> p_38851_, int p_38852_, Inventory inventory, BlockEntity tile) {
|
||||
this(p_38851_, p_38852_, inventory);
|
||||
super(p_38851_, p_38852_);
|
||||
this.inventory = inventory;
|
||||
this.ply = inventory.player;
|
||||
this.tile = tile;
|
||||
}
|
||||
|
||||
@ -157,22 +157,6 @@ public abstract class MatteryMenu extends AbstractContainerMenu {
|
||||
abstract protected int getWorkingSlotStart();
|
||||
abstract protected int getWorkingSlotEnd();
|
||||
|
||||
protected void notifySlotsWatchCurrentStack() {
|
||||
for (var slot : slots) {
|
||||
if (slot instanceof MatterySlot slot1) {
|
||||
slot1.watchCurrentStack();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void notifySlotsUnwatchCurrentStack() {
|
||||
for (var slot : slots) {
|
||||
if (slot instanceof MatterySlot slot1) {
|
||||
slot1.unwatchCurrentStack();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This method receive Player interactor and slot_index where Shift + Right click occurred
|
||||
// It shall return item stack that got moved
|
||||
@Override
|
||||
@ -193,7 +177,6 @@ public abstract class MatteryMenu extends AbstractContainerMenu {
|
||||
|
||||
ItemStack moved = ItemStack.EMPTY;
|
||||
Slot get_slot = this.slots.get(slot_index);
|
||||
notifySlotsWatchCurrentStack();
|
||||
|
||||
if (get_slot.hasItem()) {
|
||||
ItemStack slot_item = get_slot.getItem();
|
||||
@ -203,12 +186,10 @@ public abstract class MatteryMenu extends AbstractContainerMenu {
|
||||
// Moving FROM machine TO inventory
|
||||
|
||||
if (!moveItemStackTo(slot_item, inventory_slot_index_start, inventory_slot_index_end + 1, false)) {
|
||||
notifySlotsUnwatchCurrentStack();
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
} else if (!moveItemStackTo(slot_item, start, end, false)) {
|
||||
// Moving FROM inventory TO machine
|
||||
notifySlotsUnwatchCurrentStack();
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@ -217,11 +198,8 @@ public abstract class MatteryMenu extends AbstractContainerMenu {
|
||||
} else {
|
||||
get_slot.setChanged();
|
||||
}
|
||||
|
||||
notifySlotsWatchCurrentStack();
|
||||
}
|
||||
|
||||
notifySlotsUnwatchCurrentStack();
|
||||
return moved;
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ import ru.dbotthepony.mc.otm.menu.widget.BatteryLevelWidget;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
abstract public class PoweredMatteryMenu extends MatteryMenu {
|
||||
protected BlockEntityMatteryPowered tile;
|
||||
public final BlockEntityMatteryPowered tile;
|
||||
|
||||
public BatteryLevelWidget battery_widget;
|
||||
public BatterySlot battery_slot;
|
||||
|
@ -0,0 +1,31 @@
|
||||
package ru.dbotthepony.mc.otm.menu.data;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraftforge.fmllegacy.network.NetworkEvent;
|
||||
import ru.dbotthepony.mc.otm.menu.DriveViewerMenu;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public record ClearPacket(int id) {
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeInt(id);
|
||||
}
|
||||
|
||||
public static ClearPacket read(FriendlyByteBuf buffer) {
|
||||
return new ClearPacket(buffer.readInt());
|
||||
}
|
||||
|
||||
public void play(Supplier<NetworkEvent.Context> context) {
|
||||
context.get().setPacketHandled(true);
|
||||
context.get().enqueueWork(() -> {
|
||||
var get = Minecraft.getInstance().player.containerMenu instanceof INetworkedItemViewSupplier supplier && Minecraft.getInstance().player.containerMenu.containerId == id ? supplier.getNetworkedItemView() : null;
|
||||
|
||||
if (get == null) {
|
||||
throw new IllegalStateException("No such item tracker with id " + id);
|
||||
}
|
||||
|
||||
get.clear();
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package ru.dbotthepony.mc.otm.menu.data;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public interface INetworkedItemViewSupplier {
|
||||
NetworkedItemView getNetworkedItemView();
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package ru.dbotthepony.mc.otm.menu.data;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.world.inventory.ClickAction;
|
||||
import net.minecraft.world.inventory.ClickType;
|
||||
import net.minecraftforge.fmllegacy.network.NetworkEvent;
|
||||
import ru.dbotthepony.mc.otm.block.entity.BlockEntityDriveViewer;
|
||||
import ru.dbotthepony.mc.otm.menu.DriveViewerMenu;
|
||||
import ru.dbotthepony.mc.otm.network.MatteryNetworking;
|
||||
import ru.dbotthepony.mc.otm.network.SetCarriedPacket;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public record InteractPacket(int id, int stack_id, ClickType click, ClickAction action) {
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeInt(id);
|
||||
buffer.writeInt(stack_id);
|
||||
buffer.writeEnum(click);
|
||||
buffer.writeEnum(action);
|
||||
}
|
||||
|
||||
public static InteractPacket read(FriendlyByteBuf buffer) {
|
||||
var id = buffer.readInt();
|
||||
var stack = buffer.readInt();
|
||||
var click = buffer.readEnum(ClickType.class);
|
||||
var action = buffer.readEnum(ClickAction.class);
|
||||
return new InteractPacket(id, stack, click, action);
|
||||
}
|
||||
|
||||
public void play(Supplier<NetworkEvent.Context> context) {
|
||||
context.get().setPacketHandled(true);
|
||||
context.get().enqueueWork(() -> {
|
||||
var ply = context.get().getSender();
|
||||
|
||||
if (ply.containerMenu instanceof INetworkedItemViewSupplier supplier && ply.containerMenu.containerId == id) {
|
||||
ply.resetLastActionTime();
|
||||
supplier.getNetworkedItemView().playerInteract(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,288 @@
|
||||
package ru.dbotthepony.mc.otm.menu.data;
|
||||
|
||||
import com.mojang.blaze3d.platform.InputConstants;
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.ClickAction;
|
||||
import net.minecraft.world.inventory.ClickType;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.fmllegacy.network.PacketDistributor;
|
||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu;
|
||||
import ru.dbotthepony.mc.otm.network.MatteryNetworking;
|
||||
import ru.dbotthepony.mc.otm.network.SetCarriedPacket;
|
||||
import ru.dbotthepony.mc.otm.storage.*;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.minecraft.client.gui.screens.Screen.hasShiftDown;
|
||||
|
||||
/**
|
||||
* Creates a virtual, slotless container for Player's interaction with.
|
||||
*/
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public class NetworkedItemView implements IStorageListener<ItemStackObject> {
|
||||
public final boolean remote;
|
||||
public final MatteryMenu menu;
|
||||
public final Player ply;
|
||||
|
||||
protected int next_stack_id = 0;
|
||||
|
||||
protected final HashMap<Integer, NetworkedItem> state = new HashMap<>();
|
||||
protected final HashMap<UUID, NetworkedItem> upstream_state = new HashMap<>();
|
||||
protected final ArrayList<Object> backlog = new ArrayList<>();
|
||||
|
||||
@Nullable
|
||||
public NetworkedItem get(int id) {
|
||||
return state.get(id);
|
||||
}
|
||||
|
||||
private List<NetworkedItem> view_cache;
|
||||
|
||||
protected IStorageComponent<ItemStackObject> provider;
|
||||
|
||||
public NetworkedItemView(Player ply, MatteryMenu menu, boolean remote) {
|
||||
this.remote = remote;
|
||||
this.menu = menu;
|
||||
this.ply = ply;
|
||||
}
|
||||
|
||||
public void mouseClick(int index, int mouse_click_type) {
|
||||
var list = getItems();
|
||||
var action = mouse_click_type == InputConstants.MOUSE_BUTTON_LEFT ? ClickAction.PRIMARY : ClickAction.SECONDARY;
|
||||
var type = mouse_click_type == InputConstants.MOUSE_BUTTON_MIDDLE ? ClickType.CLONE : hasShiftDown() ? ClickType.QUICK_MOVE : ClickType.PICKUP;
|
||||
|
||||
MatteryNetworking.send(null, new InteractPacket(menu.containerId, index >= list.size() ? -1 : list.get(index).id(), type, action));
|
||||
}
|
||||
|
||||
public void setComponent(@Nullable IStorageComponent<ItemStackObject> provider) {
|
||||
if (provider == this.provider)
|
||||
return;
|
||||
|
||||
if (this.provider != null)
|
||||
this.provider.removeListenerAuto(this);
|
||||
|
||||
this.provider = provider;
|
||||
|
||||
if (provider != null)
|
||||
provider.addListenerAuto(this);
|
||||
}
|
||||
|
||||
public record NetworkedItem(int id, ItemStack stack, @Nullable UUID id_upstream) {
|
||||
public NetworkedItem(int id, ItemStack stack) {
|
||||
this(id, stack, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearCache() {
|
||||
view_cache = null;
|
||||
}
|
||||
|
||||
public List<NetworkedItem> getItems() {
|
||||
if (view_cache != null)
|
||||
return view_cache;
|
||||
|
||||
return view_cache = List.copyOf(state.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addObject(ItemStackObject stack, UUID id, IStorageView<ItemStackObject> provider) {
|
||||
addObject(stack.stack(), id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeObject(UUID id, BigDecimal new_count) {
|
||||
changeObject(id, new_count.intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeObject(UUID id) {
|
||||
var get = upstream_state.get(id);
|
||||
|
||||
if (get == null)
|
||||
throw new IllegalStateException("Unknown ItemStack with upstream id " + id + "!");
|
||||
|
||||
upstream_state.remove(id);
|
||||
state.remove(get.id);
|
||||
|
||||
if (!remote) {
|
||||
backlog.add(new StackRemovePacket(menu.containerId, get.id));
|
||||
}
|
||||
|
||||
clearCache();
|
||||
}
|
||||
|
||||
public void addObject(ItemStack stack, UUID id_upstream) {
|
||||
if (upstream_state.containsKey(id_upstream))
|
||||
throw new IllegalStateException("Already tracking ItemStack with upstream id " + id_upstream + "!");
|
||||
|
||||
var state = new NetworkedItem(next_stack_id++, stack.copy(), id_upstream);
|
||||
this.state.put(state.id, state);
|
||||
this.upstream_state.put(id_upstream, state);
|
||||
|
||||
if (!remote) {
|
||||
backlog.add(new StackAddPacket(menu.containerId, state.id, stack));
|
||||
}
|
||||
|
||||
clearCache();
|
||||
}
|
||||
|
||||
public void changeObject(UUID id_upstream, int new_count) {
|
||||
var get = upstream_state.get(id_upstream);
|
||||
|
||||
if (get == null)
|
||||
throw new IllegalStateException("Unknown ItemStack with upstream id " + id_upstream + "!");
|
||||
|
||||
get.stack.setCount(new_count);
|
||||
|
||||
if (!remote) {
|
||||
backlog.add(new StackChangePacket(menu.containerId, get.id, new_count));
|
||||
}
|
||||
|
||||
clearCache();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
clearCache();
|
||||
upstream_state.clear();
|
||||
state.clear();
|
||||
|
||||
if (!remote) {
|
||||
backlog.clear();
|
||||
backlog.add(new ClearPacket(menu.containerId));
|
||||
}
|
||||
}
|
||||
|
||||
public void network() {
|
||||
if (remote)
|
||||
throw new IllegalStateException("Not a server");
|
||||
|
||||
var consumer = PacketDistributor.PLAYER.with(() -> (ServerPlayer) ply);
|
||||
|
||||
for (var packet : backlog) {
|
||||
MatteryNetworking.CHANNEL.send(consumer, packet);
|
||||
}
|
||||
|
||||
backlog.clear();
|
||||
}
|
||||
|
||||
public int calculateIOAmount(int desired_amount) {
|
||||
return desired_amount;
|
||||
}
|
||||
|
||||
public void doneIOAmount(int done_amount) {
|
||||
|
||||
}
|
||||
|
||||
public void playerInteract(InteractPacket packet) {
|
||||
if (provider == null)
|
||||
return;
|
||||
|
||||
var click = packet.click();
|
||||
var action = packet.action();
|
||||
var stack_id = packet.stack_id();
|
||||
|
||||
if (click == ClickType.CLONE) {
|
||||
if (stack_id < 0 || !ply.getAbilities().instabuild)
|
||||
return;
|
||||
|
||||
var get_state = get(stack_id);
|
||||
|
||||
if (get_state == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var copy = get_state.stack().copy();
|
||||
copy.setCount(Math.min(copy.getCount(), copy.getMaxStackSize()));
|
||||
|
||||
ply.containerMenu.setCarried(copy);
|
||||
MatteryNetworking.send((ServerPlayer) ply, new SetCarriedPacket(ply.containerMenu.getCarried()));
|
||||
ply.containerMenu.setRemoteCarried(ply.containerMenu.getCarried().copy());
|
||||
return;
|
||||
}
|
||||
|
||||
if (click == ClickType.QUICK_MOVE && stack_id > -1) {
|
||||
var get_state = get(stack_id);
|
||||
|
||||
if (get_state == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int amount = calculateIOAmount(action == ClickAction.PRIMARY ? get_state.stack().getMaxStackSize() : Math.max(1, get_state.stack().getMaxStackSize() / 2));
|
||||
var extracted = provider.extractObject(get_state.id_upstream(), new BigDecimal(amount), true);
|
||||
|
||||
if (!extracted.isEmpty()) {
|
||||
var move = menu.quickMoveToInventory(extracted.stack(), false);
|
||||
|
||||
if (move.remaining().getCount() != extracted.stack().getCount()) {
|
||||
provider.extractObject(get_state.id_upstream(), new BigDecimal(extracted.stack().getCount() - move.remaining().getCount()), false);
|
||||
doneIOAmount(extracted.stack().getCount() - move.remaining().getCount());
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!menu.getCarried().isEmpty() && click != ClickType.QUICK_MOVE) {
|
||||
// try to put
|
||||
if (action == ClickAction.PRIMARY) {
|
||||
var carried = menu.getCarried();
|
||||
int amount = calculateIOAmount(carried.getCount());
|
||||
|
||||
if (amount == carried.getCount()) {
|
||||
var leftover = provider.insertObject(new ItemStackObject(menu.getCarried()), false);
|
||||
menu.setCarried(leftover.stack());
|
||||
doneIOAmount(amount - leftover.stack().getCount());
|
||||
|
||||
MatteryNetworking.send((ServerPlayer) ply, new SetCarriedPacket(menu.getCarried()));
|
||||
menu.setRemoteCarried(menu.getCarried().copy());
|
||||
} else if (amount != 0) {
|
||||
var copy = carried.copy();
|
||||
copy.setCount(amount);
|
||||
|
||||
var leftover = provider.insertObject(new ItemStackObject(copy), false);
|
||||
doneIOAmount(amount - leftover.stack().getCount());
|
||||
|
||||
leftover.setCount(carried.getCount() - amount + leftover.getCountInt());
|
||||
menu.setCarried(leftover.stack());
|
||||
|
||||
MatteryNetworking.send((ServerPlayer) ply, new SetCarriedPacket(menu.getCarried()));
|
||||
menu.setRemoteCarried(menu.getCarried().copy());
|
||||
}
|
||||
} else {
|
||||
var copy = menu.getCarried().copy();
|
||||
copy.setCount(1);
|
||||
|
||||
if (calculateIOAmount(1) == 1 && provider.insertObject(new ItemStackObject(copy), false).isEmpty()) {
|
||||
menu.getCarried().shrink(1);
|
||||
doneIOAmount(1);
|
||||
MatteryNetworking.send((ServerPlayer) ply, new SetCarriedPacket(menu.getCarried()));
|
||||
menu.setRemoteCarried(menu.getCarried().copy());
|
||||
}
|
||||
}
|
||||
} else if (stack_id > -1) {
|
||||
var get_state = get(stack_id);
|
||||
|
||||
if (get_state == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int amount = calculateIOAmount(action == ClickAction.PRIMARY ? get_state.stack().getMaxStackSize() : Math.max(1, get_state.stack().getMaxStackSize() / 2));
|
||||
|
||||
var extracted = provider.extractObject(get_state.id_upstream(), new BigDecimal(amount), false);
|
||||
|
||||
doneIOAmount(extracted.getCountInt());
|
||||
menu.setCarried(extracted.stack());
|
||||
MatteryNetworking.send((ServerPlayer) ply, new SetCarriedPacket(menu.getCarried()));
|
||||
menu.setRemoteCarried(menu.getCarried().copy());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package ru.dbotthepony.mc.otm.menu.data;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.fmllegacy.network.NetworkEvent;
|
||||
import ru.dbotthepony.mc.otm.menu.DriveViewerMenu;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public record StackAddPacket(int id, int stack_id, ItemStack stack) {
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeInt(id);
|
||||
buffer.writeInt(stack_id);
|
||||
buffer.writeRegistryId(stack.getItem());
|
||||
buffer.writeInt(stack.getCount());
|
||||
buffer.writeBoolean(stack.getTag() != null);
|
||||
|
||||
if (stack.getTag() != null)
|
||||
buffer.writeNbt(stack.getShareTag());
|
||||
}
|
||||
|
||||
public static StackAddPacket read(FriendlyByteBuf buffer) {
|
||||
var id = buffer.readInt();
|
||||
var stack = buffer.readInt();
|
||||
var item = buffer.readRegistryIdSafe(Item.class);
|
||||
var count = buffer.readInt();
|
||||
|
||||
var state = new ItemStack(item, count);
|
||||
|
||||
if (buffer.readBoolean())
|
||||
state.readShareTag(buffer.readNbt());
|
||||
|
||||
return new StackAddPacket(id, stack, state);
|
||||
}
|
||||
|
||||
public void play(Supplier<NetworkEvent.Context> context) {
|
||||
context.get().setPacketHandled(true);
|
||||
context.get().enqueueWork(() -> {
|
||||
var get = Minecraft.getInstance().player.containerMenu instanceof INetworkedItemViewSupplier supplier && Minecraft.getInstance().player.containerMenu.containerId == id ? supplier.getNetworkedItemView() : null;
|
||||
|
||||
if (get == null) {
|
||||
throw new IllegalStateException("No such item tracker with id " + id);
|
||||
}
|
||||
|
||||
if (get.state.containsKey(stack_id)) {
|
||||
throw new IllegalStateException("Item tracker " + id + " already has stack with id of " + stack_id);
|
||||
}
|
||||
|
||||
get.state.put(stack_id, new NetworkedItemView.NetworkedItem(stack_id, stack));
|
||||
get.clearCache();
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package ru.dbotthepony.mc.otm.menu.data;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraftforge.fmllegacy.network.NetworkEvent;
|
||||
import ru.dbotthepony.mc.otm.menu.DriveViewerMenu;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public record StackChangePacket(int id, int stack_id, int new_count) {
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeInt(id);
|
||||
buffer.writeInt(stack_id);
|
||||
buffer.writeInt(new_count);
|
||||
}
|
||||
|
||||
public static StackChangePacket read(FriendlyByteBuf buffer) {
|
||||
var id = buffer.readInt();
|
||||
var stack_id = buffer.readInt();
|
||||
var new_count = buffer.readInt();
|
||||
|
||||
return new StackChangePacket(id, stack_id, new_count);
|
||||
}
|
||||
|
||||
public void play(Supplier<NetworkEvent.Context> context) {
|
||||
context.get().setPacketHandled(true);
|
||||
context.get().enqueueWork(() -> {
|
||||
var get = Minecraft.getInstance().player.containerMenu instanceof INetworkedItemViewSupplier supplier && Minecraft.getInstance().player.containerMenu.containerId == id ? supplier.getNetworkedItemView() : null;
|
||||
|
||||
if (get == null) {
|
||||
throw new IllegalStateException("No such item tracker with id " + id);
|
||||
}
|
||||
|
||||
var get_state = get.state.get(stack_id);
|
||||
|
||||
if (get_state == null) {
|
||||
throw new IllegalStateException("Item tracker " + id + " has no stack with id of " + stack_id);
|
||||
}
|
||||
|
||||
get_state.stack().setCount(new_count);
|
||||
get.clearCache();
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package ru.dbotthepony.mc.otm.menu.data;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraftforge.fmllegacy.network.NetworkEvent;
|
||||
import ru.dbotthepony.mc.otm.menu.DriveViewerMenu;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public record StackRemovePacket(int id, int stack_id) {
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeInt(id);
|
||||
buffer.writeInt(stack_id);
|
||||
}
|
||||
|
||||
public static StackRemovePacket read(FriendlyByteBuf buffer) {
|
||||
var id = buffer.readInt();
|
||||
var stack_id = buffer.readInt();
|
||||
|
||||
return new StackRemovePacket(id, stack_id);
|
||||
}
|
||||
|
||||
public void play(Supplier<NetworkEvent.Context> context) {
|
||||
context.get().setPacketHandled(true);
|
||||
context.get().enqueueWork(() -> {
|
||||
var get = Minecraft.getInstance().player.containerMenu instanceof INetworkedItemViewSupplier supplier && Minecraft.getInstance().player.containerMenu.containerId == id ? supplier.getNetworkedItemView() : null;
|
||||
|
||||
if (get == null) {
|
||||
throw new IllegalStateException("No such item tracker with id " + id);
|
||||
}
|
||||
|
||||
var get_state = get.state.remove(stack_id);
|
||||
|
||||
if (get_state == null) {
|
||||
throw new IllegalStateException("Item tracker " + id + " has no stack with id of " + stack_id);
|
||||
}
|
||||
|
||||
get.clearCache();
|
||||
});
|
||||
}
|
||||
}
|
@ -30,56 +30,4 @@ public class MatterySlot extends Slot {
|
||||
public MatterySlot(Container p_40223_, int index) {
|
||||
this(p_40223_, index, 0, 0, true);
|
||||
}
|
||||
|
||||
private ItemStack last_stack;
|
||||
private ItemStack watching_stack;
|
||||
|
||||
public void watchCurrentStack() {
|
||||
watching_stack = super.getItem().copy();
|
||||
}
|
||||
|
||||
public void unwatchCurrentStack() {
|
||||
watching_stack = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItem() {
|
||||
var get = super.getItem();
|
||||
last_stack = get.copy();
|
||||
return get;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChanged() {
|
||||
if (container instanceof MatteryContainer container1) {
|
||||
ItemStack old = watching_stack != null ? watching_stack.copy() : last_stack.copy();
|
||||
container1.setChanged(getSlotIndex(), super.getItem(), old);
|
||||
} else {
|
||||
super.setChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(ItemStack p_40240_) {
|
||||
if (container instanceof MatteryContainer container1) {
|
||||
ItemStack old = watching_stack != null ? watching_stack.copy() : container1.getItem(getSlotIndex()).copy();
|
||||
container1.startIgnore();
|
||||
container1.setItem(getSlotIndex(), p_40240_);
|
||||
container1.stopIgnore();
|
||||
container1.setChanged(getSlotIndex(), p_40240_, old);
|
||||
} else {
|
||||
super.set(p_40240_);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTake(Player p_150645_, ItemStack p_150646_) {
|
||||
if (container instanceof MatteryContainer container1) {
|
||||
ItemStack old = watching_stack != null ? watching_stack.copy() : last_stack.copy();
|
||||
container1.setChanged(getSlotIndex(), p_150646_.copy(), old);
|
||||
last_stack = ItemStack.EMPTY;
|
||||
} else {
|
||||
super.onTake(p_150645_, p_150646_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ import net.minecraftforge.fmllegacy.network.NetworkRegistry;
|
||||
import net.minecraftforge.fmllegacy.network.PacketDistributor;
|
||||
import net.minecraftforge.fmllegacy.network.simple.SimpleChannel;
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
|
||||
import ru.dbotthepony.mc.otm.item.ItemPortableCondensationDrive;
|
||||
import ru.dbotthepony.mc.otm.menu.DriveViewerMenu;
|
||||
import ru.dbotthepony.mc.otm.menu.data.*;
|
||||
import ru.dbotthepony.mc.otm.network.android.*;
|
||||
|
||||
import java.util.Optional;
|
||||
@ -26,6 +26,14 @@ public class MatteryNetworking {
|
||||
);
|
||||
|
||||
public static void send(ServerPlayer ply, Object ...messages) {
|
||||
if (ply == null) {
|
||||
for (var message : messages) {
|
||||
CHANNEL.sendToServer(message);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var supplier = PacketDistributor.PLAYER.with(() -> ply);
|
||||
|
||||
for (var message : messages) {
|
||||
@ -33,12 +41,6 @@ public class MatteryNetworking {
|
||||
}
|
||||
}
|
||||
|
||||
public static void send(Object ...messages) {
|
||||
for (var message : messages) {
|
||||
CHANNEL.sendToServer(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void register() {
|
||||
CHANNEL.registerMessage(
|
||||
next_network_id++,
|
||||
@ -150,46 +152,46 @@ public class MatteryNetworking {
|
||||
|
||||
CHANNEL.registerMessage(
|
||||
next_network_id++,
|
||||
DriveViewerMenu.ClearPacket.class,
|
||||
DriveViewerMenu.ClearPacket::write,
|
||||
DriveViewerMenu.ClearPacket::read,
|
||||
DriveViewerMenu.ClearPacket::play,
|
||||
ClearPacket.class,
|
||||
ClearPacket::write,
|
||||
ClearPacket::read,
|
||||
ClearPacket::play,
|
||||
Optional.of(NetworkDirection.PLAY_TO_CLIENT)
|
||||
);
|
||||
|
||||
CHANNEL.registerMessage(
|
||||
next_network_id++,
|
||||
DriveViewerMenu.StackAddPacket.class,
|
||||
DriveViewerMenu.StackAddPacket::write,
|
||||
DriveViewerMenu.StackAddPacket::read,
|
||||
DriveViewerMenu.StackAddPacket::play,
|
||||
StackAddPacket.class,
|
||||
StackAddPacket::write,
|
||||
StackAddPacket::read,
|
||||
StackAddPacket::play,
|
||||
Optional.of(NetworkDirection.PLAY_TO_CLIENT)
|
||||
);
|
||||
|
||||
CHANNEL.registerMessage(
|
||||
next_network_id++,
|
||||
DriveViewerMenu.StackChangePacket.class,
|
||||
DriveViewerMenu.StackChangePacket::write,
|
||||
DriveViewerMenu.StackChangePacket::read,
|
||||
DriveViewerMenu.StackChangePacket::play,
|
||||
StackChangePacket.class,
|
||||
StackChangePacket::write,
|
||||
StackChangePacket::read,
|
||||
StackChangePacket::play,
|
||||
Optional.of(NetworkDirection.PLAY_TO_CLIENT)
|
||||
);
|
||||
|
||||
CHANNEL.registerMessage(
|
||||
next_network_id++,
|
||||
DriveViewerMenu.StackRemovePacket.class,
|
||||
DriveViewerMenu.StackRemovePacket::write,
|
||||
DriveViewerMenu.StackRemovePacket::read,
|
||||
DriveViewerMenu.StackRemovePacket::play,
|
||||
StackRemovePacket.class,
|
||||
StackRemovePacket::write,
|
||||
StackRemovePacket::read,
|
||||
StackRemovePacket::play,
|
||||
Optional.of(NetworkDirection.PLAY_TO_CLIENT)
|
||||
);
|
||||
|
||||
CHANNEL.registerMessage(
|
||||
next_network_id++,
|
||||
DriveViewerMenu.InteractPacket.class,
|
||||
DriveViewerMenu.InteractPacket::write,
|
||||
DriveViewerMenu.InteractPacket::read,
|
||||
DriveViewerMenu.InteractPacket::play,
|
||||
InteractPacket.class,
|
||||
InteractPacket::write,
|
||||
InteractPacket::read,
|
||||
InteractPacket::play,
|
||||
Optional.of(NetworkDirection.PLAY_TO_SERVER)
|
||||
);
|
||||
|
||||
|
@ -0,0 +1,12 @@
|
||||
package ru.dbotthepony.mc.otm.storage;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.util.List;
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public interface IStorageComponent<T extends IStorageObject> extends IStorageView<T>, IStorageConsumer<T> {
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package ru.dbotthepony.mc.otm.storage;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public interface IStorageConsumer<T extends IStorageObject> extends IStorageIdentity<T> {
|
||||
T insertObject(T obj, boolean simulate);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package ru.dbotthepony.mc.otm.storage;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public interface IStorageIdentity<T extends IStorageObject> {
|
||||
Class<T> storageIdentity();
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package ru.dbotthepony.mc.otm.storage;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.UUID;
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public interface IStorageListener<T extends IStorageObject> {
|
||||
void addObject(T stack, UUID id, IStorageView<T> provider);
|
||||
void changeObject(UUID id, BigDecimal new_count);
|
||||
void removeObject(UUID id);
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package ru.dbotthepony.mc.otm.storage;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public interface IStorageObject {
|
||||
IStorageObject copy();
|
||||
|
||||
void setCount(BigDecimal value);
|
||||
BigDecimal getCount();
|
||||
|
||||
boolean isEmpty();
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package ru.dbotthepony.mc.otm.storage;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public interface IStorageTrigger<T extends IStorageObject> extends IStorageIdentity<T> {
|
||||
boolean addListener(IStorageListener<T> listener);
|
||||
boolean removeListener(IStorageListener<T> listener);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package ru.dbotthepony.mc.otm.storage;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface IStorageTuple<T extends IStorageObject> {
|
||||
UUID id();
|
||||
T object();
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package ru.dbotthepony.mc.otm.storage;
|
||||
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public interface IStorageView<T extends IStorageObject> extends IStorageTrigger<T> {
|
||||
/**
|
||||
* @param id identifier of object
|
||||
* @return stored object (not a copy). Do not edit it.
|
||||
*/
|
||||
T getStoredObject(UUID id);
|
||||
|
||||
/**
|
||||
* @param id identifier of object to extract
|
||||
* @param amount amount of units to extract
|
||||
* @param simulate whenever to simulate the action or not
|
||||
* @return copy of object, with amount of units actually extracted
|
||||
*/
|
||||
T extractObject(UUID id, BigDecimal amount, boolean simulate);
|
||||
|
||||
/**
|
||||
* Designed for views, for extraction with less computation overhead caused by
|
||||
* copying object extracted
|
||||
*
|
||||
* @param id identifier of object to extract
|
||||
* @param amount desired amount to extract
|
||||
* @param simulate whenever to simulate the action or not
|
||||
* @return amount extracted
|
||||
*/
|
||||
default BigDecimal extractObjectCount(UUID id, BigDecimal amount, boolean simulate) {
|
||||
return extractObject(id, amount, simulate).getCount();
|
||||
}
|
||||
|
||||
List<IStorageTuple<T>> getStorageObjects();
|
||||
|
||||
default boolean addListenerAuto(IStorageListener<T> listener) {
|
||||
if (addListener(listener)) {
|
||||
for (var stack : getStorageObjects()) {
|
||||
listener.addObject(stack.object(), stack.id(), this);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean removeListenerAuto(IStorageListener<T> listener) {
|
||||
if (removeListener(listener)) {
|
||||
for (var stack : getStorageObjects()) {
|
||||
listener.removeObject(stack.id());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package ru.dbotthepony.mc.otm.storage;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public record ItemStackObject(ItemStack stack) implements IStorageObject {
|
||||
public static final ItemStackObject EMPTY = new ItemStackObject(ItemStack.EMPTY);
|
||||
|
||||
@Override
|
||||
public IStorageObject copy() {
|
||||
return new ItemStackObject(stack.copy());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCount(BigDecimal value) {
|
||||
stack.setCount(Math.max(value.intValue(), 0));
|
||||
}
|
||||
|
||||
public void setCount(int value) {
|
||||
stack.setCount(Math.max(value, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getCount() {
|
||||
return new BigDecimal(stack.getCount());
|
||||
}
|
||||
|
||||
public int getCountInt() {
|
||||
return stack.getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return stack.isEmpty();
|
||||
}
|
||||
}
|
221
src/main/java/ru/dbotthepony/mc/otm/storage/StorageGrid.java
Normal file
221
src/main/java/ru/dbotthepony/mc/otm/storage/StorageGrid.java
Normal file
@ -0,0 +1,221 @@
|
||||
package ru.dbotthepony.mc.otm.storage;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
|
||||
import ru.dbotthepony.mc.otm.capability.IStorageGridCell;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public class StorageGrid {
|
||||
public final StorageItemView global_item_view = new StorageItemView();
|
||||
private final HashSet<IStorageGridCell> cells = new HashSet<>();
|
||||
|
||||
private final HashMap<Class<? extends IStorageObject>, IStorageView<? extends IStorageObject>> views = new HashMap<>();
|
||||
private final HashMap<Class<? extends IStorageObject>, ArrayList<IStorageConsumer<? extends IStorageObject>>> consumers = new HashMap<>();
|
||||
private final HashMap<Class<? extends IStorageObject>, IStorageComponent<? extends IStorageObject>> virtual_components = new HashMap<>();
|
||||
|
||||
public StorageGrid() {
|
||||
views.put(ItemStackObject.class, global_item_view);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends IStorageObject> T insertObject(Class<T> type, T object, boolean simulate) {
|
||||
var leftover = object;
|
||||
|
||||
for (var consumer : consumers.computeIfAbsent(type, (k) -> new ArrayList<>())) {
|
||||
leftover = ((IStorageConsumer<T>) consumer).insertObject(leftover, simulate);
|
||||
|
||||
if (leftover.isEmpty()) {
|
||||
return leftover;
|
||||
}
|
||||
}
|
||||
|
||||
return leftover;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type Class, representing identity of stored object
|
||||
* @param <T> The identity itself
|
||||
* @return a virtual IStorageComponent<T>, or null if storage grid contain no view for provided type
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
public <T extends IStorageObject> IStorageComponent<T> getVirtualComponent(final Class<T> type) {
|
||||
return (IStorageComponent<T>) virtual_components.computeIfAbsent(type, (k) -> {
|
||||
final var get_view = (IStorageView<T>) views.get(type);
|
||||
|
||||
if (get_view == null)
|
||||
return null;
|
||||
|
||||
return new IStorageComponent<T>() {
|
||||
@Override
|
||||
public T insertObject(T obj, boolean simulate) {
|
||||
return StorageGrid.this.insertObject(type, obj, simulate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getStoredObject(UUID id) {
|
||||
return get_view.getStoredObject(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T extractObject(UUID id, BigDecimal amount, boolean simulate) {
|
||||
return get_view.extractObject(id, amount, simulate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IStorageTuple<T>> getStorageObjects() {
|
||||
return get_view.getStorageObjects();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> storageIdentity() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addListener(IStorageListener<T> listener) {
|
||||
return get_view.addListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeListener(IStorageListener<T> listener) {
|
||||
return get_view.removeListener(listener);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return cells.size();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends IStorageObject> void add(IStorageIdentity<T> identity) {
|
||||
final var view = (IStorageView<T>) views.get(identity.storageIdentity());
|
||||
|
||||
if (view != null && identity instanceof IStorageView provider) {
|
||||
((IStorageView<T>) provider).addListenerAuto((IStorageListener<T>) view);
|
||||
} else if (view != null && identity instanceof IStorageTrigger provider) {
|
||||
((IStorageTrigger<T>) provider).addListener((IStorageListener<T>) view);
|
||||
}
|
||||
|
||||
if (identity instanceof IStorageConsumer provider) {
|
||||
consumers.computeIfAbsent(identity.storageIdentity(), (k) -> new ArrayList<>()).add(provider);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean add(LazyOptional<IStorageGridCell> cell) {
|
||||
if (!cell.isPresent())
|
||||
return false;
|
||||
|
||||
var resolved = cell.resolve();
|
||||
|
||||
if (resolved.isPresent()) {
|
||||
final var value = resolved.get();
|
||||
|
||||
if (add(value)) {
|
||||
cell.addListener((lazy) -> remove(value));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean add(IStorageGridCell cell) {
|
||||
if (cells.add(cell)) {
|
||||
cell.setStorageGrid(this);
|
||||
|
||||
for (var identity : cell.getComponents()) {
|
||||
add(identity);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends IStorageObject> void remove(IStorageIdentity<T> identity) {
|
||||
final var view = (IStorageView<T>) views.get(identity.storageIdentity());
|
||||
|
||||
if (view != null && identity instanceof IStorageView provider) {
|
||||
((IStorageView<T>) provider).removeListenerAuto((IStorageListener<T>) view);
|
||||
} else if (view != null && identity instanceof IStorageTrigger provider) {
|
||||
((IStorageTrigger<T>) provider).removeListener((IStorageListener<T>) view);
|
||||
}
|
||||
|
||||
if (identity instanceof IStorageConsumer provider) {
|
||||
consumers.computeIfAbsent(identity.storageIdentity(), (k) -> new ArrayList<>()).remove(provider);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean remove(IStorageGridCell cell) {
|
||||
if (cells.remove(cell)) {
|
||||
cell.setStorageGrid(null);
|
||||
|
||||
for (var identity : cell.getComponents()) {
|
||||
remove(identity);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void detach(IStorageGridCell cell) {
|
||||
if (cells.contains(cell)) {
|
||||
for (var identity : cell.getComponents()) {
|
||||
remove(identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void attach(IStorageGridCell cell) {
|
||||
if (cells.contains(cell)) {
|
||||
for (var identity : cell.getComponents()) {
|
||||
add(identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public StorageGrid merge(StorageGrid other) {
|
||||
if (other == this)
|
||||
return this;
|
||||
|
||||
if (size() < other.size()) {
|
||||
var copy = List.copyOf(cells);
|
||||
|
||||
for (var cell : copy) {
|
||||
remove(cell);
|
||||
other.add(cell);
|
||||
}
|
||||
|
||||
return other;
|
||||
} else {
|
||||
var copy = List.copyOf(other.cells);
|
||||
|
||||
for (var cell : copy) {
|
||||
other.remove(cell);
|
||||
add(cell);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public static void scheduleDiscoverNeighbours(IStorageGridCell cell, Level level, BlockPos pos) {
|
||||
OverdriveThatMatters.tickUntil(level, () -> !cell.isValidStorageCell() || cell.connectOrCreateStorageGrid(level, pos, true));
|
||||
}
|
||||
}
|
278
src/main/java/ru/dbotthepony/mc/otm/storage/StorageItemView.java
Normal file
278
src/main/java/ru/dbotthepony/mc/otm/storage/StorageItemView.java
Normal file
@ -0,0 +1,278 @@
|
||||
package ru.dbotthepony.mc.otm.storage;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public class StorageItemView implements IStorageListener<ItemStackObject>, IStorageView<ItemStackObject> {
|
||||
public record LocalTuple(ItemStackObject object, UUID id, List<RemoteTuple> tuples) implements IStorageTuple<ItemStackObject> {
|
||||
public static final LocalTuple EMPTY = new LocalTuple(ItemStackObject.EMPTY, new UUID(0, 0), List.of());
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof LocalTuple tuple && tuple.id.equals(id) || obj instanceof UUID id && this.id.equals(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<ItemStackObject> storageIdentity() {
|
||||
return ItemStackObject.class;
|
||||
}
|
||||
|
||||
public record RemoteTuple(ItemStack stack, UUID remote_id, IStorageView<ItemStackObject> provider, LocalTuple local) {
|
||||
public static final RemoteTuple EMPTY = new RemoteTuple(ItemStack.EMPTY, new UUID(0, 0), new IStorageView<>() {
|
||||
@Override
|
||||
public Class<ItemStackObject> storageIdentity() {
|
||||
return ItemStackObject.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addListener(IStorageListener<ItemStackObject> listener) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeListener(IStorageListener<ItemStackObject> listener) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStackObject getStoredObject(UUID id) {
|
||||
return ItemStackObject.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStackObject extractObject(UUID id, BigDecimal amount, boolean simulate) {
|
||||
return ItemStackObject.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IStorageTuple<ItemStackObject>> getStorageObjects() {
|
||||
return List.of();
|
||||
}
|
||||
}, LocalTuple.EMPTY);
|
||||
|
||||
public ItemStackObject extract(BigDecimal amount, boolean simulate) {
|
||||
return provider.extractObject(remote_id, amount, simulate);
|
||||
}
|
||||
|
||||
public BigDecimal extractCount(BigDecimal amount, boolean simulate) {
|
||||
return provider.extractObjectCount(remote_id, amount, simulate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof RemoteTuple tuple && tuple.remote_id.equals(remote_id) || obj instanceof UUID id && id.equals(remote_id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return remote_id.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
// удаленный UUID -> Кортеж
|
||||
private final HashMap<UUID, RemoteTuple> indexed_by_remote_uuid = new HashMap<>();
|
||||
|
||||
// локальный UUID -> Локальный кортеж
|
||||
private final HashMap<UUID, LocalTuple> indexed_by_local_uuid = new HashMap<>();
|
||||
|
||||
// Item -> Список Локальных кортежей
|
||||
private final HashMap<Item, ArrayList<LocalTuple>> indexed_by_item = new HashMap<>();
|
||||
|
||||
public List<ItemStack> getCopyRawItemList() {
|
||||
final var list = new ArrayList<ItemStack>(indexed_by_remote_uuid.size());
|
||||
|
||||
for (var state : indexed_by_remote_uuid.values())
|
||||
list.add(state.stack.copy());
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<ItemStack> getRawItemList() {
|
||||
final var list = new ArrayList<ItemStack>(indexed_by_remote_uuid.size());
|
||||
|
||||
for (var state : indexed_by_remote_uuid.values())
|
||||
list.add(state.stack);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IStorageTuple<ItemStackObject>> getStorageObjects() {
|
||||
int capacity = 0;
|
||||
|
||||
for (var list : indexed_by_item.values())
|
||||
capacity += list.size();
|
||||
|
||||
final var output = new ArrayList<IStorageTuple<ItemStackObject>>(capacity);
|
||||
|
||||
for (var listing : indexed_by_item.values())
|
||||
output.addAll(listing);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
public List<ItemStack> getCombinedItemList() {
|
||||
int capacity = 0;
|
||||
|
||||
for (var list : indexed_by_item.values())
|
||||
capacity += list.size();
|
||||
|
||||
final var output = new ArrayList<ItemStack>(capacity);
|
||||
|
||||
for (var listing : indexed_by_item.values())
|
||||
for (var combined : listing)
|
||||
output.add(combined.object.stack());
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addObject(ItemStackObject _stack, UUID id, IStorageView<ItemStackObject> provider) {
|
||||
if (indexed_by_remote_uuid.containsKey(id)) {
|
||||
throw new IllegalStateException("Already tracking tuple with id " + id);
|
||||
}
|
||||
|
||||
var stack = _stack.stack();
|
||||
|
||||
var items = indexed_by_item.computeIfAbsent(stack.getItem(), (k) -> new ArrayList<>());
|
||||
LocalTuple local_tuple = null;
|
||||
|
||||
for (var item : items) {
|
||||
if (ItemStack.tagMatches(item.object.stack(), stack)) {
|
||||
item.object.stack().grow(stack.getCount());
|
||||
local_tuple = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
boolean added = local_tuple == null;
|
||||
|
||||
if (added) {
|
||||
local_tuple = new LocalTuple((ItemStackObject) _stack.copy(), UUID.randomUUID(), new ArrayList<>(1));
|
||||
items.add(local_tuple);
|
||||
indexed_by_local_uuid.put(local_tuple.id, local_tuple);
|
||||
}
|
||||
|
||||
var tuple = new RemoteTuple(stack.copy(), id, provider, local_tuple);
|
||||
local_tuple.tuples.add(tuple);
|
||||
indexed_by_remote_uuid.put(id, tuple);
|
||||
|
||||
if (added) {
|
||||
for (var listener : listeners) {
|
||||
listener.addObject(local_tuple.object, local_tuple.id, this);
|
||||
}
|
||||
} else {
|
||||
for (var listener : listeners) {
|
||||
listener.changeObject(local_tuple.id, local_tuple.object.getCount());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeObject(UUID id, BigDecimal new_count) {
|
||||
assert new_count.compareTo(BigDecimal.ZERO) > 0;
|
||||
var tuple = indexed_by_remote_uuid.get(id);
|
||||
|
||||
if (tuple == null)
|
||||
throw new IllegalStateException("No such tuple with id " + id);
|
||||
|
||||
var delta = new_count.intValue() - tuple.stack.getCount();
|
||||
tuple.stack.setCount(new_count.intValue());
|
||||
tuple.local.object.stack().grow(delta);
|
||||
|
||||
for (var listener : listeners) {
|
||||
listener.changeObject(tuple.local.id, tuple.local.object.getCount());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeObject(UUID id) {
|
||||
var tuple = indexed_by_remote_uuid.get(id);
|
||||
|
||||
if (tuple == null)
|
||||
throw new IllegalStateException("No such tuple with id " + id);
|
||||
|
||||
var item = tuple.local.object.stack().getItem();
|
||||
tuple.local.object.stack().shrink(tuple.stack.getCount());
|
||||
tuple.local.tuples.remove(tuple);
|
||||
|
||||
indexed_by_remote_uuid.remove(id);
|
||||
|
||||
if (tuple.local.object.stack().getCount() <= 0 || tuple.local.tuples.size() == 0) {
|
||||
assert tuple.local.object.stack().getCount() == tuple.local.tuples.size();
|
||||
|
||||
indexed_by_local_uuid.remove(tuple.local.id);
|
||||
indexed_by_item.get(item).remove(tuple.local);
|
||||
|
||||
for (var listener : listeners) {
|
||||
listener.removeObject(tuple.local.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final Set<IStorageListener<ItemStackObject>> listeners = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public boolean addListener(IStorageListener<ItemStackObject> listener) {
|
||||
return listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeListener(IStorageListener<ItemStackObject> listener) {
|
||||
return listeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStackObject getStoredObject(UUID id) {
|
||||
return indexed_by_local_uuid.getOrDefault(id, LocalTuple.EMPTY).object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStackObject extractObject(UUID id, BigDecimal _amount, boolean simulate) {
|
||||
var tuple = indexed_by_local_uuid.get(id);
|
||||
|
||||
if (tuple == null)
|
||||
return ItemStackObject.EMPTY;
|
||||
|
||||
int amount = _amount.intValue();
|
||||
|
||||
if (amount == 0)
|
||||
return ItemStackObject.EMPTY;
|
||||
|
||||
if (amount == -1)
|
||||
amount = tuple.object.stack().getMaxStackSize();
|
||||
|
||||
int extract = Math.min(amount, tuple.object.stack().getCount());
|
||||
int extracted = 0;
|
||||
|
||||
var copy = tuple.object.stack().copy();
|
||||
|
||||
for (var remote_tuple : tuple.tuples) {
|
||||
extracted += remote_tuple.extractCount(new BigDecimal(extract - extracted), simulate).intValue();
|
||||
|
||||
if (extracted >= extract)
|
||||
break;
|
||||
}
|
||||
|
||||
if (extracted > 0) {
|
||||
copy.setCount(extracted);
|
||||
return new ItemStackObject(copy);
|
||||
}
|
||||
|
||||
return ItemStackObject.EMPTY;
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package ru.dbotthepony.mc.otm.storage;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public record StorageTuple<T extends IStorageObject>(UUID id, T object) implements IStorageTuple<T> {
|
||||
}
|
Loading…
Reference in New Issue
Block a user