Added stack merging, RMB actions, Sticks and fixed an unholy bug

- Added Test:Stick
- When left-clicking, stacks that can merge will
- Added right-clicking behavior straight from Minecraft
- hooooooly sh*t man StatefulObject.equals was totally broken omfg how
tf i did notice :o
This commit is contained in:
OLEGSHA 2021-08-30 18:09:08 +03:00
parent b3ac7b6afe
commit 040a4f7fd7
Signed by: OLEGSHA
GPG Key ID: E57A4B08D64AFF7A
7 changed files with 198 additions and 22 deletions

View File

@ -235,7 +235,7 @@ public abstract class StatefulObject extends Namespaced implements Encodable {
StatefulObject statefulObj = (StatefulObject) obj; StatefulObject statefulObj = (StatefulObject) obj;
if (statefulObj.getId().equals(this.getId())) if (!statefulObj.getId().equals(this.getId()))
return false; return false;
return true; return true;

View File

@ -94,6 +94,21 @@ public class ItemSlot implements Encodable {
return amount == 0; 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() { private synchronized void checkState() {
if ((contents == null) != (amount == 0)) { if ((contents == null) != (amount == 0)) {
if (contents == null) { if (contents == null) {

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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() {
}
}

View File

@ -65,7 +65,8 @@ public class PlayerManager {
player.getInventory().addSlots(10); 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.getInventory().getSlot(6).setContents(ItemDataRegistry.getInstance().create("Test:MoonTypeIceCream"), 1);
player.setPosition(getServer().getWorld().getGenerator().suggestSpawnLocation()); player.setPosition(getServer().getWorld().getGenerator().suggestSpawnLocation());

View File

@ -106,7 +106,7 @@ public class TestContent {
register(new BlockRenderNone("Test:Air")); register(new BlockRenderNone("Test:Air"));
register(new TestBlockLogicAir("Test:Air")); register(new TestBlockLogicAir("Test:Air"));
placeableBlacklist.add("Test:Air"); placeableBlacklist.add("Test:Air");
registerSimplestBlock("Dirt"); registerSimplestBlock("Dirt");
registerSimplestBlock("Chernozem"); registerSimplestBlock("Chernozem");
registerSimplestBlock("Stone"); registerSimplestBlock("Stone");
@ -244,6 +244,7 @@ public class TestContent {
private static void registerItems() { private static void registerItems() {
registerSimplestItem("MoonTypeIceCream", Units.get("200 g"), Units.get("1 L")); 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) { private static void registerSimplestBlock(String name) {

View File

@ -18,6 +18,7 @@
package ru.windcorp.progressia.test.inv; package ru.windcorp.progressia.test.inv;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier;
import org.lwjgl.glfw.GLFW; 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.Panel;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign; import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutFill; 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.client.graphics.model.Renderable;
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer; import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
import ru.windcorp.progressia.common.world.item.ItemContainer; 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.ItemSlot;
import ru.windcorp.progressia.common.world.item.Items;
public class InventoryScreen extends Component { public class InventoryScreen extends Component {
@ -131,34 +134,72 @@ public class InventoryScreen extends Component {
} }
private void addListeners(InventoryComponent mainInventory) { private void addListeners(InventoryComponent mainInventory) {
Consumer<BasicButton> pickIntoLeft = createPickAction(leftHand.getSlot(0), rightHand.getSlot(0));
ItemSlot left = leftHand.getSlot(0);
for (DecoratedSlotComponent component : mainInventory.getSlots()) { ItemSlot right = rightHand.getSlot(0);
component.addAction(pickIntoLeft);
} Supplier<ItemSlot> handSlot = () -> {
}
private Consumer<BasicButton> createPickAction(ItemSlot toWithoutCtrl, ItemSlot toWithCtrl) {
return button -> {
boolean hasCtrl = InputTracker.isKeyPressed(GLFW.GLFW_KEY_LEFT_CONTROL) boolean hasCtrl = InputTracker.isKeyPressed(GLFW.GLFW_KEY_LEFT_CONTROL)
|| InputTracker.isKeyPressed(GLFW.GLFW_KEY_RIGHT_CONTROL); || InputTracker.isKeyPressed(GLFW.GLFW_KEY_RIGHT_CONTROL);
ItemSlot to = hasCtrl ? toWithCtrl : toWithoutCtrl; return hasCtrl ? left : right;
ItemSlot from = ((DecoratedSlotComponent) button).getSlot(); };
Consumer<BasicButton> pickAll = createPickAllAction(handSlot);
ItemData fromData = from.getContents(); for (DecoratedSlotComponent component : mainInventory.getSlots()) {
int fromAmount = from.getAmount(); component.addAction(pickAll);
component.addListener(KeyEvent.class, createRMBAction(component.getSlot(), handSlot));
}
}
private Consumer<BasicButton> createPickAllAction(Supplier<ItemSlot> handSlotChooser) {
return button -> {
ItemData toData = to.getContents(); ItemSlot handSlot = handSlotChooser.get();
int toAmount = to.getAmount(); ItemSlot invSlot = ((DecoratedSlotComponent) button).getSlot();
from.setContents(toData, toAmount); if (Items.pour(handSlot, invSlot) == 0) {
to.setContents(fromData, fromAmount); if (!Items.swap(handSlot, invSlot)) {
return;
}
}
requestReassembly(); requestReassembly();
}; };
} }
private InputListener<KeyEvent> createRMBAction(ItemSlot invSlot, Supplier<ItemSlot> 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;
};
}
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 775 B