diff --git a/src/main/java/ru/windcorp/progressia/common/state/StatefulObject.java b/src/main/java/ru/windcorp/progressia/common/state/StatefulObject.java
index 2feb7e6..3b78898 100644
--- a/src/main/java/ru/windcorp/progressia/common/state/StatefulObject.java
+++ b/src/main/java/ru/windcorp/progressia/common/state/StatefulObject.java
@@ -235,7 +235,7 @@ public abstract class StatefulObject extends Namespaced implements Encodable {
StatefulObject statefulObj = (StatefulObject) obj;
- if (statefulObj.getId().equals(this.getId()))
+ if (!statefulObj.getId().equals(this.getId()))
return false;
return true;
diff --git a/src/main/java/ru/windcorp/progressia/common/world/item/ItemSlot.java b/src/main/java/ru/windcorp/progressia/common/world/item/ItemSlot.java
index 390266c..c8cfa1b 100644
--- a/src/main/java/ru/windcorp/progressia/common/world/item/ItemSlot.java
+++ b/src/main/java/ru/windcorp/progressia/common/world/item/ItemSlot.java
@@ -94,6 +94,21 @@ public class ItemSlot implements Encodable {
return amount == 0;
}
+ public synchronized boolean canInsert(ItemData contents, int amount) {
+
+ // Ignore amount
+
+ if (this.contents == null) {
+ return true;
+ }
+
+ return this.contents.equals(contents);
+ }
+
+ public synchronized boolean canRemove(int amount) {
+ return this.amount >= amount;
+ }
+
private synchronized void checkState() {
if ((contents == null) != (amount == 0)) {
if (contents == null) {
diff --git a/src/main/java/ru/windcorp/progressia/common/world/item/Items.java b/src/main/java/ru/windcorp/progressia/common/world/item/Items.java
new file mode 100644
index 0000000..e8ab5c6
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/common/world/item/Items.java
@@ -0,0 +1,118 @@
+/*
+ * Progressia
+ * Copyright (C) 2020-2021 Wind Corporation and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package ru.windcorp.progressia.common.world.item;
+
+public class Items {
+
+ /**
+ * Attempts to transfer as many items as possible, but no more than
+ * {@code max}, between two slots. The origin of the items is {@code from},
+ * the destination is {@code into}. This method does nothing if the items
+ * could not be removed from origin or could not be inserted into
+ * destination, such as when {@code into} contains different items.
+ *
+ * @param from the slot to transfer item from
+ * @param into the destination of the items
+ * @param max the maximum amount of items to transfer. Use
+ * {@code Integer.MAX_VALUE} to remove the limit
+ * @return the actual amount of items moved between slots
+ */
+ public static int pour(ItemSlot from, ItemSlot into, int max) {
+ synchronized (from) {
+ synchronized (into) {
+
+ ItemData item = from.getContents();
+
+ int originalAmount = from.getAmount();
+ int transferAmount = Math.min(originalAmount, max);
+
+ while (transferAmount > 0 && !into.canInsert(item, transferAmount)) {
+ transferAmount--;
+ }
+
+ if (transferAmount == 0) {
+ return 0;
+ }
+
+ if (!from.canRemove(transferAmount)) {
+ return 0;
+ }
+
+ into.setContents(item, into.getAmount() + transferAmount);
+ from.setAmount(originalAmount - transferAmount);
+
+ return transferAmount;
+
+ }
+ }
+ }
+
+ /**
+ * Attempts to transfer as many items as possible between two slots. The
+ * origin of the items is {@code from}, the destination is {@code into}.
+ * This method does nothing if the items could not be removed from origin or
+ * could not be inserted into destination, such as when {@code into}
+ * contains different items.
+ *
+ * @param from the slot to transfer item from
+ * @param into the destination of the items
+ * @return the actual amount of items moved between slots
+ */
+ public static int pour(ItemSlot from, ItemSlot into) {
+ return pour(from, into, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Attempts to swap the contents of the two slots.
+ *
+ * @param a one of the slots
+ * @param b the other slot
+ *
+ * @return whether the swap succeeded
+ */
+ public static boolean swap(ItemSlot a, ItemSlot b) {
+ synchronized (a) {
+ synchronized (b) {
+
+ ItemData aItem = a.getContents();
+ int aAmount = a.getAmount();
+
+ ItemData bItem = b.getContents();
+ int bAmount = b.getAmount();
+
+ a.clear();
+ b.clear();
+
+ if (a.canInsert(bItem, bAmount) && b.canInsert(aItem, aAmount)) {
+ a.setContents(bItem, bAmount);
+ b.setContents(aItem, aAmount);
+ return true;
+ } else {
+ a.setContents(aItem, aAmount);
+ b.setContents(bItem, bAmount);
+ return false;
+ }
+
+ }
+ }
+ }
+
+ private Items() {
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/server/PlayerManager.java b/src/main/java/ru/windcorp/progressia/server/PlayerManager.java
index dd07d60..1953184 100644
--- a/src/main/java/ru/windcorp/progressia/server/PlayerManager.java
+++ b/src/main/java/ru/windcorp/progressia/server/PlayerManager.java
@@ -65,7 +65,8 @@ public class PlayerManager {
player.getInventory().addSlots(10);
- player.getInventory().getSlot(3).setContents(ItemDataRegistry.getInstance().create("Test:MoonTypeIceCream"), 5);
+ player.getInventory().getSlot(3).setContents(ItemDataRegistry.getInstance().create("Test:Stick"), 5);
+ player.getInventory().getSlot(5).setContents(ItemDataRegistry.getInstance().create("Test:Stick"), 4);
player.getInventory().getSlot(6).setContents(ItemDataRegistry.getInstance().create("Test:MoonTypeIceCream"), 1);
player.setPosition(getServer().getWorld().getGenerator().suggestSpawnLocation());
diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java
index 2582fb8..a265d21 100644
--- a/src/main/java/ru/windcorp/progressia/test/TestContent.java
+++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java
@@ -106,7 +106,7 @@ public class TestContent {
register(new BlockRenderNone("Test:Air"));
register(new TestBlockLogicAir("Test:Air"));
placeableBlacklist.add("Test:Air");
-
+
registerSimplestBlock("Dirt");
registerSimplestBlock("Chernozem");
registerSimplestBlock("Stone");
@@ -244,6 +244,7 @@ public class TestContent {
private static void registerItems() {
registerSimplestItem("MoonTypeIceCream", Units.get("200 g"), Units.get("1 L"));
+ registerSimplestItem("Stick", Units.get("260 g"), Units.get("0.5 L"));
}
private static void registerSimplestBlock(String name) {
diff --git a/src/main/java/ru/windcorp/progressia/test/inv/InventoryScreen.java b/src/main/java/ru/windcorp/progressia/test/inv/InventoryScreen.java
index dbbdce1..08aa9fa 100644
--- a/src/main/java/ru/windcorp/progressia/test/inv/InventoryScreen.java
+++ b/src/main/java/ru/windcorp/progressia/test/inv/InventoryScreen.java
@@ -18,6 +18,7 @@
package ru.windcorp.progressia.test.inv;
import java.util.function.Consumer;
+import java.util.function.Supplier;
import org.lwjgl.glfw.GLFW;
@@ -33,11 +34,13 @@ import ru.windcorp.progressia.client.graphics.gui.Layout;
import ru.windcorp.progressia.client.graphics.gui.Panel;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutFill;
+import ru.windcorp.progressia.client.graphics.input.KeyEvent;
+import ru.windcorp.progressia.client.graphics.input.bus.InputListener;
import ru.windcorp.progressia.client.graphics.model.Renderable;
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
import ru.windcorp.progressia.common.world.item.ItemContainer;
-import ru.windcorp.progressia.common.world.item.ItemData;
import ru.windcorp.progressia.common.world.item.ItemSlot;
+import ru.windcorp.progressia.common.world.item.Items;
public class InventoryScreen extends Component {
@@ -131,34 +134,72 @@ public class InventoryScreen extends Component {
}
private void addListeners(InventoryComponent mainInventory) {
- Consumer pickIntoLeft = createPickAction(leftHand.getSlot(0), rightHand.getSlot(0));
-
- for (DecoratedSlotComponent component : mainInventory.getSlots()) {
- component.addAction(pickIntoLeft);
- }
- }
-
- private Consumer createPickAction(ItemSlot toWithoutCtrl, ItemSlot toWithCtrl) {
- return button -> {
-
+
+ ItemSlot left = leftHand.getSlot(0);
+ ItemSlot right = rightHand.getSlot(0);
+
+ Supplier handSlot = () -> {
boolean hasCtrl = InputTracker.isKeyPressed(GLFW.GLFW_KEY_LEFT_CONTROL)
|| InputTracker.isKeyPressed(GLFW.GLFW_KEY_RIGHT_CONTROL);
- ItemSlot to = hasCtrl ? toWithCtrl : toWithoutCtrl;
- ItemSlot from = ((DecoratedSlotComponent) button).getSlot();
+ return hasCtrl ? left : right;
+ };
+
+ Consumer pickAll = createPickAllAction(handSlot);
- ItemData fromData = from.getContents();
- int fromAmount = from.getAmount();
+ for (DecoratedSlotComponent component : mainInventory.getSlots()) {
+ component.addAction(pickAll);
+ component.addListener(KeyEvent.class, createRMBAction(component.getSlot(), handSlot));
+ }
+ }
+
+ private Consumer createPickAllAction(Supplier handSlotChooser) {
+ return button -> {
- ItemData toData = to.getContents();
- int toAmount = to.getAmount();
+ ItemSlot handSlot = handSlotChooser.get();
+ ItemSlot invSlot = ((DecoratedSlotComponent) button).getSlot();
- from.setContents(toData, toAmount);
- to.setContents(fromData, fromAmount);
+ if (Items.pour(handSlot, invSlot) == 0) {
+ if (!Items.swap(handSlot, invSlot)) {
+ return;
+ }
+ }
requestReassembly();
};
}
+ private InputListener createRMBAction(ItemSlot invSlot, Supplier handSlotChooser) {
+ return input -> {
+
+ if (input.isPress() && input.isRightMouseButton()) {
+ ItemSlot handSlot = handSlotChooser.get();
+
+ boolean success = false;
+
+ if (handSlot.isEmpty()) {
+ success = Items.pour(invSlot, handSlot, invSlot.getAmount() / 2) != 0;
+ }
+
+ if (!success) {
+ success = Items.pour(handSlot, invSlot, 1) != 0;
+ }
+
+ if (!success) {
+ success = Items.swap(handSlot, invSlot);
+ }
+
+ if (success) {
+ requestReassembly();
+ }
+
+ return true;
+ }
+
+ return false;
+
+ };
+ }
+
}
diff --git a/src/main/resources/assets/textures/items/Stick.png b/src/main/resources/assets/textures/items/Stick.png
new file mode 100644
index 0000000..7271702
Binary files /dev/null and b/src/main/resources/assets/textures/items/Stick.png differ