Update drive viewer screen, move to PoweredVirtualComponent

This commit is contained in:
DBotThePony 2022-01-03 15:03:08 +07:00
parent 287238c2d1
commit d9ba74bc0f
Signed by: DBot
GPG Key ID: DCC23B5715498507
15 changed files with 892 additions and 1043 deletions

View File

@ -33,6 +33,7 @@ import ru.dbotthepony.mc.otm.matter.MatterRegistry;
import ru.dbotthepony.mc.otm.network.MatteryNetworking; import ru.dbotthepony.mc.otm.network.MatteryNetworking;
import ru.dbotthepony.mc.otm.storage.ItemStackWrapper; import ru.dbotthepony.mc.otm.storage.ItemStackWrapper;
import ru.dbotthepony.mc.otm.storage.StorageObjectRegistry; import ru.dbotthepony.mc.otm.storage.StorageObjectRegistry;
import ru.dbotthepony.mc.otm.storage.StorageObjectTuple;
import javax.annotation.ParametersAreNonnullByDefault; import javax.annotation.ParametersAreNonnullByDefault;
import java.util.ArrayList; import java.util.ArrayList;
@ -160,13 +161,15 @@ public class OverdriveThatMatters {
}; };
} }
public static StorageObjectTuple<ItemStackWrapper> ITEM_STORAGE;
private void setup(final FMLCommonSetupEvent event) { private void setup(final FMLCommonSetupEvent event) {
MatteryNetworking.register(); MatteryNetworking.register();
// LOGGER.info("Registered network"); // LOGGER.info("Registered network");
MatterRegistry.registerInitialItems(); MatterRegistry.registerInitialItems();
StorageObjectRegistry.register(ItemStackWrapper.class, ItemStackWrapper.EMPTY, new Fraction("3.125")); ITEM_STORAGE = StorageObjectRegistry.register(ItemStackWrapper.class, ItemStackWrapper.EMPTY, new Fraction("3.125"));
} }
private void setupClient(final FMLClientSetupEvent event) { private void setupClient(final FMLClientSetupEvent event) {

View File

@ -1,250 +0,0 @@
package ru.dbotthepony.mc.otm.client.screen;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.world.entity.player.Inventory;
import 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.network.MatteryNetworking;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
public class DriveViewerScreen extends MatteryScreen<DriveViewerMenu> {
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 DriveViewerScreen(DriveViewerMenu menu, Inventory inventory, Component title) {
super(menu, inventory, title);
}
@Nullable
@Override
protected FramePanel makeMainFrame() {
var frame = new FramePanel(this, null, 0, 0, FRAME_WIDTH, FRAME_HEIGHT, getTitle());
var view_panels = new ArrayList<EditablePanel>();
var settings_panels = new ArrayList<EditablePanel>();
var view_button = frame.addTab(FramePanel.FrameTabPosition.TOP);
var settings_button = frame.addTab(FramePanel.FrameTabPosition.TOP);
view_button.bindOnOpen(() -> {
for (var panel : view_panels) {
panel.setVisible(true);
}
});
view_button.bindOnClose(() -> {
for (var panel : view_panels) {
panel.setVisible(false);
}
});
settings_button.bindOnOpen(() -> {
for (var panel : settings_panels) {
panel.setVisible(true);
}
});
settings_button.bindOnClose(() -> {
for (var panel : settings_panels) {
panel.setVisible(false);
}
});
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;
});
view_panels.add(grid);
view_panels.add(scroll_bar);
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;
}
};
}
var dock_left = new FlexGridPanel(this, frame, 0, 0, 90, 0);
dock_left.setDock(Dock.LEFT);
dock_left.setDockMargin(4, 0, 4, 0);
var grid_filter = new FlexGridPanel(this, frame);
grid_filter.setDock(Dock.FILL);
settings_panels.add(dock_left);
settings_panels.add(grid_filter);
for (int i = 0; i < ItemPortableCondensationDrive.FilterSettings.MAX_FILTERS; i++) {
final int index = i;
new AbstractSlotPanel(this, grid_filter, 0, 0) {
@Nonnull
@Override
protected ItemStack getItemStack() {
var filter = menu.getFilter();
if (filter == null)
return ItemStack.EMPTY;
return filter.items[index];
}
private boolean clicking = false;
@Override
protected boolean mouseClickedInner(double mouse_x, double mouse_y, int flag) {
clicking = true;
return true;
}
@Override
protected boolean mouseReleasedInner(double mouse_x, double mouse_y, int flag) {
if (clicking)
MatteryNetworking.send(null, new DriveViewerMenu.FilterSetPacket(menu.containerId, index, menu.getCarried()));
clicking = false;
return true;
}
};
}
final var no = new TranslatableComponent("otm.filter.no");
final var yes = new TranslatableComponent("otm.filter.yes");
var match_nbt = new ButtonPanel(this, dock_left, 0, 0, 90, 20, new TranslatableComponent("otm.filter.match_nbt", no)) {
@Override
public void tick() {
super.tick();
var filter = menu.getFilter();
if (filter != null) {
getOrCreateWidget().setMessage(new TranslatableComponent("otm.filter.match_nbt", filter.matchNbt ? yes : no));
getOrCreateWidget().active = !isWidgetDisabled();
} else {
getOrCreateWidget().active = false;
}
}
@Override
protected void onPress() {
super.onPress();
var filter = menu.getFilter();
if (filter != null) {
MatteryNetworking.send(null, new DriveViewerMenu.FilterSwitchPacket(menu.containerId, DriveViewerMenu.FilterSwitch.MATCH_NBT, !filter.matchNbt));
disableFor(20);
}
}
};
var match_tag = new ButtonPanel(this, dock_left, 0, 0, 90, 20, new TranslatableComponent("otm.filter.match_tag", no)) {
@Override
public void tick() {
super.tick();
var filter = menu.getFilter();
if (filter != null) {
getOrCreateWidget().setMessage(new TranslatableComponent("otm.filter.match_tag", filter.matchTag ? yes : no));
getOrCreateWidget().active = !isWidgetDisabled();
} else {
getOrCreateWidget().active = false;
}
}
@Override
protected void onPress() {
super.onPress();
var filter = menu.getFilter();
if (filter != null) {
MatteryNetworking.send(null, new DriveViewerMenu.FilterSwitchPacket(menu.containerId, DriveViewerMenu.FilterSwitch.MATCH_TAG, !filter.matchTag));
disableFor(20);
}
}
};
var blacklist = new ButtonPanel(this, dock_left, 0, 0, 90, 20, new TranslatableComponent("otm.filter.blacklist", no)) {
@Override
public void tick() {
super.tick();
var filter = menu.getFilter();
if (filter != null) {
getOrCreateWidget().setMessage(new TranslatableComponent("otm.filter.blacklist", filter.isBlacklist ? yes : no));
getOrCreateWidget().active = !isWidgetDisabled();
} else {
getOrCreateWidget().active = false;
}
}
@Override
protected void onPress() {
super.onPress();
var filter = menu.getFilter();
if (filter != null) {
MatteryNetworking.send(null, new DriveViewerMenu.FilterSwitchPacket(menu.containerId, DriveViewerMenu.FilterSwitch.BLACKLIST, !filter.isBlacklist));
disableFor(20);
}
}
};
match_nbt.setDockMargin(0, 4, 0, 0);
match_tag.setDockMargin(0, 4, 0, 0);
blacklist.setDockMargin(0, 4, 0, 0);
for (var panel : settings_panels) {
panel.setVisible(false);
}
return frame;
}
}

View File

@ -115,11 +115,11 @@ public abstract class MatteryScreen<T extends MatteryMenu> extends AbstractConta
this.menu = menu; this.menu = menu;
playerInventoryTitle = inventory.getDisplayName(); playerInventoryTitle = inventory.getDisplayName();
if (menu.inventory_slots.size() != 0) { if (menu.inventorySlots.size() != 0) {
inventory_frame = new FramePanel(this, null, 0, 0, INVENTORY_FRAME_WIDTH, INVENTORY_FRAME_HEIGHT, inventory.getDisplayName()); inventory_frame = new FramePanel(this, null, 0, 0, INVENTORY_FRAME_WIDTH, INVENTORY_FRAME_HEIGHT, inventory.getDisplayName());
panels.add(inventory_frame); panels.add(inventory_frame);
for (var slot : menu.inventory_slots) { for (var slot : menu.inventorySlots) {
new SlotPanel<>( new SlotPanel<>(
this, this,
inventory_frame, inventory_frame,
@ -359,10 +359,6 @@ public abstract class MatteryScreen<T extends MatteryMenu> extends AbstractConta
if (main_frame != null) { if (main_frame != null) {
addPanel(main_frame); addPanel(main_frame);
for (var slot : menu.main_slots) {
new SlotPanel<>(this, main_frame, slot);
}
} }
movePanels(); movePanels();

View File

@ -1,266 +0,0 @@
package ru.dbotthepony.mc.otm.menu;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.network.NetworkEvent;
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.IMatteryDrive;
import ru.dbotthepony.mc.otm.item.ItemPortableCondensationDrive;
import ru.dbotthepony.mc.otm.menu.data.INetworkedItemViewSupplier;
import ru.dbotthepony.mc.otm.menu.data.NetworkedItemView;
import ru.dbotthepony.mc.otm.storage.ItemStackWrapper;
import javax.annotation.Nullable;
import java.util.function.Supplier;
public class DriveViewerMenu extends PoweredMatteryMenu implements INetworkedItemViewSupplier {
public final NetworkedItemView view;
public MatterySlot drive_slot;
public IMatteryDrive<ItemStackWrapper> last_drive;
@Override
public NetworkedItemView getNetworkedItemView() {
return view;
}
public DriveViewerMenu(int containerID, Inventory inventory) {
this(containerID, inventory, null);
}
public DriveViewerMenu(int containerID, Inventory inventory, @Nullable BlockEntityDriveViewer tile) {
super(Registry.Menus.DRIVE_VIEWER, containerID, inventory, tile);
var container = tile != null ? tile.drive_slot : new SimpleContainer(1);
drive_slot = new MatterySlot(container, 0) {
@Override
public boolean mayPlace(ItemStack stack) {
return stack.getCapability(MatteryCapability.DRIVE).isPresent();
}
};
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();
}
@Override
@SuppressWarnings("unchecked")
public void broadcastChanges() {
super.broadcastChanges();
if (tile != null) {
var get = ((BlockEntityDriveViewer) tile).drive_slot.getItem(0);
if (get.isEmpty()) {
last_drive = null;
} else {
var get_cap = get.getCapability(MatteryCapability.DRIVE).resolve();
if (get_cap.isEmpty() || get_cap.get().storageIdentity() != ItemStackWrapper.class) {
last_drive = null;
} else {
last_drive = (IMatteryDrive<ItemStackWrapper>) get_cap.get();
}
}
view.setComponent(last_drive);
view.network();
}
}
@Override
protected int getWorkingSlotStart() {
return 0;
}
@Override
protected int getWorkingSlotEnd() {
return 2;
}
@Override
public void removed(Player p_38940_) {
super.removed(p_38940_);
if (last_drive != null) {
last_drive.removeListener(view);
view.clear();
}
}
@Override
public ItemStack quickMoveStack(Player ply, int slot_index) {
var slot = slots.get(slot_index);
var item = slot.getItem();
if (item.isEmpty() || item.getCapability(MatteryCapability.DRIVE).isPresent() || item.getCapability(CapabilityEnergy.ENERGY).isPresent())
return super.quickMoveStack(ply, slot_index);
if (last_drive == null || tile == null)
return ItemStack.EMPTY;
var tile = (BlockEntityDriveViewer) this.tile;
int amount = tile.getIOItemCount(item.getCount(), true);
if (amount == 0)
return ItemStack.EMPTY;
if (amount == item.getCount()) {
var remaining = last_drive.insertStack(new ItemStackWrapper(item), false);
if (remaining.getCount().toInt() == item.getCount())
return ItemStack.EMPTY;
if (remaining.isEmpty()) {
var copy = item.copy();
slot.set(ItemStack.EMPTY);
tile.getIOItemCount(item.getCount(), false);
return copy;
}
var copy = item.copy();
tile.getIOItemCount(item.getCount() - remaining.getCount().toInt(), false);
item.shrink(remaining.getCount().toInt());
slot.setChanged();
return copy;
}
var copy_insert = item.copy();
copy_insert.setCount(amount);
var remaining = last_drive.insertStack(new ItemStackWrapper(copy_insert), false);
if (remaining.getCount().toInt() == copy_insert.getCount())
return ItemStack.EMPTY;
var copy = item.copy();
tile.getIOItemCount(amount - remaining.getCount().toInt(), false);
item.shrink(amount - remaining.getCount().toInt());
slot.setChanged();
return copy;
}
public enum FilterSwitch {
MATCH_NBT,
MATCH_TAG,
BLACKLIST
}
public ItemPortableCondensationDrive.FilterSettings getFilter() {
if (drive_slot.getItem().isEmpty())
return null;
if (drive_slot.getItem().getItem() instanceof ItemPortableCondensationDrive item)
return item.getFilterSettings(drive_slot.getItem());
return null;
}
public record FilterSetPacket(int id, int slot, ItemStack value) {
public void write(FriendlyByteBuf buffer) {
buffer.writeInt(id);
buffer.writeInt(slot);
buffer.writeItem(value);
}
public static FilterSetPacket read(FriendlyByteBuf buffer) {
return new FilterSetPacket(buffer.readInt(), buffer.readInt(), buffer.readItem());
}
public void play(Supplier<NetworkEvent.Context> context) {
context.get().setPacketHandled(true);
if (slot < 0 || slot >= ItemPortableCondensationDrive.FilterSettings.MAX_FILTERS)
return;
if (value.getCount() > 1)
value.setCount(1);
context.get().enqueueWork(() -> {
var ply = context.get().getSender();
if (ply.containerMenu instanceof DriveViewerMenu menu && menu.containerId == id) {
if (menu.drive_slot.getItem().isEmpty())
return;
if (menu.drive_slot.getItem().getItem() instanceof ItemPortableCondensationDrive drive) {
var filter = drive.getFilterSettings(menu.drive_slot.getItem());
filter.items[slot] = value;
filter.serializeNBT(menu.drive_slot.getItem());
}
}
});
}
}
public record FilterSwitchPacket(int id, FilterSwitch type, boolean value) {
public void write(FriendlyByteBuf buffer) {
buffer.writeInt(id);
buffer.writeEnum(type);
buffer.writeBoolean(value);
}
public static FilterSwitchPacket read(FriendlyByteBuf buffer) {
return new FilterSwitchPacket(buffer.readInt(), buffer.readEnum(FilterSwitch.class), buffer.readBoolean());
}
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 && menu.containerId == id) {
var settings = menu.getFilter();
if (settings == null)
return;
switch (type) {
case MATCH_NBT -> {
settings.matchNbt = value;
}
case MATCH_TAG -> {
settings.matchTag = value;
}
case BLACKLIST -> {
settings.isBlacklist = value;
}
}
settings.serializeNBT(menu.drive_slot.getItem());
}
});
}
}
}

View File

@ -1,293 +0,0 @@
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.network.PacketDistributor;
import ru.dbotthepony.mc.otm.core.Fraction;
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.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<ItemStackWrapper> {
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<ItemStackWrapper> 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<ItemStackWrapper> provider) {
if (provider == this.provider)
return;
if (this.provider != null)
this.provider.removeListenerAuto(this);
this.provider = provider;
if (provider != null)
provider.addListenerAuto(this);
}
public void removed() {
if (this.provider != null)
this.provider.removeListenerAuto(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(ItemStackWrapper stack, UUID id, IStorageView<ItemStackWrapper> provider) {
addObject(stack.stack(), id);
}
@Override
public void changeObject(UUID id, Fraction newCount) {
changeObject(id, newCount.toInt());
}
@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.extractStack(get_state.id_upstream(), new Fraction(amount), true);
if (!extracted.isEmpty()) {
var move = menu.quickMoveToInventory(extracted.stack(), false);
if (move.remaining().getCount() != extracted.stack().getCount()) {
provider.extractStack(get_state.id_upstream(), new Fraction(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.insertStack(new ItemStackWrapper(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.insertStack(new ItemStackWrapper(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.insertStack(new ItemStackWrapper(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.extractStack(get_state.id_upstream(), new Fraction(amount), false);
doneIOAmount(extracted.getCountInt());
menu.setCarried(extracted.stack());
MatteryNetworking.send((ServerPlayer) ply, new SetCarriedPacket(menu.getCarried()));
menu.setRemoteCarried(menu.getCarried().copy());
}
}
}

View File

@ -1,45 +1,42 @@
package ru.dbotthepony.mc.otm.block; package ru.dbotthepony.mc.otm.block
import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.BlockPos
import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level
import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityTicker
import net.minecraft.world.level.block.entity.BlockEntityTicker; import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.BooleanProperty
import net.minecraft.world.level.block.state.properties.BooleanProperty; import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.Registry; import ru.dbotthepony.mc.otm.block.entity.BlockEntityDriveViewer
import ru.dbotthepony.mc.otm.block.entity.BlockEntityDriveViewer; import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import javax.annotation.Nullable; class BlockDriveViewer : BlockMatteryRotatable(), EntityBlock {
import javax.annotation.ParametersAreNonnullByDefault; override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity {
return BlockEntityDriveViewer(blockPos, blockState)
import static ru.dbotthepony.mc.otm.block.entity.worker.WorkerState.SEMI_WORKER_STATE;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public class BlockDriveViewer extends BlockMatteryRotatable implements EntityBlock {
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
return new BlockEntityDriveViewer(blockPos, blockState);
} }
@Nullable override fun <T : BlockEntity> getTicker(
@Override p_153212_: Level,
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level p_153212_, BlockState p_153213_, BlockEntityType<T> p_153214_) { p_153213_: BlockState,
return p_153212_.isClientSide || p_153214_ != Registry.BlockEntities.DRIVE_VIEWER ? null : BlockEntityDriveViewer::ticker; p_153214_: BlockEntityType<T>
): BlockEntityTicker<T>? {
if (p_153212_.isClientSide || p_153214_ !== Registry.BlockEntities.DRIVE_VIEWER)
return null
return BlockEntityTicker { _, _, _, tile -> if (tile is BlockEntityDriveViewer) tile.tick() }
} }
public static final BooleanProperty DRIVE_PRESENT = BooleanProperty.create("drive"); override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
super.createBlockStateDefinition(builder)
builder.add(WorkerState.SEMI_WORKER_STATE)
builder.add(DRIVE_PRESENT)
}
@Override companion object {
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) { val DRIVE_PRESENT = BooleanProperty.create("drive")
super.createBlockStateDefinition(builder);
builder.add(SEMI_WORKER_STATE);
builder.add(DRIVE_PRESENT);
} }
} }

View File

@ -1,137 +1,113 @@
package ru.dbotthepony.mc.otm.block.entity; package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.MethodsReturnNonnullByDefault
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component
import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.BlockState; import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.OverdriveThatMatters; import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.Registry; import ru.dbotthepony.mc.otm.block.BlockDriveViewer
import ru.dbotthepony.mc.otm.block.BlockDriveViewer; import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState; import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.MatteryCapability; import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage
import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage; import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.container.MatteryContainer; import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.core.Fraction; import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.menu.DriveViewerMenu; import ru.dbotthepony.mc.otm.menu.DriveViewerMenu
import ru.dbotthepony.mc.otm.set
import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault
import javax.annotation.ParametersAreNonnullByDefault;
@MethodsReturnNonnullByDefault @MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
public class BlockEntityDriveViewer extends BlockEntityMatteryPowered { class BlockEntityDriveViewer(p_155229_: BlockPos, p_155230_: BlockState) : BlockEntityMatteryPowered(Registry.BlockEntities.DRIVE_VIEWER, p_155229_, p_155230_) {
public static final Fraction MTE_PER_OPERATION = new Fraction("3.125"); override fun setChanged() {
super.setChanged()
public boolean canIOItems() { val level = level
return energy.getBatteryLevel().compareTo(MTE_PER_OPERATION) >= 0;
}
private void updateState(Level level) { if (level != null) {
if (isRemoved()) OverdriveThatMatters.tickOnceSelf(level) {
return; if (isRemoved) return@tickOnceSelf
var state = getBlockState(); var state = blockState
if (drive_slot.getItem(0).getCapability(MatteryCapability.DRIVE).isPresent() && canIOItems()) { if (drive_slot.getItem(0).getCapability(MatteryCapability.DRIVE).isPresent && energy.batteryLevel >= OverdriveThatMatters.ITEM_STORAGE.energyPerOperation()) {
state = state.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.WORKING); state = state.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.WORKING)
} else { } else {
state = state.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE); state = state.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE)
} }
if (state != getBlockState()) { if (state !== blockState) {
level.setBlock(getBlockPos(), state, Block.UPDATE_CLIENTS); it.setBlock(blockPos, state, Block.UPDATE_CLIENTS)
}
}
} }
} }
@Override @JvmField
public void setChanged() { val drive_slot: MatteryContainer = object : MatteryContainer(this::setChanged, 1) {
super.setChanged(); override fun setChanged(slot: Int, new_state: ItemStack, old_state: ItemStack) {
super.setChanged(slot, new_state, old_state)
if (level != null) val level = level
OverdriveThatMatters.tickOnceSelf(level, this::updateState); if (level != null) {
} OverdriveThatMatters.tickOnceSelf(level) {
if (!isRemoved) {
var state = blockState
public int getIOItemCount(int desired, boolean simulate) { if (new_state.getCapability(MatteryCapability.DRIVE).isPresent) {
if (!canIOItems()) state = state.setValue(BlockDriveViewer.DRIVE_PRESENT, true)
return 0;
var extracted = energy.extractEnergyInner(MTE_PER_OPERATION.times(desired), true);
var modulo = extracted.rem(MTE_PER_OPERATION);
if (simulate)
return modulo.toInt();
energy.extractEnergyInner(modulo.times(MTE_PER_OPERATION), false);
return modulo.toInt();
}
public BlockEntityDriveViewer(BlockPos p_155229_, BlockState p_155230_) {
super(Registry.BlockEntities.DRIVE_VIEWER, p_155229_, p_155230_);
energy = new MatteryMachineEnergyStorage(this, MatteryMachineEnergyStorage.MachineType.WORKER, new Fraction(30_000));
}
private static final TranslatableComponent NAME = new TranslatableComponent("block.overdrive_that_matters.drive_viewer");
public final MatteryContainer drive_slot = new MatteryContainer(this::setChanged, 1) {
@Override
public void setChanged(int slot, ItemStack new_state, ItemStack old_state) {
super.setChanged(slot, new_state, old_state);
if (level != null)
OverdriveThatMatters.tickOnceSelf(level, (level) -> {
if (!isRemoved()) {
var state = getBlockState();
if (new_state.getCapability(MatteryCapability.DRIVE).isPresent()) {
state = state.setValue(BlockDriveViewer.DRIVE_PRESENT, true);
} else { } else {
state = state.setValue(BlockDriveViewer.DRIVE_PRESENT, false); state = state.setValue(BlockDriveViewer.DRIVE_PRESENT, false)
} }
if (state != getBlockState()) { if (state !== blockState) {
level.setBlock(getBlockPos(), state, Block.UPDATE_CLIENTS); level.setBlock(blockPos, state, Block.UPDATE_CLIENTS)
} }
} }
}); }
}
} }
};
@Override
protected Component getDefaultDisplayName() {
return NAME;
} }
@Nullable init {
@Override energy = MatteryMachineEnergyStorage(this, MatteryMachineEnergyStorage.MachineType.WORKER, Fraction(30000))
public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply) {
return new DriveViewerMenu(containerID, inventory, this);
} }
@Override override fun getDefaultDisplayName(): Component {
public void saveAdditional(CompoundTag nbt) { return NAME
super.saveAdditional(nbt);
nbt.put("drive_slot", drive_slot.serializeNBT());
} }
@Override override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu? {
public void load(CompoundTag nbt) { return DriveViewerMenu(containerID, inventory, this)
super.load(nbt);
drive_slot.deserializeNBT(nbt.get("drive_slot"));
} }
public static <T extends BlockEntity> void ticker(Level level, BlockPos blockPos, BlockState blockState, T t) { override fun saveAdditional(nbt: CompoundTag) {
if (t instanceof BlockEntityDriveViewer tile) { super.saveAdditional(nbt)
tile.batteryChargeLoop(); nbt["drive_slot"] = drive_slot.serializeNBT()
}
override fun load(nbt: CompoundTag) {
super.load(nbt)
nbt.ifHas("drive_slot") {
drive_slot.deserializeNBT(it)
} }
} }
fun tick() {
batteryChargeLoop()
}
companion object {
private val NAME = TranslatableComponent("block.overdrive_that_matters.drive_viewer")
}
} }

View File

@ -0,0 +1,233 @@
package ru.dbotthepony.mc.otm.client.screen
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
import ru.dbotthepony.mc.otm.item.ItemPortableCondensationDrive.FilterSettings
import ru.dbotthepony.mc.otm.menu.DriveViewerMenu
import ru.dbotthepony.mc.otm.menu.DriveViewerMenu.FilterSetPacket
import ru.dbotthepony.mc.otm.menu.DriveViewerMenu.FilterSwitchPacket
import ru.dbotthepony.mc.otm.network.MatteryNetworking
class DriveViewerScreen(menu: DriveViewerMenu, inventory: Inventory, title: Component) :
MatteryScreen<DriveViewerMenu>(menu, inventory, title) {
override fun makeMainFrame(): FramePanel {
val frame = FramePanel(this, null, 0f, 0f, FRAME_WIDTH, FRAME_HEIGHT, getTitle())
val views = ArrayList<EditablePanel>()
val settings = ArrayList<EditablePanel>()
val viewButton = frame.addTab(FramePanel.FrameTabPosition.TOP)
val settingsButton = frame.addTab(FramePanel.FrameTabPosition.TOP)
viewButton.bindOnOpen {
for (panel in views) {
panel.visible = true
}
}
viewButton.bindOnClose {
for (panel in views) {
panel.visible = false
}
}
settingsButton.bindOnOpen {
for (panel in settings) {
panel.visible = true
}
}
settingsButton.bindOnClose {
for (panel in settings) {
panel.visible = false
}
}
views.add(PowerGaugePanel(this, frame, menu.battery_widget, 8f, 16f))
views.add(SlotPanel(this, frame, menu.battery_slot, 8f, 67f))
views.add(SlotPanel(this, frame, menu.driveSlot, 8f, 85f))
val grid = GridPanel(this, frame, 28f, 16f, GRID_WIDTH * 18f, GRID_HEIGHT * 18f, GRID_WIDTH, GRID_HEIGHT)
val scroll_bar = ScrollBarPanel(this, frame, 192f, 14f, 92f)
scroll_bar.setupRowMultiplier { menu.view.getItemCount() / GRID_WIDTH }
views.add(grid)
views.add(scroll_bar)
for (i in 0 until GRID_WIDTH * GRID_HEIGHT) {
object : AbstractSlotPanel(this@DriveViewerScreen, grid, 0f, 0f) {
override fun getItemStack(): ItemStack {
val index = i + scroll_bar.getScroll(menu.view.getItems().size / GRID_WIDTH)
val list = menu.view.getItems()
return if (index >= list.size) {
ItemStack.EMPTY
} else list[index].stack
}
override fun mouseScrolledInner(mouse_x: Double, mouse_y: Double, scroll: Double): Boolean {
return scroll_bar.mouseScrolledInner(mouse_x, mouse_y, scroll)
}
override fun mouseClickedInner(mouse_x: Double, mouse_y: Double, mouse_click_type: Int): Boolean {
val index = i + scroll_bar.getScroll(GRID_WIDTH)
menu.view.mouseClick(index, mouse_click_type)
return true
}
}
}
val dock_left = FlexGridPanel(this, frame, 0f, 0f, 90f, 0f)
dock_left.dock = Dock.LEFT
dock_left.setDockMargin(4f, 0f, 4f, 0f)
val grid_filter = FlexGridPanel(this, frame)
grid_filter.dock = Dock.FILL
settings.add(dock_left)
settings.add(grid_filter)
for (i in 0 until FilterSettings.MAX_FILTERS) {
object : AbstractSlotPanel(this@DriveViewerScreen, grid_filter, 0f, 0f) {
override fun getItemStack(): ItemStack {
val filter = menu.getFilter() ?: return ItemStack.EMPTY
return filter.items[i]
}
private var clicking = false
override fun mouseClickedInner(mouse_x: Double, mouse_y: Double, mouse_click_type: Int): Boolean {
clicking = true
return true
}
override fun mouseReleasedInner(mouse_x: Double, mouse_y: Double, flag: Int): Boolean {
if (clicking)
MatteryNetworking.send(null, FilterSetPacket(menu.containerId, i, menu.carried))
clicking = false
return true
}
}
}
val no = TranslatableComponent("otm.filter.no")
val yes = TranslatableComponent("otm.filter.yes")
val matchNbt =
object : ButtonPanel(this@DriveViewerScreen, dock_left, 0f, 0f, 90f, 20f, TranslatableComponent("otm.filter.match_nbt", no)) {
override fun tick() {
super.tick()
val filter = menu.getFilter()
if (filter != null) {
orCreateWidget.message = TranslatableComponent("otm.filter.match_nbt", if (filter.matchNbt) yes else no)
orCreateWidget.active = !isWidgetDisabled
} else {
orCreateWidget.active = false
}
}
override fun onPress() {
super.onPress()
val filter = menu.getFilter()
if (filter != null) {
MatteryNetworking.send(
null,
FilterSwitchPacket(
menu.containerId,
DriveViewerMenu.FilterSwitch.MATCH_NBT,
!filter.matchNbt
)
)
disableFor(20)
}
}
}
val matchTag =
object : ButtonPanel(this@DriveViewerScreen, dock_left, 0f, 0f, 90f, 20f, TranslatableComponent("otm.filter.match_tag", no)) {
override fun tick() {
super.tick()
val filter = menu.getFilter()
if (filter != null) {
orCreateWidget.message =
TranslatableComponent("otm.filter.match_tag", if (filter.matchTag) yes else no)
orCreateWidget.active = !isWidgetDisabled
} else {
orCreateWidget.active = false
}
}
override fun onPress() {
super.onPress()
val filter = menu.getFilter()
if (filter != null) {
MatteryNetworking.send(
null,
FilterSwitchPacket(
menu.containerId,
DriveViewerMenu.FilterSwitch.MATCH_TAG,
!filter.matchTag
)
)
disableFor(20)
}
}
}
val blacklist =
object : ButtonPanel(this@DriveViewerScreen, dock_left, 0f, 0f, 90f, 20f, TranslatableComponent("otm.filter.blacklist", no)) {
override fun tick() {
super.tick()
val filter = menu.getFilter()
if (filter != null) {
orCreateWidget.message = TranslatableComponent("otm.filter.blacklist", if (filter.isBlacklist) yes else no)
orCreateWidget.active = !isWidgetDisabled
} else {
orCreateWidget.active = false
}
}
override fun onPress() {
super.onPress()
val filter = menu.getFilter()
if (filter != null) {
MatteryNetworking.send(
null,
FilterSwitchPacket(
menu.containerId,
DriveViewerMenu.FilterSwitch.BLACKLIST,
!filter.isBlacklist
)
)
disableFor(20)
}
}
}
matchNbt.setDockMargin(0f, 4f, 0f, 0f)
matchTag.setDockMargin(0f, 4f, 0f, 0f)
blacklist.setDockMargin(0f, 4f, 0f, 0f)
for (panel in settings) {
panel.visible = false
}
return frame
}
companion object {
const val FRAME_WIDTH = 210f
const val FRAME_HEIGHT = 110f
const val GRID_WIDTH = 9
const val GRID_HEIGHT = 5
}
}

View File

@ -17,16 +17,16 @@ class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Comp
SlotPanel(this, frame, menu.battery_slot, 8f, 80f) SlotPanel(this, frame, menu.battery_slot, 8f, 80f)
val scrollBar = ScrollBarPanel(this, frame, 192f, 14f, 92f) val scrollBar = ScrollBarPanel(this, frame, 192f, 14f, 92f)
scrollBar.setupRowMultiplier { menu.view.items.size / GRID_WIDTH } scrollBar.setupRowMultiplier { menu.view.getItemCount() / GRID_WIDTH }
val gridPanel = GridPanel(this, frame, 28f, 16f, GRID_WIDTH * 18f, GRID_HEIGHT * 18f, GRID_WIDTH, GRID_HEIGHT) val gridPanel = GridPanel(this, frame, 28f, 16f, GRID_WIDTH * 18f, GRID_HEIGHT * 18f, GRID_WIDTH, GRID_HEIGHT)
for (i in 0 until GRID_WIDTH * GRID_HEIGHT) { for (i in 0 until GRID_WIDTH * GRID_HEIGHT) {
object : AbstractSlotPanel(this@ItemMonitorScreen, gridPanel) { object : AbstractSlotPanel(this@ItemMonitorScreen, gridPanel) {
override fun getItemStack(): ItemStack { override fun getItemStack(): ItemStack {
val index = i + scrollBar.getScroll(menu.view.items.size / GRID_WIDTH) val index = i + scrollBar.getScroll(menu.view.getItemCount() / GRID_WIDTH)
val list = menu.view.items val list = menu.view.getItems()
return if (index >= list.size) ItemStack.EMPTY else list[index].stack() return if (index >= list.size) ItemStack.EMPTY else list[index].stack
} }
override fun mouseScrolledInner(mouse_x: Double, mouse_y: Double, scroll: Double): Boolean { override fun mouseScrolledInner(mouse_x: Double, mouse_y: Double, scroll: Double): Boolean {

View File

@ -0,0 +1,241 @@
package ru.dbotthepony.mc.otm.menu
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraftforge.energy.CapabilityEnergy
import net.minecraftforge.network.NetworkEvent
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.IMatteryDrive
import ru.dbotthepony.mc.otm.item.ItemPortableCondensationDrive
import ru.dbotthepony.mc.otm.item.ItemPortableCondensationDrive.FilterSettings
import ru.dbotthepony.mc.otm.menu.data.INetworkedItemViewSupplier
import ru.dbotthepony.mc.otm.menu.data.NetworkedItemView
import ru.dbotthepony.mc.otm.storage.ItemStackWrapper
import ru.dbotthepony.mc.otm.storage.PoweredVirtualComponent
import java.util.function.Supplier
class DriveViewerMenu @JvmOverloads constructor(
containerID: Int,
inventory: Inventory,
tile: BlockEntityDriveViewer? = null
) : PoweredMatteryMenu(
Registry.Menus.DRIVE_VIEWER, containerID, inventory, tile
), INetworkedItemViewSupplier {
@JvmField val view: NetworkedItemView
private val powered: PoweredVirtualComponent<ItemStackWrapper>?
@JvmField val driveSlot: MatterySlot
private var lastDrive: IMatteryDrive<ItemStackWrapper>? = null
override fun getNetworkedItemView() = view
init {
val container = if (tile != null) tile.drive_slot else SimpleContainer(1)
driveSlot = object : MatterySlot(container, 0) {
override fun mayPlace(stack: ItemStack): Boolean {
return stack.getCapability(MatteryCapability.DRIVE).isPresent
}
}
view = NetworkedItemView(inventory.player, this, tile == null)
if (tile != null) {
powered = PoweredVirtualComponent(
ItemStackWrapper::class.java,
tile.getCapability(MatteryCapability.ENERGY).resolve().get()
)
view.setComponent(powered)
} else {
powered = null
}
addSlot(driveSlot)
addBatterySlot()
addInventorySlots()
}
override fun broadcastChanges() {
super.broadcastChanges()
if (tile != null) {
val itemStack = (tile as BlockEntityDriveViewer).drive_slot.getItem(0)
val prev = lastDrive
lastDrive = null
if (!itemStack.isEmpty) {
itemStack.getCapability(MatteryCapability.DRIVE).ifPresent {
if (it.storageIdentity() == ItemStackWrapper::class.java) {
lastDrive = it as IMatteryDrive<ItemStackWrapper>
}
}
}
if (prev != lastDrive) {
if (prev != null)
powered!!.remove(prev)
view.clear()
if (lastDrive != null)
powered!!.add(lastDrive!!)
}
view.network()
}
}
override fun getWorkingSlotStart(): Int {
return 0
}
override fun getWorkingSlotEnd(): Int {
return 2
}
override fun removed(p_38940_: Player) {
super.removed(p_38940_)
if (powered != null)
lastDrive?.removeListener(powered)
view.clear()
}
override fun quickMoveStack(ply: Player, slot_index: Int): ItemStack {
val slot = slots[slot_index]
val item = slot.item
if (item.isEmpty || item.getCapability(MatteryCapability.DRIVE).isPresent || item.getCapability(CapabilityEnergy.ENERGY).isPresent)
return super.quickMoveStack(ply, slot_index)
val powered = powered
if (lastDrive == null || powered == null)
return ItemStack.EMPTY
val remaining = powered.insertStack(ItemStackWrapper(item), false)
if (remaining.count.toInt() == item.count)
return ItemStack.EMPTY
if (remaining.isEmpty()) {
val copy = item.copy()
slot.set(ItemStack.EMPTY)
return copy
}
val copy = item.copy()
item.shrink(remaining.count.toInt())
slot.setChanged()
return copy
}
enum class FilterSwitch {
MATCH_NBT, MATCH_TAG, BLACKLIST
}
fun getFilter(): FilterSettings? {
if (driveSlot.item.isEmpty)
return null
val item = driveSlot.item.item
return if (item is ItemPortableCondensationDrive) item.getFilterSettings(driveSlot.item) else null
}
class FilterSetPacket(val id: Int, val slot: Int, val value: ItemStack) {
fun write(buffer: FriendlyByteBuf) {
buffer.writeInt(id)
buffer.writeInt(slot)
buffer.writeItem(value)
}
fun play(context: Supplier<NetworkEvent.Context>) {
context.get().packetHandled = true
if (slot < 0 || slot >= FilterSettings.MAX_FILTERS)
return
if (value.count > 1)
value.count = 1
context.get().enqueueWork {
val ply = context.get().sender!!
val menu = ply.containerMenu
if (menu is DriveViewerMenu && menu.containerId == id) {
if (menu.driveSlot.item.isEmpty)
return@enqueueWork
val itemStack = menu.driveSlot.item
val item = itemStack.item
if (item is ItemPortableCondensationDrive) {
val filter = item.getFilterSettings(itemStack)
filter.items[slot] = value
filter.serializeNBT(itemStack)
}
}
}
}
companion object {
@JvmStatic
fun read(buffer: FriendlyByteBuf): FilterSetPacket {
return FilterSetPacket(buffer.readInt(), buffer.readInt(), buffer.readItem())
}
}
}
class FilterSwitchPacket(val id: Int, val type: FilterSwitch, val value: Boolean) {
fun write(buffer: FriendlyByteBuf) {
buffer.writeInt(id)
buffer.writeEnum(type)
buffer.writeBoolean(value)
}
fun play(context: Supplier<NetworkEvent.Context>) {
context.get().packetHandled = true
context.get().enqueueWork {
val ply = context.get().sender!!
val menu = ply.containerMenu
if (menu is DriveViewerMenu && menu.containerId == id) {
val settings = menu.getFilter() ?: return@enqueueWork
when (type) {
FilterSwitch.MATCH_NBT -> {
settings.matchNbt = value
}
FilterSwitch.MATCH_TAG -> {
settings.matchTag = value
}
FilterSwitch.BLACKLIST -> {
settings.isBlacklist = value
}
}
settings.serializeNBT(menu.driveSlot.item)
}
}
}
companion object {
@JvmStatic
fun read(buffer: FriendlyByteBuf): FilterSwitchPacket {
return FilterSwitchPacket(
buffer.readInt(),
buffer.readEnum(FilterSwitch::class.java),
buffer.readBoolean()
)
}
}
}
}

View File

@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.menu
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.Registry import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.block.entity.BlockEntityItemMonitor import ru.dbotthepony.mc.otm.block.entity.BlockEntityItemMonitor
import ru.dbotthepony.mc.otm.capability.IMatteryEnergyStorage import ru.dbotthepony.mc.otm.capability.IMatteryEnergyStorage
@ -58,4 +59,12 @@ class ItemMonitorMenu @JvmOverloads constructor(
override fun getWorkingSlotEnd(): Int { override fun getWorkingSlotEnd(): Int {
return 1 return 1
} }
override fun quickMoveStack(ply: Player, slot_index: Int): ItemStack {
if (slot_index in inventorySlotIndexStart..inventorySlotIndexEnd) {
}
return super.quickMoveStack(ply, slot_index)
}
} }

View File

@ -9,32 +9,26 @@ import ru.dbotthepony.mc.otm.menu.widget.AbstractWidget
import java.util.function.Consumer import java.util.function.Consumer
@JvmRecord @JvmRecord
data class MoveResult(val merge_occured: Boolean, val remaining: ItemStack, val changed_slots: Set<Slot>) data class MoveResult(val mergeOccurred: Boolean, val remaining: ItemStack, val changed_slots: Set<Slot>)
abstract class MatteryMenu protected @JvmOverloads constructor( abstract class MatteryMenu protected @JvmOverloads constructor(
p_38851_: MenuType<*>?, p_38851_: MenuType<*>?,
p_38852_: Int, p_38852_: Int,
@JvmField val inventory: Inventory, @JvmField val inventory: Inventory,
tile: BlockEntity? = null @JvmField val tile: BlockEntity? = null
) : AbstractContainerMenu(p_38851_, p_38852_) { ) : AbstractContainerMenu(p_38851_, p_38852_) {
@JvmField
val tile: BlockEntity?
@JvmField @JvmField
val ply: Player = inventory.player val ply: Player = inventory.player
@JvmField @JvmField
val mattery_widgets = ArrayList<AbstractWidget>() val matteryWidgets = ArrayList<AbstractWidget>()
@JvmField @JvmField
val inventory_slots = ArrayList<MatterySlot>() val inventorySlots = ArrayList<MatterySlot>()
@JvmField @JvmField
val main_slots = ArrayList<MatterySlot>() protected val lockedInventorySlots: MutableSet<Int> = HashSet()
protected open fun isInventorySlotLocked(index: Int): Boolean = lockedInventorySlots.contains(index)
@JvmField
protected val locked_inventory_slots: MutableSet<Int> = HashSet()
protected fun isInventorySlotLocked(index: Int): Boolean = locked_inventory_slots.contains(index)
@JvmField @JvmField
protected var _synchronizer: ContainerSynchronizer? = null protected var _synchronizer: ContainerSynchronizer? = null
@ -45,27 +39,17 @@ abstract class MatteryMenu protected @JvmOverloads constructor(
} }
fun addWidget(widget: AbstractWidget, consumer: Consumer<Consumer<ContainerData>>) { fun addWidget(widget: AbstractWidget, consumer: Consumer<Consumer<ContainerData>>) {
if (!mattery_widgets.contains(widget)) { if (!matteryWidgets.contains(widget)) {
mattery_widgets.add(widget) matteryWidgets.add(widget)
consumer.accept(Consumer { p_38885_: ContainerData -> addDataSlots(p_38885_) }) consumer.accept(Consumer { p_38885_: ContainerData -> addDataSlots(p_38885_) })
} }
} }
fun addMainSlot(slot: MatterySlot): MatterySlot { @JvmField
addSlot(slot) protected var inventorySlotIndexStart = 0
main_slots.add(slot)
return slot
}
@JvmField @JvmField
protected var inventory_slot_index_start = 0 protected var inventorySlotIndexEnd = 0
@JvmField
protected var inventory_slot_index_end = 0
init {
this.tile = tile
}
@JvmOverloads @JvmOverloads
protected fun addInventorySlots(offset: Int = 97) { protected fun addInventorySlots(offset: Int = 97) {
@ -83,12 +67,12 @@ abstract class MatteryMenu protected @JvmOverloads constructor(
} }
} }
inventory_slots.add(slot) inventorySlots.add(slot)
addSlot(slot) addSlot(slot)
if (first) { if (first) {
first = false first = false
inventory_slot_index_start = slot.index inventorySlotIndexStart = slot.index
} }
} }
} }
@ -107,14 +91,14 @@ abstract class MatteryMenu protected @JvmOverloads constructor(
} }
addSlot(last) addSlot(last)
inventory_slots.add(last) inventorySlots.add(last)
} }
inventory_slot_index_end = last!!.index inventorySlotIndexEnd = last!!.index
} }
override fun broadcastChanges() { override fun broadcastChanges() {
for (widget in mattery_widgets) { for (widget in matteryWidgets) {
widget.updateServer() widget.updateServer()
} }
@ -122,7 +106,7 @@ abstract class MatteryMenu protected @JvmOverloads constructor(
} }
override fun broadcastFullState() { override fun broadcastFullState() {
for (widget in mattery_widgets) { for (widget in matteryWidgets) {
widget.updateServer() widget.updateServer()
} }
@ -148,7 +132,7 @@ abstract class MatteryMenu protected @JvmOverloads constructor(
// It shall return item stack that got moved // It shall return item stack that got moved
override fun quickMoveStack(ply: Player, slot_index: Int): ItemStack { override fun quickMoveStack(ply: Player, slot_index: Int): ItemStack {
// this.moveItemStackTo(ItemStack, int start_slot_index, int end_slot_index, boolean iteration_order) // this.moveItemStackTo(ItemStack, int start_slot_index, int end_slot_index, boolean iteration_order)
// returns boolean, telling whenever ItemStack was modified (moved or sharnk) // returns boolean, telling whenever ItemStack was modified (moved or shrank)
// false means nothing happened // false means nothing happened
// Last boolean determine order of slot iteration, where: // Last boolean determine order of slot iteration, where:
// if TRUE, iteration order is end_slot_index -> start_slot_index // if TRUE, iteration order is end_slot_index -> start_slot_index
@ -161,26 +145,26 @@ abstract class MatteryMenu protected @JvmOverloads constructor(
} }
var moved = ItemStack.EMPTY var moved = ItemStack.EMPTY
val get_slot = slots[slot_index] val initialSlot = slots[slot_index]
if (get_slot.hasItem()) { if (initialSlot.hasItem()) {
val slot_item = get_slot.item val initialItem = initialSlot.item
moved = slot_item.copy() moved = initialItem.copy()
if (slot_index < inventory_slot_index_start) { if (slot_index < inventorySlotIndexStart) {
// Moving FROM machine TO inventory // Moving FROM machine TO inventory
if (!moveItemStackTo(slot_item, inventory_slot_index_start, inventory_slot_index_end + 1, false)) { if (!moveItemStackTo(initialItem, inventorySlotIndexStart, inventorySlotIndexEnd + 1, false)) {
return ItemStack.EMPTY return ItemStack.EMPTY
} }
} else if (!moveItemStackTo(slot_item, start, end, false)) { } else if (!moveItemStackTo(initialItem, start, end, false)) {
// Moving FROM inventory TO machine // Moving FROM inventory TO machine
return ItemStack.EMPTY return ItemStack.EMPTY
} }
if (slot_item.isEmpty) { if (initialItem.isEmpty) {
get_slot.set(ItemStack.EMPTY) initialSlot.set(ItemStack.EMPTY)
} else { } else {
get_slot.setChanged() initialSlot.setChanged()
} }
} }
@ -188,12 +172,12 @@ abstract class MatteryMenu protected @JvmOverloads constructor(
} }
fun quickMoveToInventory(stack: ItemStack, simulate: Boolean): MoveResult { fun quickMoveToInventory(stack: ItemStack, simulate: Boolean): MoveResult {
return if (inventory_slot_index_start == 0 && inventory_slot_index_end == 0) { return if (inventorySlotIndexStart == 0 && inventorySlotIndexEnd == 0) {
MoveResult(false, stack, java.util.Set.of<Slot>()) MoveResult(false, stack, setOf())
} else customMoveItemStackTo( } else customMoveItemStackTo(
stack, stack,
inventory_slot_index_start, inventorySlotIndexStart,
inventory_slot_index_end + 1, inventorySlotIndexEnd + 1,
false, false,
simulate simulate
) )
@ -205,27 +189,27 @@ abstract class MatteryMenu protected @JvmOverloads constructor(
final_slot: Int, final_slot: Int,
reverse_direction: Boolean reverse_direction: Boolean
): Boolean { ): Boolean {
val move_result = customMoveItemStackTo(stack_to_move, initial_slot, final_slot, reverse_direction, false) val moveResult = customMoveItemStackTo(stack_to_move, initial_slot, final_slot, reverse_direction, false)
val remaining: ItemStack = move_result.remaining val remaining: ItemStack = moveResult.remaining
if (remaining.count == stack_to_move.count) return false if (remaining.count == stack_to_move.count) return false
stack_to_move.count = remaining.count stack_to_move.count = remaining.count
return move_result.merge_occured return moveResult.mergeOccurred
} }
protected fun customMoveItemStackTo( protected fun customMoveItemStackTo(
_stack_to_move: ItemStack, stackToMove1: ItemStack,
initial_slot: Int, initial_slot: Int,
final_slot: Int, final_slot: Int,
reverse_direction: Boolean, reverse_direction: Boolean,
simulate: Boolean simulate: Boolean
): MoveResult { ): MoveResult {
var merge_occured = false var mergeOccurred = false
var i = if (reverse_direction) final_slot - 1 else initial_slot var i = if (reverse_direction) final_slot - 1 else initial_slot
val changed = HashSet<Slot>() val changed = HashSet<Slot>()
val stack_to_move = _stack_to_move.copy() val stackToMove = stackToMove1.copy()
if (stack_to_move.isStackable) { if (stackToMove.isStackable) {
while (!stack_to_move.isEmpty) { while (!stackToMove.isEmpty) {
if (reverse_direction) { if (reverse_direction) {
if (i < initial_slot) { if (i < initial_slot) {
break break
@ -237,29 +221,29 @@ abstract class MatteryMenu protected @JvmOverloads constructor(
val slot = slots[i] val slot = slots[i]
val slot_stack = slot.item val slot_stack = slot.item
if (!slot_stack.isEmpty && ItemStack.isSameItemSameTags(stack_to_move, slot_stack)) { if (!slot_stack.isEmpty && ItemStack.isSameItemSameTags(stackToMove, slot_stack)) {
val j = slot_stack.count + stack_to_move.count val j = slot_stack.count + stackToMove.count
val maxSize = slot.getMaxStackSize(stack_to_move) val maxSize = slot.getMaxStackSize(stackToMove)
if (j <= maxSize) { if (j <= maxSize) {
stack_to_move.count = 0 stackToMove.count = 0
if (!simulate) { if (!simulate) {
slot_stack.count = j slot_stack.count = j
slot.setChanged() slot.setChanged()
} }
merge_occured = true mergeOccurred = true
changed.add(slot) changed.add(slot)
} else if (slot_stack.count < maxSize) { } else if (slot_stack.count < maxSize) {
stack_to_move.shrink(maxSize - slot_stack.count) stackToMove.shrink(maxSize - slot_stack.count)
if (!simulate) { if (!simulate) {
slot_stack.count = maxSize slot_stack.count = maxSize
slot.setChanged() slot.setChanged()
} }
merge_occured = true mergeOccurred = true
changed.add(slot) changed.add(slot)
} }
} }
@ -268,7 +252,7 @@ abstract class MatteryMenu protected @JvmOverloads constructor(
} }
} }
if (!stack_to_move.isEmpty) { if (!stackToMove.isEmpty) {
i = if (reverse_direction) final_slot - 1 else initial_slot i = if (reverse_direction) final_slot - 1 else initial_slot
while (true) { while (true) {
@ -283,18 +267,18 @@ abstract class MatteryMenu protected @JvmOverloads constructor(
val slot = slots[i] val slot = slots[i]
val slot_stack = slot.item val slot_stack = slot.item
if (slot_stack.isEmpty && slot.mayPlace(stack_to_move)) { if (slot_stack.isEmpty && slot.mayPlace(stackToMove)) {
if (!simulate) { if (!simulate) {
if (stack_to_move.count > slot.maxStackSize) { if (stackToMove.count > slot.maxStackSize) {
slot.set(stack_to_move.split(slot.maxStackSize)) slot.set(stackToMove.split(slot.maxStackSize))
} else { } else {
slot.set(stack_to_move.split(stack_to_move.count)) slot.set(stackToMove.split(stackToMove.count))
} }
slot.setChanged() slot.setChanged()
} }
merge_occured = true mergeOccurred = true
changed.add(slot) changed.add(slot)
break break
} }
@ -302,6 +286,7 @@ abstract class MatteryMenu protected @JvmOverloads constructor(
i += if (reverse_direction) -1 else 1 i += if (reverse_direction) -1 else 1
} }
} }
return MoveResult(merge_occured, stack_to_move, changed)
return MoveResult(mergeOccurred, stackToMove, changed)
} }
} }

View File

@ -0,0 +1,213 @@
package ru.dbotthepony.mc.otm.menu.data
import com.mojang.blaze3d.platform.InputConstants
import net.minecraft.client.gui.screens.Screen
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.network.PacketDistributor
import ru.dbotthepony.mc.otm.core.Fraction
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.IStorageComponent
import ru.dbotthepony.mc.otm.storage.IStorageListener
import ru.dbotthepony.mc.otm.storage.IStorageView
import ru.dbotthepony.mc.otm.storage.ItemStackWrapper
import java.util.*
/**
* Creates a virtual, slotless container for Player's interaction with.
*/
open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote: Boolean) : IStorageListener<ItemStackWrapper> {
@JvmRecord
data class NetworkedItem @JvmOverloads constructor(val id: Int, val stack: ItemStack, val upstreamId: UUID? = null)
@JvmField protected var next_stack_id = 0
@JvmField val state = HashMap<Int, NetworkedItem>()
@JvmField protected val upstream_state = HashMap<UUID, NetworkedItem>()
@JvmField protected val backlog = ArrayList<Any>()
operator fun get(id: Int): NetworkedItem? {
return state[id]
}
private var cachedView: List<NetworkedItem>? = null
@JvmField protected var provider: IStorageComponent<ItemStackWrapper>? = null
fun mouseClick(index: Int, mouse_click_type: Int) {
val list = getItems()
val action =
if (mouse_click_type == InputConstants.MOUSE_BUTTON_LEFT) ClickAction.PRIMARY else ClickAction.SECONDARY
val type =
if (mouse_click_type == InputConstants.MOUSE_BUTTON_MIDDLE) ClickType.CLONE else if (Screen.hasShiftDown()) ClickType.QUICK_MOVE else ClickType.PICKUP
MatteryNetworking.send(
null,
InteractPacket(menu.containerId, if (index >= list.size) -1 else list[index].id, type, action)
)
}
fun setComponent(provider: IStorageComponent<ItemStackWrapper>?) {
if (provider === this.provider) return
this.provider?.removeListenerAuto(this)
this.provider = provider
provider?.addListenerAuto(this)
}
fun removed() {
provider?.removeListenerAuto(this)
}
fun clearCache() {
cachedView = null
}
fun getItems(): List<NetworkedItem> {
return if (cachedView != null) cachedView!! else java.util.List.copyOf(state.values).also { cachedView = it }
}
fun getItemCount(): Int {
return state.values.size
}
override fun addObject(stack: ItemStackWrapper, id: UUID, provider: IStorageView<ItemStackWrapper>) = addObject(stack.stack, id)
override fun changeObject(id: UUID, newCount: Fraction) = changeObject(id, newCount.toInt())
protected fun network(fn: () -> Any) {
if (!remote) {
backlog.add(fn())
}
}
override fun removeObject(id: UUID) {
val get = upstream_state[id] ?: throw IllegalStateException("Unknown ItemStack with upstream id $id!")
upstream_state.remove(id)
state.remove(get.id)
network { StackRemovePacket(menu.containerId, get.id) }
clearCache()
}
fun addObject(stack: ItemStack, id_upstream: UUID) {
check(!upstream_state.containsKey(id_upstream)) { "Already tracking ItemStack with upstream id $id_upstream!" }
val state = NetworkedItem(next_stack_id++, stack.copy(), id_upstream)
this.state[state.id] = state
upstream_state[id_upstream] = state
network { StackAddPacket(menu.containerId, state.id, stack) }
clearCache()
}
fun changeObject(id_upstream: UUID, new_count: Int) {
val get = upstream_state[id_upstream] ?: throw IllegalStateException("Unknown ItemStack with upstream id $id_upstream!")
get.stack.count = new_count
network { StackChangePacket(menu.containerId, get.id, new_count) }
clearCache()
}
fun clear() {
clearCache()
upstream_state.clear()
state.clear()
if (!remote) {
backlog.clear()
backlog.add(ClearPacket(menu.containerId))
}
}
fun network() {
check(!remote) { "Not a server" }
val consumer = PacketDistributor.PLAYER.with { ply as ServerPlayer }
for (packet in backlog) MatteryNetworking.CHANNEL.send(consumer, packet)
backlog.clear()
}
fun playerInteract(packet: InteractPacket) {
val provider = provider ?: return
val click = packet.click()
val action = packet.action()
val stack_id = packet.stack_id()
if (click == ClickType.CLONE) {
if (stack_id < 0 || !ply.abilities.instabuild) return
val state = get(stack_id) ?: return
val copy: ItemStack = state.stack.copy()
copy.count = Math.min(copy.count, copy.maxStackSize)
ply.containerMenu.carried = copy
MatteryNetworking.send(ply as ServerPlayer, SetCarriedPacket(ply.containerMenu.carried))
ply.containerMenu.setRemoteCarried(ply.containerMenu.carried.copy())
return
}
if (click == ClickType.QUICK_MOVE && stack_id > -1) {
val state = get(stack_id) ?: return
val amount =
if (action == ClickAction.PRIMARY)
state.stack.maxStackSize
else
Math.max(1, state.stack.maxStackSize / 2)
val extracted = provider.extractStack(state.upstreamId!!, amount, true)
if (!extracted.isEmpty()) {
val (_, remaining) = menu.quickMoveToInventory(extracted.stack, false)
if (remaining.count != extracted.stack.count) {
provider.extractStack(state.upstreamId, extracted.stack.count - remaining.count, false)
}
}
return
}
if (!menu.carried.isEmpty && click != ClickType.QUICK_MOVE) {
// try to put
if (action == ClickAction.PRIMARY) {
val carried = menu.carried
val amount = carried.count
if (amount == carried.count) {
val (stack) = provider.insertStack(ItemStackWrapper(menu.carried), false)
menu.carried = stack
MatteryNetworking.send(ply as ServerPlayer, SetCarriedPacket(menu.carried))
menu.setRemoteCarried(menu.carried.copy())
}
} else {
val copy = menu.carried.copy()
copy.count = 1
if (provider.insertStack(ItemStackWrapper(copy), false).isEmpty()) {
menu.carried.shrink(1)
MatteryNetworking.send(ply as ServerPlayer, SetCarriedPacket(menu.carried))
menu.setRemoteCarried(menu.carried.copy())
}
}
} else if (stack_id > -1) {
val state = get(stack_id) ?: return
val amount =
if (action == ClickAction.PRIMARY)
state.stack.maxStackSize
else
Math.max(1, state.stack.maxStackSize / 2)
val extracted = provider.extractStack(state.upstreamId!!, amount, false)
menu.carried = extracted.stack
MatteryNetworking.send(ply as ServerPlayer, SetCarriedPacket(menu.carried))
menu.setRemoteCarried(menu.carried.copy())
}
}
}

View File

@ -84,6 +84,8 @@ interface IStorageView<T : IStorageStack> : IStorageTrigger<T> {
* @return copy of object, with amount of units actually extracted * @return copy of object, with amount of units actually extracted
*/ */
fun extractStack(id: UUID, amount: Fraction, simulate: Boolean): T fun extractStack(id: UUID, amount: Fraction, simulate: Boolean): T
fun extractStack(id: UUID, amount: Int, simulate: Boolean): T = extractStack(id, Fraction(amount), simulate)
fun extractStack(id: UUID, amount: Long, simulate: Boolean): T = extractStack(id, Fraction(amount), simulate)
/** /**
* Designed for views, for extraction with less computation overhead caused by * Designed for views, for extraction with less computation overhead caused by
@ -98,6 +100,9 @@ interface IStorageView<T : IStorageStack> : IStorageTrigger<T> {
return extractStack(id, amount, simulate).count return extractStack(id, amount, simulate).count
} }
fun extractStackCount(id: UUID, amount: Int, simulate: Boolean): Fraction = extractStackCount(id, Fraction(amount), simulate)
fun extractStackCount(id: UUID, amount: Long, simulate: Boolean): Fraction = extractStackCount(id, Fraction(amount), simulate)
fun getStacks(): Collection<IStorageTuple<T>> fun getStacks(): Collection<IStorageTuple<T>>
fun addListenerAuto(listener: IStorageListener<T>): Boolean { fun addListenerAuto(listener: IStorageListener<T>): Boolean {

View File

@ -15,7 +15,7 @@ data class ItemStackWrapper(val stack: ItemStack) : IStorageStack {
} }
override var count: Fraction override var count: Fraction
get() = Fraction(stack.getCount()) get() = Fraction(stack.count)
set(value) = setCount(value.toInt()) set(value) = setCount(value.toInt())
fun getCountInt() = stack.count fun getCountInt() = stack.count