Added item containers

- Added ItemDataContainer. It is an item that has a container
  - Added Test:CardboardBackpack
- Added back inventory GUIs
  - Now in window form!
    - *not interactive (don't sue us)
- Hand background icons now only render when an inventory is open
- Removed intrinsic player inventory because we're hardcore
This commit is contained in:
OLEGSHA 2021-09-10 23:11:15 +03:00
parent 782b3ef553
commit 30464febf6
15 changed files with 318 additions and 48 deletions

View File

@ -40,7 +40,8 @@ public class HUDManager implements HUDWorkspace {
@Override
public void openContainer(InventoryComponent component) {
System.err.println("openContainer NYI");
InventoryWindow window = new InventoryWindow("Window", component);
layer.getWindowManager().addWindow(window);
}
public void closeEverything() {

View File

@ -31,7 +31,6 @@ import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutBorderHorizontal;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutHorizontal;
import ru.windcorp.progressia.client.graphics.model.Renderable;
import ru.windcorp.progressia.client.graphics.world.LocalPlayer;
import ru.windcorp.progressia.client.world.entity.SpeciesRender;
import ru.windcorp.progressia.client.world.entity.SpeciesRenderRegistry;
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
@ -59,7 +58,7 @@ public class HandsHUD extends Component {
Renderable renderable = slotComponent.assembleToRenderable();
target.addCustomRenderer(renderer -> {
float scale = player.getEntity().getSelectedHand() == slotComponent.getSlot().getContainer() ? 2 : 1;
float scale = manager.getHand() == slotComponent.getSlot().getContainer() ? 2 : 1;
renderer.pushTransform()
.translate(getX() + getWidth() / 2, getY(), 0)
.scale(selected.updateForFrame(scale));
@ -88,11 +87,11 @@ public class HandsHUD extends Component {
}
}
private final LocalPlayer player;
private final HUDManager manager;
public HandsHUD(String name, HUDManager manager) {
super(name);
this.player = manager.getPlayer();
this.manager = manager;
EntityDataPlayer entity = manager.getPlayerEntity();
String speciesId = entity.getSpecies().getId();
@ -129,7 +128,7 @@ public class HandsHUD extends Component {
}
private boolean shouldRenderHandPlaceholder() {
return true;
return manager.isInventoryShown();
}
}

View File

@ -25,6 +25,7 @@ import ru.windcorp.progressia.client.graphics.input.KeyMatcher;
import ru.windcorp.progressia.client.graphics.input.WheelScrollEvent;
import ru.windcorp.progressia.common.Units;
import ru.windcorp.progressia.common.world.item.ItemContainer;
import ru.windcorp.progressia.common.world.item.ItemDataContainer;
import ru.windcorp.progressia.common.world.item.ItemSlot;
import ru.windcorp.progressia.common.world.item.Items;
@ -120,7 +121,15 @@ public class InteractiveSlotComponent extends Button {
boolean success = false;
if (handSlot.isEmpty()) {
if (handSlot.isEmpty() && invSlot.getAmount() == 1 && invSlot.getContents() instanceof ItemDataContainer) {
ItemDataContainer item = (ItemDataContainer) invSlot.getContents();
if (item.canOpenContainer()) {
workspace.openContainer(new SimpleInventoryComponent(item.getContainer(), workspace));
success = true;
}
}
if (!success && handSlot.isEmpty()) {
success = Items.pour(invSlot, handSlot, invSlot.getAmount() / 2) != 0;
}

View File

@ -20,6 +20,7 @@ package ru.windcorp.progressia.client.graphics.world.hud;
import java.util.Collection;
import ru.windcorp.progressia.client.graphics.gui.Component;
import ru.windcorp.progressia.common.world.item.ItemContainer;
public abstract class InventoryComponent extends Component {
@ -27,6 +28,8 @@ public abstract class InventoryComponent extends Component {
super(name);
}
public abstract ItemContainer getContainer();
public abstract Collection<InteractiveSlotComponent> getSlots();
}

View File

@ -0,0 +1,104 @@
/*
* 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.client.graphics.world.hud;
import java.util.function.Consumer;
import glm.vec._4.Vec4;
import ru.windcorp.progressia.client.graphics.Colors;
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
import ru.windcorp.progressia.client.graphics.font.Font;
import ru.windcorp.progressia.client.graphics.font.Typeface;
import ru.windcorp.progressia.client.graphics.gui.Button;
import ru.windcorp.progressia.client.graphics.gui.Component;
import ru.windcorp.progressia.client.graphics.gui.Group;
import ru.windcorp.progressia.client.graphics.gui.Label;
import ru.windcorp.progressia.client.graphics.gui.Panel;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutBorderHorizontal;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutFill;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical;
import ru.windcorp.progressia.client.localization.MutableString;
import ru.windcorp.progressia.client.localization.MutableStringLocalized;
public class InventoryWindow extends Panel {
private static final String CLOSE_CHAR = "\u2715";
private static final Vec4 CLOSE_BUTTON_IDLE = Colors.toVector(0xFFBC1515);
private static final Vec4 CLOSE_BUTTON_HOVER = Colors.toVector(0xFFFA6464);
private static final Vec4 CLOSE_BUTTON_PRESSED = Colors.BLACK;
public InventoryWindow(String name, InventoryComponent component) {
super(name, new LayoutVertical(15, 15));
Group titleBar = new Group(getName() + ".TitleBar", new LayoutBorderHorizontal());
titleBar.addChild(createLabel(component).setLayoutHint(LayoutBorderHorizontal.CENTER));
titleBar.addChild(createCloseButton().setLayoutHint(LayoutBorderHorizontal.RIGHT));
addChild(titleBar);
addChild(component);
}
private Label createLabel(InventoryComponent component) {
String translationKey = "Inventory." + component.getContainer().getId() + ".Title";
MutableString titleText = new MutableStringLocalized(translationKey);
Font titleFont = new Font().deriveBold().withColor(Colors.BLACK).withAlign(Typeface.ALIGN_LEFT);
return new Label(getName() + ".Title", titleFont, titleText);
}
private void doWithManager(Consumer<WindowedHUD> action) {
Component parent = getParent();
if (parent instanceof WindowedHUD) {
action.accept((WindowedHUD) parent);
}
}
private Component createCloseButton() {
Button button = new Button(getName() + ".CloseButton", CLOSE_CHAR) {
@Override
protected void assembleSelf(RenderTarget target) {
Vec4 color = CLOSE_BUTTON_IDLE;
if (isPressed()) {
color = CLOSE_BUTTON_PRESSED;
} else if (isHovered()) {
color = CLOSE_BUTTON_HOVER;
}
if (hasLabel()) {
getLabel().setFont(getLabel().getFont().withColor(color));
}
}
};
button.addAction(b -> doWithManager(manager -> manager.closeWindow(this)));
button.setLayout(new LayoutFill());
int height = button.getLabel().getFont().getHeight(button.getLabel().getCurrentText());
button.setPreferredSize(height, height);
return button;
}
}

View File

@ -23,8 +23,10 @@ import com.google.common.eventbus.Subscribe;
import ru.windcorp.progressia.client.events.NewLocalEntityEvent;
import ru.windcorp.progressia.client.graphics.GUI;
import ru.windcorp.progressia.client.graphics.gui.Component;
import ru.windcorp.progressia.client.graphics.gui.Components;
import ru.windcorp.progressia.client.graphics.gui.GUILayer;
import ru.windcorp.progressia.client.graphics.gui.Group;
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.Input;
@ -33,6 +35,7 @@ import ru.windcorp.progressia.test.TestPlayerControls;
public class LayerHUD extends GUILayer {
private final HUDManager manager;
private WindowedHUD windowManager = null;
private boolean showInventory = false;
private boolean isHidden = false;
@ -58,12 +61,25 @@ public class LayerHUD extends GUILayer {
}
getRoot().addChild(new PermanentHUD(getName() + ".Permanent", manager));
getRoot().addChild(Components.hide(new InventoryHUD(getName() + ".Equipment", manager), () -> !showInventory));
getRoot().addChild(Components.hide(new CursorHUD(getName() + ".Equipment", manager.getPlayerEntity()), () -> !showInventory));
Component inventoryGroup = new Group(getName() + ".InventoryGroup", new LayoutFill());
inventoryGroup.addChild(new InventoryHUD(getName() + ".Equipment", manager));
windowManager = new WindowedHUD(getName() + ".Windows");
inventoryGroup.addChild(windowManager);
inventoryGroup.addChild(new CursorHUD(getName() + ".Cursor", manager.getPlayerEntity()));
getRoot().addChild(Components.hide(inventoryGroup, () -> !showInventory));
getRoot().requestReassembly();
}
public WindowedHUD getWindowManager() {
return windowManager;
}
public boolean isInventoryShown() {
return showInventory;
}

View File

@ -31,11 +31,13 @@ import ru.windcorp.progressia.common.world.item.ItemContainer;
public class SimpleInventoryComponent extends InventoryComponent {
private final Group slots = new Group("Inventory.Slots", new LayoutGrid(15));
private final Group slots = new Group("Inventory.Slots", new LayoutGrid(0, 15));
private final Collection<InteractiveSlotComponent> slotCollection = new ArrayList<>();
private final ItemContainer container;
public SimpleInventoryComponent(ItemContainer container, HUDWorkspace workspace) {
super("Inventory");
this.container = container;
setLayout(new LayoutBorderHorizontal(15));
@ -79,6 +81,11 @@ public class SimpleInventoryComponent extends InventoryComponent {
slotCollection.add(component);
}
@Override
public ItemContainer getContainer() {
return container;
}
@Override
public Collection<InteractiveSlotComponent> getSlots() {
return slotCollection;

View File

@ -0,0 +1,48 @@
/*
* 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.client.graphics.world.hud;
import ru.windcorp.progressia.client.graphics.gui.Component;
public class WindowedHUD extends Component {
public WindowedHUD(String name) {
super(name);
setLayout(null);
}
public void addWindow(InventoryWindow window) {
addChild(window);
window.setSize(window.getPreferredSize());
centerWindow(window);
}
public void closeWindow(InventoryWindow window) {
removeChild(window);
requestReassembly();
}
private void centerWindow(InventoryWindow window) {
window.setPosition(
(getWidth() - window.getWidth()) / 2,
(getHeight() - window.getHeight()) / 2
);
}
}

View File

@ -17,22 +17,16 @@
*/
package ru.windcorp.progressia.common.world.entity;
import ru.windcorp.progressia.common.Units;
import ru.windcorp.progressia.common.state.IntStateField;
import ru.windcorp.progressia.common.state.ObjectStateField;
import ru.windcorp.progressia.common.world.item.ItemContainerEquipment;
import ru.windcorp.progressia.common.world.item.ItemContainerHand;
import ru.windcorp.progressia.common.world.item.ItemContainerMixedSimple;
public class EntityDataPlayer extends EntityData {
private final ObjectStateField<SpeciesDatalet> speciesDatalet = field("Core:SpeciesDatalet").setShared()
.of(SpeciesDataRegistry.getInstance().getCodec()).build();
private final ObjectStateField<ItemContainerMixedSimple> inventory = field("Core:Inventory").setShared().def(
() -> new ItemContainerMixedSimple("Core:PlayerInventory", Units.get(15, "kg"), Units.get(50, "L"))
).build();
private final IntStateField selectedHand = field("Core:SelectedHand").setShared().ofInt().build();
public EntityDataPlayer(String id, SpeciesData species) {
@ -41,10 +35,6 @@ public class EntityDataPlayer extends EntityData {
setSpecies(species);
}
public ItemContainerMixedSimple getInventory() {
return inventory.get(this);
}
private void setSpecies(SpeciesData species) {
speciesDatalet.setNow(this, species.createDatalet());
setCollisionModel(species.getCollisionModel());

View File

@ -28,10 +28,16 @@ public class ItemContainerMixedSimple extends ItemContainerMixed {
private final float volumeLimit;
public ItemContainerMixedSimple(String id, float massLimit, float volumeLimit) {
this(id, massLimit, volumeLimit, 1);
}
public ItemContainerMixedSimple(String id, float massLimit, float volumeLimit, int startingSlots) {
super(id);
this.list = new ArrayList<>();
this.massLimit = massLimit;
this.volumeLimit = volumeLimit;
addSlots(startingSlots);
}
@Override

View File

@ -0,0 +1,75 @@
/*
* 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;
import ru.windcorp.progressia.common.state.ObjectStateField;
public class ItemDataContainer extends ItemData {
private final ObjectStateField<ItemContainer> container = field("Core:Contents").def(this::createContainer).build();
private final float ownMass;
private final float containerMassLimit;
private final float ownVolume;
private final float containerVolumeLimit;
private final boolean containerContributesVolume;
public ItemDataContainer(
String id,
float ownMass,
float containerMassLimit,
float ownVolume,
float containerVolumeLimit,
boolean containerContributesVolume
) {
super(id);
this.ownMass = ownMass;
this.containerMassLimit = containerMassLimit;
this.ownVolume = ownVolume;
this.containerVolumeLimit = containerVolumeLimit;
this.containerContributesVolume = containerContributesVolume;
}
protected ItemContainer createContainer() {
return new ItemContainerMixedSimple(getId(), containerMassLimit, containerVolumeLimit, 10);
}
public ItemContainer getContainer() {
return container.get(this);
}
public boolean canOpenContainer() {
return true;
}
@Override
public float getMass() {
return ownMass + getContainer().getMass();
}
@Override
public float getVolume() {
if (containerContributesVolume) {
return ownVolume + getContainer().getVolume();
} else {
return ownVolume;
}
}
}

View File

@ -63,14 +63,8 @@ public class PlayerManager {
private EntityDataPlayer spawnPlayerEntity(String login) {
EntityDataPlayer player = (EntityDataPlayer) EntityDataRegistry.getInstance().create("Core:Player");
player.getInventory().addSlots(10);
player.getInventory().getSlot(3).setContents(ItemDataRegistry.getInstance().create("Test:Stick"), 7);
player.getInventory().getSlot(5).setContents(ItemDataRegistry.getInstance().create("Test:Stick"), 4);
player.getInventory().getSlot(9).setContents(ItemDataRegistry.getInstance().create("Test:RedGraniteCobblestone"), 1);
player.getInventory().getSlot(6).setContents(ItemDataRegistry.getInstance().create("Test:MoonTypeIceCream"), 1);
player.getHand(0).slot().setContents(ItemDataRegistry.getInstance().create("Test:Stick"), 7);
player.getEquipmentSlot(0).slot().setContents(ItemDataRegistry.getInstance().create("Test:CardboardBackpack"), 1);
player.setPosition(getServer().getWorld().getGenerator().suggestSpawnLocation());
player.setUpVector(new Vec3(0, 0, 1));

View File

@ -54,6 +54,7 @@ import ru.windcorp.progressia.common.world.block.*;
import ru.windcorp.progressia.common.world.entity.*;
import ru.windcorp.progressia.common.world.io.ChunkIO;
import ru.windcorp.progressia.common.world.item.ItemData;
import ru.windcorp.progressia.common.world.item.ItemDataContainer;
import ru.windcorp.progressia.common.world.item.ItemDataRegistry;
import ru.windcorp.progressia.common.world.item.ItemDataSimple;
import ru.windcorp.progressia.common.world.rels.AbsFace;
@ -133,7 +134,7 @@ public class TestContent {
register(new BlockData("Test:TemporaryLeaves"));
register(new BlockRenderTransparentCube("Test:TemporaryLeaves", getBlockTexture("TemporaryLeaves")));
// Sic, using Glass logic for leaves because Test
// Sic, using Glass logic for leaves because Test
register(new TestBlockLogicGlass("Test:TemporaryLeaves"));
register(new BlockData("Test:StatieSpawner"));
@ -244,6 +245,19 @@ public class TestContent {
registerSimplestItem("MoonTypeIceCream", Units.get("200 g"), Units.get("1 L"));
registerSimplestItem("Stick", Units.get("260 g"), Units.get("0.5 L"));
registerSimplestItem("RedGraniteCobblestone", Units.get("4 kg"), Units.get("1500 cm^3"));
registerItem(
"Test:CardboardBackpack",
s -> new ItemDataContainer(
"Test:CardboardBackpack",
Units.get("0.7 kg"), // Own mass
Units.get("5 kg"), // Container mass limit
Units.get("125 L"), // Own volume
Units.get("125 L"), // Container volume limit
false // Whether container contents contribute to item volume
)
);
register(new ItemRenderSimple("Test:CardboardBackpack", getItemTexture("CardboardBackpack")));
}
private static void registerSimplestBlock(String name) {

View File

@ -23,3 +23,5 @@ LayerTestGUI.IsVSync = VSync: %5s (F12)
LayerButtonTest.Title = Button Test
LayerInventory.Title = Player
Inventory.Test:CardboardBackpack.Title = Cardboard Backpack

View File

@ -23,3 +23,5 @@ LayerTestGUI.IsVSync = Верт. синхр.: %5s (F12)
LayerButtonTest.Title = Тест Кнопок
LayerInventory.Title = Игрок
Inventory.Test:CardboardBackpack.Title = Картонный рюкзак