Added the concept of inventories

I'll end myself if I spend any more time on this neverending commit
This commit is contained in:
OLEGSHA 2021-10-17 14:02:54 +03:00
parent 30464febf6
commit c6e6dc6851
Signed by: OLEGSHA
GPG Key ID: E57A4B08D64AFF7A
32 changed files with 871 additions and 47 deletions

View File

@ -21,6 +21,7 @@ package ru.windcorp.progressia.client.graphics.world;
import org.apache.logging.log4j.LogManager;
import ru.windcorp.progressia.client.Client;
import ru.windcorp.progressia.client.events.ClientEvent;
import ru.windcorp.progressia.client.events.NewLocalEntityEvent;
import ru.windcorp.progressia.client.world.WorldRender;
import ru.windcorp.progressia.client.world.entity.EntityRenderable;
@ -83,8 +84,9 @@ public class LocalPlayer {
}
if (playerEntity != lastKnownEntity) {
ClientEvent event = new NewLocalEntityEvent.Immutable(getClient(), playerEntity, lastKnownEntity);
this.lastKnownEntity = playerEntity;
getClient().postEvent(new NewLocalEntityEvent.Immutable(getClient(), playerEntity, lastKnownEntity));
getClient().postEvent(event);
}
return playerEntity;

View File

@ -17,8 +17,19 @@
*/
package ru.windcorp.progressia.client.graphics.world.hud;
import com.google.common.eventbus.Subscribe;
import ru.windcorp.progressia.client.Client;
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.world.item.inventory.InventoryComponent;
import ru.windcorp.progressia.client.world.item.inventory.InventoryRender;
import ru.windcorp.progressia.client.world.item.inventory.InventoryRenderRegistry;
import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.common.world.item.inventory.Inventory;
import ru.windcorp.progressia.common.world.item.inventory.InventoryClosingEvent;
import ru.windcorp.progressia.common.world.item.inventory.InventoryOpenedEvent;
public class HUDManager implements HUDWorkspace {
@ -28,6 +39,17 @@ public class HUDManager implements HUDWorkspace {
public HUDManager(Client client) {
this.client = client;
this.layer = new LayerHUD(this);
client.subscribe(new Object() {
@Subscribe
public void onLocalEntityChanged(NewLocalEntityEvent e) {
if (e.getNewEntity() != null) {
e.getNewEntity().subscribe(HUDManager.this);
}
if (e.getPreviousEntity() != null) {
e.getPreviousEntity().unsubscribe(HUDManager.this);
}
}
});
}
public void install() {
@ -39,8 +61,8 @@ public class HUDManager implements HUDWorkspace {
}
@Override
public void openContainer(InventoryComponent component) {
InventoryWindow window = new InventoryWindow("Window", component);
public void openInventory(InventoryComponent component) {
InventoryWindow window = new InventoryWindow("Window", component, this);
layer.getWindowManager().addWindow(window);
}
@ -68,5 +90,36 @@ public class HUDManager implements HUDWorkspace {
public Client getClient() {
return client;
}
@Subscribe
private void onInventoryOpened(InventoryOpenedEvent event) {
Inventory inventory = event.getInventory();
InventoryRender render = InventoryRenderRegistry.getInstance().get(inventory.getId());
if (render == null) {
throw CrashReports.report(null, "InventoryRender not found for ID %s", inventory.getId());
}
try {
InventoryComponent component = render.createComponent(inventory, this);
openInventory(component);
} catch (Exception e) {
throw CrashReports.report(null, "Could not open inventory %s", inventory.getId());
}
}
@Subscribe
private void onInventoryClosing(InventoryClosingEvent event) {
Inventory inventory = event.getInventory();
for (Component component : layer.getWindowManager().getChildren()) {
if (component instanceof InventoryWindow) {
InventoryWindow window = (InventoryWindow) component;
if (window.getContent().getInventory() == inventory) {
layer.getWindowManager().closeWindow(window);
}
}
}
}
}

View File

@ -19,6 +19,7 @@ package ru.windcorp.progressia.client.graphics.world.hud;
import ru.windcorp.progressia.client.Client;
import ru.windcorp.progressia.client.graphics.world.LocalPlayer;
import ru.windcorp.progressia.client.world.item.inventory.InventoryComponent;
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
import ru.windcorp.progressia.common.world.item.ItemContainerHand;
@ -38,6 +39,6 @@ public interface HUDWorkspace {
return getClient().getLocalPlayer().getEntity().getSelectedHand();
}
void openContainer(InventoryComponent component);
void openInventory(InventoryComponent component);
}

View File

@ -121,12 +121,8 @@ public class InteractiveSlotComponent extends Button {
boolean success = false;
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 (handSlot.isEmpty()) {
success = tryToOpen(invSlot);
}
if (!success && handSlot.isEmpty()) {
@ -146,6 +142,18 @@ public class InteractiveSlotComponent extends Button {
}
}
private boolean tryToOpen(ItemSlot invSlot) {
if (invSlot.getAmount() != 1) {
return false;
}
if (!(invSlot.getContents() instanceof ItemDataContainer)) {
return false;
}
ItemDataContainer item = (ItemDataContainer) invSlot.getContents();
return item.open(workspace.getPlayerEntity()) != null;
}
private void onSingleMoveAction(boolean fromHand) {
ItemSlot handSlot = workspace.getHand().slot();
ItemSlot invSlot = getSlot();

View File

@ -17,8 +17,6 @@
*/
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;
@ -34,6 +32,7 @@ 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;
import ru.windcorp.progressia.client.world.item.inventory.InventoryComponent;
public class InventoryWindow extends Panel {
@ -41,13 +40,18 @@ public class InventoryWindow extends Panel {
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;
private final InventoryComponent content;
private final HUDWorkspace workspace;
public InventoryWindow(String name, InventoryComponent component) {
public InventoryWindow(String name, InventoryComponent component, HUDWorkspace workspace) {
super(name, new LayoutVertical(15, 15));
this.content = component;
this.workspace = workspace;
Group titleBar = new Group(getName() + ".TitleBar", new LayoutBorderHorizontal());
titleBar.addChild(createLabel(component).setLayoutHint(LayoutBorderHorizontal.CENTER));
titleBar.addChild(createCloseButton().setLayoutHint(LayoutBorderHorizontal.RIGHT));
titleBar.addChild(createCloseButton(component).setLayoutHint(LayoutBorderHorizontal.RIGHT));
addChild(titleBar);
@ -55,21 +59,22 @@ public class InventoryWindow extends Panel {
}
private Label createLabel(InventoryComponent component) {
String translationKey = "Inventory." + component.getContainer().getId() + ".Title";
String translationKey = "Inventory." + component.getInventory().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) {
private WindowedHUD getManager() {
Component parent = getParent();
if (parent instanceof WindowedHUD) {
action.accept((WindowedHUD) parent);
return (WindowedHUD) parent;
}
return null;
}
private Component createCloseButton() {
private Component createCloseButton(InventoryComponent component) {
Button button = new Button(getName() + ".CloseButton", CLOSE_CHAR) {
@ -91,7 +96,18 @@ public class InventoryWindow extends Panel {
};
button.addAction(b -> doWithManager(manager -> manager.closeWindow(this)));
button.addAction(b -> {
content.getInventory().close(workspace.getPlayerEntity());
WindowedHUD manager = getManager();
if (manager == null) {
return;
}
manager.closeWindow(this);
});
button.setLayout(new LayoutFill());
@ -100,5 +116,9 @@ public class InventoryWindow extends Panel {
return button;
}
public InventoryComponent getContent() {
return content;
}
}

View File

@ -19,6 +19,7 @@ package ru.windcorp.progressia.client.graphics.world.hud;
import java.util.function.BooleanSupplier;
import glm.mat._4.Mat4;
import ru.windcorp.progressia.client.graphics.Colors;
import ru.windcorp.progressia.client.graphics.flat.FlatRenderProgram;
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
import ru.windcorp.progressia.client.graphics.font.Font;
@ -26,18 +27,22 @@ import ru.windcorp.progressia.client.graphics.gui.Component;
import ru.windcorp.progressia.client.graphics.gui.DynamicLabel;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
import ru.windcorp.progressia.client.graphics.model.Renderable;
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
import ru.windcorp.progressia.client.graphics.model.Shapes.PgmBuilder;
import ru.windcorp.progressia.client.graphics.texture.Texture;
import ru.windcorp.progressia.client.world.item.ItemRenderRegistry;
import ru.windcorp.progressia.client.world.item.ItemRenderable;
import ru.windcorp.progressia.common.world.item.ItemContainer;
import ru.windcorp.progressia.common.world.item.ItemData;
import ru.windcorp.progressia.common.world.item.ItemDataContainer;
import ru.windcorp.progressia.common.world.item.ItemSlot;
public class SlotComponent extends Component {
static final float TEXTURE_SIZE = 24;
private static Renderable containerOpenDecoration = null;
private final ItemContainer container;
private final int index;
@ -62,6 +67,13 @@ public class SlotComponent extends Component {
addChild(new DynamicLabel(getName() + ".Size", sizeFont, () -> amountDisplayString, getPreferredSize().x));
setLayout(new LayoutAlign(0, 0, 0));
if (containerOpenDecoration == null) {
containerOpenDecoration = new PgmBuilder(
FlatRenderProgram.getDefault(),
HUDTextures.getHUDTexture("DecorationContainerOpen")
).setSize(TEXTURE_SIZE + 2).setOrigin(-1, -1, 0).create();
}
}
public ItemSlot getSlot() {
@ -83,11 +95,11 @@ public class SlotComponent extends Component {
setBackgroundDisplayCondition(when);
return this;
}
public SlotComponent setBackground(Texture texture) {
return setBackground(texture, null);
}
public SlotComponent setBackgroundDisplayCondition(BooleanSupplier backgroundCondition) {
this.backgroundCondition = backgroundCondition;
return this;
@ -120,13 +132,14 @@ public class SlotComponent extends Component {
}
private void assembleItem(RenderTarget target) {
target.pushTransform(new Mat4().translate(getX(), getY(), 0).scale(scale));
target.pushTransform(new Mat4().translate(getX(), getY(), 0).scale(scale, scale, 1));
target.addCustomRenderer(renderer -> {
updateItemRenderer();
if (itemRenderer != null) {
itemRenderer.render(renderer);
renderDecorations(renderer);
} else if (background != null) {
if (backgroundCondition == null || backgroundCondition.getAsBoolean()) {
background.render(renderer);
@ -137,4 +150,17 @@ public class SlotComponent extends Component {
target.popTransform();
}
private void renderDecorations(ShapeRenderHelper renderer) {
ItemData contents = getSlot().getContents();
if (contents instanceof ItemDataContainer) {
ItemDataContainer asContainer = (ItemDataContainer) contents;
if (asContainer.isOpen()) {
renderer.pushColorMultiplier().mul(Colors.BLUE);
containerOpenDecoration.render(renderer);
renderer.popColorMultiplier();
}
}
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.world.item.inventory;
import java.util.Collection;
import ru.windcorp.progressia.client.graphics.gui.Component;
import ru.windcorp.progressia.client.graphics.world.hud.InteractiveSlotComponent;
import ru.windcorp.progressia.common.world.item.ItemContainer;
public abstract class ContainerComponent extends Component {
public ContainerComponent(String name) {
super(name);
}
public abstract ItemContainer getContainer();
public abstract Collection<InteractiveSlotComponent> getSlots();
}

View File

@ -15,7 +15,7 @@
* 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;
package ru.windcorp.progressia.client.world.item.inventory;
import java.util.ArrayList;
import java.util.Collection;
@ -27,15 +27,19 @@ import ru.windcorp.progressia.client.graphics.gui.Group;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutBorderHorizontal;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutBorderVertical;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutGrid;
import ru.windcorp.progressia.client.graphics.world.hud.Bar;
import ru.windcorp.progressia.client.graphics.world.hud.HUDWorkspace;
import ru.windcorp.progressia.client.graphics.world.hud.InteractiveSlotComponent;
import ru.windcorp.progressia.common.world.item.ItemContainer;
public class SimpleInventoryComponent extends InventoryComponent {
public class ContainerComponentSimple extends ContainerComponent {
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) {
public ContainerComponentSimple(ItemContainer container, HUDWorkspace workspace) {
super("Inventory");
this.container = container;
@ -80,7 +84,7 @@ public class SimpleInventoryComponent extends InventoryComponent {
slots.addChild(component.setLayoutHint(pos));
slotCollection.add(component);
}
@Override
public ItemContainer getContainer() {
return container;

View File

@ -15,21 +15,21 @@
* 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;
package ru.windcorp.progressia.client.world.item.inventory;
import java.util.Collection;
import ru.windcorp.progressia.client.graphics.gui.Component;
import ru.windcorp.progressia.common.world.item.ItemContainer;
import ru.windcorp.progressia.common.world.item.inventory.Inventory;
public abstract class InventoryComponent extends Component {
public InventoryComponent(String name) {
super(name);
}
public abstract ItemContainer getContainer();
public abstract Collection<InteractiveSlotComponent> getSlots();
public abstract Inventory getInventory();
public abstract Collection<? extends ContainerComponent> getContainers();
}

View File

@ -0,0 +1,55 @@
/*
* 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.world.item.inventory;
import java.util.ArrayList;
import java.util.Collection;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutFill;
import ru.windcorp.progressia.client.graphics.world.hud.HUDWorkspace;
import ru.windcorp.progressia.common.world.item.ItemContainer;
import ru.windcorp.progressia.common.world.item.inventory.Inventory;
public class InventoryComponentSimple extends InventoryComponent {
private final Inventory inventory;
private final Collection<ContainerComponentSimple> containers = new ArrayList<>();
public InventoryComponentSimple(String name, Inventory inventory, HUDWorkspace workspace) {
super(name);
setLayout(new LayoutFill());
this.inventory = inventory;
for (ItemContainer container : inventory.getContainers()) {
ContainerComponentSimple component = new ContainerComponentSimple(container, workspace);
containers.add(component);
addChild(component);
}
}
@Override
public Inventory getInventory() {
return inventory;
}
@Override
public Collection<? extends ContainerComponent> getContainers() {
return containers;
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.world.item.inventory;
import ru.windcorp.progressia.client.graphics.world.hud.HUDWorkspace;
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
import ru.windcorp.progressia.common.world.item.inventory.Inventory;
public abstract class InventoryRender extends Namespaced {
public InventoryRender(String id) {
super(id);
}
public abstract InventoryComponent createComponent(Inventory inventory, HUDWorkspace workspace);
}

View File

@ -0,0 +1,30 @@
/*
* 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.world.item.inventory;
import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry;
public class InventoryRenderRegistry extends NamespacedInstanceRegistry<InventoryRender> {
private static final InventoryRenderRegistry INSTANCE = new InventoryRenderRegistry();
public static InventoryRenderRegistry getInstance() {
return INSTANCE;
}
}

View File

@ -0,0 +1,87 @@
/*
* 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.state;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
public class BooleanStateField extends StateField {
public BooleanStateField(
String id,
boolean isLocal,
int index
) {
super(id, isLocal, index);
}
public boolean get(StatefulObject object) {
return object.getStorage().getBoolean(getIndex());
}
public void setNow(StatefulObject object, boolean value) {
object.getStorage().setBoolean(getIndex(), value);
}
public void set(StateChanger changer, boolean value) {
changer.setBoolean(this, value);
}
@Override
public void read(
StatefulObject object,
DataInput input,
IOContext context
)
throws IOException {
object.getStorage().setBoolean(getIndex(), input.readBoolean());
}
@Override
public void write(
StatefulObject object,
DataOutput output,
IOContext context
)
throws IOException {
output.writeBoolean(object.getStorage().getBoolean(getIndex()));
}
@Override
public void copy(StatefulObject from, StatefulObject to) {
setNow(to, get(from));
}
@Override
public int computeHashCode(StatefulObject object) {
return Boolean.hashCode(get(object));
}
@Override
public boolean areEqual(StatefulObject a, StatefulObject b) {
return get(a) == get(b);
}
@Override
public void setDefault(StateStorage storage) {
storage.setBoolean(getIndex(), false);
}
}

View File

@ -22,10 +22,13 @@ import gnu.trove.map.TIntIntMap;
import gnu.trove.map.TIntObjectMap;
import gnu.trove.map.hash.TIntIntHashMap;
import gnu.trove.map.hash.TIntObjectHashMap;
import gnu.trove.set.TIntSet;
import gnu.trove.set.hash.TIntHashSet;
public class HashMapStateStorage extends StateStorage {
private final TIntIntMap ints = new TIntIntHashMap();
private final TIntSet booleans = new TIntHashSet();
private final TIntObjectMap<Object> objects = new TIntObjectHashMap<>();
@Override
@ -38,6 +41,20 @@ public class HashMapStateStorage extends StateStorage {
ints.put(index, value);
}
@Override
public boolean getBoolean(int index) {
return booleans.contains(index);
}
@Override
public void setBoolean(int index, boolean value) {
if (value) {
booleans.add(index);
} else {
booleans.remove(index);
}
}
@Override
public Object getObject(int index) {
return objects.get(index);

View File

@ -85,6 +85,21 @@ public class InspectingStatefulObjectLayout
}
private class Boolean implements StateFieldBuilder.Boolean {
@Override
public BooleanStateField build() {
return registerField(
new BooleanStateField(
id,
isLocal,
fieldIndexCounters.getBooleansThenIncrement()
)
);
}
}
private class Obj<T> implements StateFieldBuilder.Obj<T> {
private final ObjectCodec<T> codec;
@ -123,6 +138,11 @@ public class InspectingStatefulObjectLayout
return new Int();
}
@Override
public Boolean ofBoolean() {
return new Boolean();
}
@Override
public <T> Obj<T> of(ObjectCodec<T> codec, Supplier<T> defaultValue) {
return new Obj<T>(codec, defaultValue);

View File

@ -21,11 +21,13 @@ package ru.windcorp.progressia.common.state;
public class OptimizedStateStorage extends StateStorage {
private final int[] ints;
private final boolean[] booleans;
private final Object[] objects;
public OptimizedStateStorage(PrimitiveCounters sizes) {
this.ints = new int[sizes.getInts()];
this.objects = new Object[sizes.getObjects()];
this.ints = sizes.getInts() == 0 ? null : new int[sizes.getInts()];
this.booleans = sizes.getBooleans() == 0 ? null : new boolean[sizes.getBooleans()];
this.objects = sizes.getObjects() == 0 ? null : new Object[sizes.getObjects()];
}
@Override
@ -38,6 +40,16 @@ public class OptimizedStateStorage extends StateStorage {
ints[index] = value;
}
@Override
public boolean getBoolean(int index) {
return booleans[index];
}
@Override
public void setBoolean(int index, boolean value) {
booleans[index] = value;
}
@Override
public Object getObject(int index) {
return objects[index];

View File

@ -75,6 +75,16 @@ public class OptimizedStatefulObjectLayout
};
}
@Override
public Boolean ofBoolean() {
return new Boolean() {
@Override
public BooleanStateField build() {
return (BooleanStateField) result;
}
};
}
@Override
public <T> Obj<T> of(ObjectCodec<T> codec, Supplier<T> defaultValue) {
return new Obj<T>() {

View File

@ -21,6 +21,7 @@ package ru.windcorp.progressia.common.state;
class PrimitiveCounters {
private int ints = 0;
private int booleans = 0;
private int objects = 0;
public PrimitiveCounters() {
@ -28,6 +29,7 @@ class PrimitiveCounters {
public PrimitiveCounters(PrimitiveCounters copyFrom) {
this.ints = copyFrom.ints;
this.booleans = copyFrom.booleans;
this.objects = copyFrom.objects;
}
@ -39,6 +41,14 @@ class PrimitiveCounters {
return this.ints++;
}
public int getBooleans() {
return booleans;
}
public int getBooleansThenIncrement() {
return this.booleans++;
}
public int getObjects() {
return objects;
}

View File

@ -21,6 +21,7 @@ package ru.windcorp.progressia.common.state;
public interface StateChanger {
void setInt(IntStateField field, int value);
void setBoolean(BooleanStateField field, boolean value);
<T> void setObject(ObjectStateField<T> field, T value);
}

View File

@ -29,12 +29,18 @@ public interface StateFieldBuilder {
IntStateField build();
}
public static interface Boolean {
BooleanStateField build();
}
public static interface Obj<T> {
ObjectStateField<T> build();
}
Int ofInt();
Boolean ofBoolean();
<T> Obj<T> of(ObjectCodec<T> codec, Supplier<T> defaultValue);
default <T> Obj<T> of(Class<T> clazz, Supplier<T> defaultValue) {

View File

@ -24,6 +24,10 @@ public abstract class StateStorage {
public abstract void setInt(int index, int value);
public abstract boolean getBoolean(int index);
public abstract void setBoolean(int index, boolean value);
public abstract Object getObject(int index);
public abstract void setObject(int index, Object object);

View File

@ -17,17 +17,26 @@
*/
package ru.windcorp.progressia.common.world.entity;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import ru.windcorp.progressia.common.state.IntStateField;
import ru.windcorp.progressia.common.state.ObjectStateField;
import ru.windcorp.progressia.common.util.crash.ReportingEventBus;
import ru.windcorp.progressia.common.world.item.ItemContainerEquipment;
import ru.windcorp.progressia.common.world.item.ItemContainerHand;
import ru.windcorp.progressia.common.world.item.inventory.InventoryClosingEvent;
import ru.windcorp.progressia.common.world.item.inventory.InventoryOpenedEvent;
import ru.windcorp.progressia.common.world.item.inventory.InventoryUser;
public class EntityDataPlayer extends EntityData {
public class EntityDataPlayer extends EntityData implements InventoryUser {
private final ObjectStateField<SpeciesDatalet> speciesDatalet = field("Core:SpeciesDatalet").setShared()
.of(SpeciesDataRegistry.getInstance().getCodec()).build();
private final IntStateField selectedHand = field("Core:SelectedHand").setShared().ofInt().build();
private final EventBus eventBus = ReportingEventBus.create("EntityDataPlayer");
public EntityDataPlayer(String id, SpeciesData species) {
super(id);
@ -71,5 +80,23 @@ public class EntityDataPlayer extends EntityData {
public ItemContainerHand getSelectedHand() {
return getHand(getSelectedHandIndex());
}
@Subscribe
private void onInventoryOpened(InventoryOpenedEvent event) {
eventBus.post(event);
}
@Subscribe
private void onInventoryClosed(InventoryClosingEvent event) {
eventBus.post(event);
}
public void subscribe(Object listener) {
eventBus.register(listener);
}
public void unsubscribe(Object listener) {
eventBus.unregister(listener);
}
}

View File

@ -23,6 +23,7 @@ import java.util.function.Consumer;
import ru.windcorp.progressia.common.state.Encodable;
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
import ru.windcorp.progressia.common.world.item.inventory.Inventory;
/**
* A collection of {@link ItemSlot}s representing a single storage unit. A
@ -34,10 +35,20 @@ import ru.windcorp.progressia.common.util.namespaces.Namespaced;
* through <i>n</i> - 1.
*/
public abstract class ItemContainer extends Namespaced implements Encodable, Iterable<ItemSlot> {
private Inventory inventory;
public ItemContainer(String id) {
super(id);
}
public Inventory getInventory() {
return inventory;
}
public void setInventory(Inventory inventory) {
this.inventory = inventory;
}
/**
* Retrieves the slot with the given index.

View File

@ -18,18 +18,21 @@
package ru.windcorp.progressia.common.world.item;
import ru.windcorp.progressia.common.state.ObjectStateField;
import ru.windcorp.progressia.common.world.item.inventory.InventorySimple;
import ru.windcorp.progressia.common.world.item.inventory.InventoryUser;
public class ItemDataContainer extends ItemData {
private final ObjectStateField<ItemContainer> container = field("Core:Contents").def(this::createContainer).build();
private final ObjectStateField<InventorySimple> inventory = field("Core:Contents").setShared().def(this::createInventory)
.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,
@ -46,27 +49,49 @@ public class ItemDataContainer extends ItemData {
this.containerContributesVolume = containerContributesVolume;
}
protected ItemContainer createContainer() {
return new ItemContainerMixedSimple(getId(), containerMassLimit, containerVolumeLimit, 10);
protected InventorySimple createInventory() {
return new InventorySimple(
getId(),
new ItemContainerMixedSimple(getId(), containerMassLimit, containerVolumeLimit, 10)
);
}
public ItemContainer getContainer() {
return container.get(this);
public InventorySimple getInventory() {
return inventory.get(this);
}
public boolean canOpenContainer() {
public boolean isOpen() {
return !getInventory().getUsers().isEmpty();
}
public boolean canOpen(InventoryUser user) {
return true;
}
public synchronized InventorySimple open(InventoryUser user) {
if (isOpen()) {
return null;
} else if (!canOpen(user)) {
return null;
} else {
getInventory().open(user);
return getInventory();
}
}
public synchronized void close() {
getInventory().closeAll();
}
@Override
public float getMass() {
return ownMass + getContainer().getMass();
return ownMass + getInventory().getMass();
}
@Override
public float getVolume() {
if (containerContributesVolume) {
return ownVolume + getContainer().getVolume();
return ownVolume + getInventory().getVolume();
} else {
return ownVolume;
}

View File

@ -0,0 +1,141 @@
/*
* 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.inventory;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
import com.google.common.eventbus.EventBus;
import ru.windcorp.progressia.common.state.Encodable;
import ru.windcorp.progressia.common.state.IOContext;
import ru.windcorp.progressia.common.util.crash.ReportingEventBus;
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
import ru.windcorp.progressia.common.world.item.ItemContainer;
public class Inventory extends Namespaced implements Encodable {
private final ItemContainer[] containers;
private final List<InventoryUser> users = new ArrayList<>();
private EventBus eventBus = null;
public Inventory(String id, ItemContainer... containers) {
super(id);
this.containers = containers;
for (ItemContainer container : containers) {
container.setInventory(this);
}
}
public synchronized void open(InventoryUser user) {
users.add(user);
subscribe(user);
eventBus.post(new InventoryOpenedEvent(this, user));
}
public synchronized void close(InventoryUser user) {
if (eventBus != null) {
eventBus.post(new InventoryClosingEvent(this, user));
}
users.remove(user);
unsubscribe(user);
}
public synchronized void subscribe(Object listener) {
if (eventBus == null) {
eventBus = ReportingEventBus.create("Inventory " + getId());
}
eventBus.register(listener);
}
public synchronized void unsubscribe(Object listener) {
if (eventBus == null) {
return;
}
eventBus.unregister(listener);
}
public synchronized boolean isUser(InventoryUser user) {
return users.contains(user);
}
public synchronized void forEachUser(Consumer<? super InventoryUser> action) {
users.forEach(action);
}
public Collection<InventoryUser> getUsers() {
return users;
}
public synchronized void closeAll() {
while (!users.isEmpty()) {
close(users.get(0));
}
}
public ItemContainer[] getContainers() {
return containers;
}
public synchronized float getMass() {
float sum = 0;
for (ItemContainer container : containers) {
sum += container.getMass();
}
return sum;
}
public synchronized float getVolume() {
float sum = 0;
for (ItemContainer container : containers) {
sum += container.getVolume();
}
return sum;
}
@Override
public synchronized void read(DataInput input, IOContext context) throws IOException {
for (ItemContainer container : containers) {
container.read(input, context);
}
}
@Override
public synchronized void write(DataOutput output, IOContext context) throws IOException {
for (ItemContainer container : containers) {
container.write(output, context);
}
}
@Override
public synchronized void copy(Encodable destination) {
Inventory inventory = (Inventory) destination;
assert inventory.containers.length == containers.length;
for (int i = 0; i < containers.length; ++i) {
containers[i].copy(inventory.containers[i]);
}
}
}

View File

@ -0,0 +1,33 @@
/*
* 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.inventory;
public class InventoryClosingEvent extends InventoryEvent {
private final InventoryUser closingUser;
public InventoryClosingEvent(Inventory inventory, InventoryUser closingUser) {
super(inventory);
this.closingUser = closingUser;
}
public InventoryUser getClosingUser() {
return closingUser;
}
}

View File

@ -0,0 +1,35 @@
/*
* 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.inventory;
public abstract class InventoryEvent {
private final Inventory inventory;
public InventoryEvent(Inventory inventory) {
this.inventory = inventory;
}
/**
* @return the inventory
*/
public Inventory getInventory() {
return inventory;
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.inventory;
public class InventoryOpenedEvent extends InventoryEvent {
private final InventoryUser newUser;
public InventoryOpenedEvent(Inventory inventory, InventoryUser newUser) {
super(inventory);
this.newUser = newUser;
}
/**
* @return the newUser
*/
public InventoryUser getNewUser() {
return newUser;
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.inventory;
import ru.windcorp.progressia.common.world.item.ItemContainer;
public class InventorySimple extends Inventory {
public InventorySimple(String id, ItemContainer container) {
super(id, container);
}
public ItemContainer getContainer() {
return getContainers()[0];
}
}

View File

@ -0,0 +1,34 @@
/*
* 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.inventory;
public interface InventoryUser {
default void open(Inventory inventory) {
inventory.open(this);
}
default void close(Inventory inventory) {
inventory.close(this);
}
default boolean isUsing(Inventory inventory) {
return inventory.isUser(this);
}
}

View File

@ -36,6 +36,7 @@ import ru.windcorp.progressia.client.comms.controls.*;
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
import ru.windcorp.progressia.client.graphics.input.KeyMatcher;
import ru.windcorp.progressia.client.graphics.world.Selection;
import ru.windcorp.progressia.client.graphics.world.hud.HUDWorkspace;
import ru.windcorp.progressia.client.world.block.*;
import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerRegistry;
import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSimple;
@ -44,6 +45,10 @@ import ru.windcorp.progressia.client.world.entity.*;
import ru.windcorp.progressia.client.world.item.ItemRender;
import ru.windcorp.progressia.client.world.item.ItemRenderRegistry;
import ru.windcorp.progressia.client.world.item.ItemRenderSimple;
import ru.windcorp.progressia.client.world.item.inventory.InventoryComponent;
import ru.windcorp.progressia.client.world.item.inventory.InventoryComponentSimple;
import ru.windcorp.progressia.client.world.item.inventory.InventoryRender;
import ru.windcorp.progressia.client.world.item.inventory.InventoryRenderRegistry;
import ru.windcorp.progressia.client.world.tile.*;
import ru.windcorp.progressia.common.Units;
import ru.windcorp.progressia.common.collision.CollisionModel;
@ -57,6 +62,7 @@ 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.item.inventory.Inventory;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.tile.*;
import ru.windcorp.progressia.server.Server;
@ -258,6 +264,7 @@ public class TestContent {
)
);
register(new ItemRenderSimple("Test:CardboardBackpack", getItemTexture("CardboardBackpack")));
registerSimplestInventory("Test:CardboardBackpack");
}
private static void registerSimplestBlock(String name) {
@ -301,6 +308,15 @@ public class TestContent {
register(new TestEntityRenderStatie("Test:Statie"));
register(new TestEntityLogicStatie("Test:Statie"));
}
private static void registerSimplestInventory(String id) {
InventoryRenderRegistry.getInstance().register(new InventoryRender(id) {
@Override
public InventoryComponent createComponent(Inventory inventory, HUDWorkspace workspace) {
return new InventoryComponentSimple(id, inventory, workspace);
}
});
}
private static void registerPlayer() {
SpeciesData human = new SpeciesDataHuman("Core:Human");

Binary file not shown.

After

Width:  |  Height:  |  Size: 1011 B