diff --git a/src/main/java/ru/windcorp/progressia/client/Client.java b/src/main/java/ru/windcorp/progressia/client/Client.java index f356954..6bae089 100644 --- a/src/main/java/ru/windcorp/progressia/client/Client.java +++ b/src/main/java/ru/windcorp/progressia/client/Client.java @@ -18,14 +18,19 @@ package ru.windcorp.progressia.client; +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; + import ru.windcorp.progressia.client.comms.DefaultClientCommsListener; import ru.windcorp.progressia.client.comms.ServerCommsChannel; +import ru.windcorp.progressia.client.events.ClientEvent; +import ru.windcorp.progressia.client.events.NewLocalEntityEvent; import ru.windcorp.progressia.client.graphics.world.Camera; import ru.windcorp.progressia.client.graphics.world.EntityAnchor; import ru.windcorp.progressia.client.graphics.world.LocalPlayer; import ru.windcorp.progressia.client.world.WorldRender; +import ru.windcorp.progressia.common.util.crash.ReportingEventBus; import ru.windcorp.progressia.common.world.DefaultWorldData; -import ru.windcorp.progressia.common.world.entity.EntityData; public class Client { @@ -33,6 +38,8 @@ public class Client { private final LocalPlayer localPlayer = new LocalPlayer(this); private final Camera camera = new Camera((float) Math.toRadians(70)); + + private final EventBus eventBus = ReportingEventBus.create("ClientEvents"); private final ServerCommsChannel comms; @@ -41,6 +48,7 @@ public class Client { this.comms = comms; comms.addListener(new DefaultClientCommsListener(this)); + subscribe(this); } public WorldRender getWorld() { @@ -63,17 +71,32 @@ public class Client { return comms; } - public void onLocalPlayerEntityChanged(EntityData entity, EntityData lastKnownEntity) { - if (entity == null) { + @Subscribe + private void onLocalPlayerEntityChanged(NewLocalEntityEvent e) { + if (e.getNewEntity() == null) { getCamera().setAnchor(null); return; } getCamera().setAnchor( new EntityAnchor( - getWorld().getEntityRenderable(entity) + getWorld().getEntityRenderable(e.getNewEntity()) ) ); } + public void subscribe(Object object) { + eventBus.register(object); + } + + public void unsubscribe(Object object) { + eventBus.unregister(object); + } + + public void postEvent(ClientEvent event) { + event.setClient(this); + eventBus.post(event); + event.setClient(null); + } + } diff --git a/src/main/java/ru/windcorp/progressia/client/ClientState.java b/src/main/java/ru/windcorp/progressia/client/ClientState.java index 36d36ed..5ba262b 100644 --- a/src/main/java/ru/windcorp/progressia/client/ClientState.java +++ b/src/main/java/ru/windcorp/progressia/client/ClientState.java @@ -20,6 +20,7 @@ package ru.windcorp.progressia.client; import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel; import ru.windcorp.progressia.client.graphics.GUI; +import ru.windcorp.progressia.client.graphics.world.LayerHUD; import ru.windcorp.progressia.client.graphics.world.LayerWorld; import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.server.ServerState; @@ -56,6 +57,7 @@ public class ClientState { GUI.addBottomLayer(new LayerWorld(client)); GUI.addTopLayer(new LayerTestUI()); + GUI.addTopLayer(new LayerHUD(client)); TestInventoryGUIManager.setup(); GUI.addTopLayer(new LayerAbout()); diff --git a/src/main/java/ru/windcorp/progressia/client/events/ClientEvent.java b/src/main/java/ru/windcorp/progressia/client/events/ClientEvent.java new file mode 100644 index 0000000..965dbf4 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/events/ClientEvent.java @@ -0,0 +1,68 @@ +/* + * 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.client.events; + +import ru.windcorp.progressia.client.Client; + +/** + * An interface for all events issued by a {@link Client}. + */ +public interface ClientEvent { + + /** + * Returns the client instance that this event happened on. + * + * @return the client + */ + Client getClient(); + + /** + * Sets the client instance that the event is posted on. The value provided + * to this method must be returned by subsequent calls to + * {@link #getClient()}. Do not call this method when handling the event. + * + * @param client the client dispatching the event or {@code null} to unbind + * any previously bound client + */ + void setClient(Client client); + + /** + * A default implementation of {@link ClientEvent}. This is not necessarily + * extended by client events. + */ + public static abstract class Default implements ClientEvent { + + private Client client; + + public Default(Client client) { + this.client = client; + } + + @Override + public Client getClient() { + return client; + } + + @Override + public void setClient(Client client) { + this.client = client; + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/events/NewLocalEntityEvent.java b/src/main/java/ru/windcorp/progressia/client/events/NewLocalEntityEvent.java new file mode 100644 index 0000000..6e77028 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/events/NewLocalEntityEvent.java @@ -0,0 +1,51 @@ +/* + * 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.client.events; + +import ru.windcorp.progressia.client.Client; +import ru.windcorp.progressia.common.world.entity.EntityDataPlayer; + +public interface NewLocalEntityEvent extends ClientEvent { + + EntityDataPlayer getNewEntity(); + EntityDataPlayer getPreviousEntity(); + + public class Immutable extends ClientEvent.Default implements NewLocalEntityEvent { + + private final EntityDataPlayer newEntity; + private final EntityDataPlayer previousEntity; + + public Immutable(Client client, EntityDataPlayer newEntity, EntityDataPlayer previousEntity) { + super(client); + this.newEntity = newEntity; + this.previousEntity = previousEntity; + } + + @Override + public EntityDataPlayer getNewEntity() { + return newEntity; + } + + @Override + public EntityDataPlayer getPreviousEntity() { + return previousEntity; + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerHUD.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerHUD.java new file mode 100644 index 0000000..eb3f8d5 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerHUD.java @@ -0,0 +1,69 @@ +/* + * 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.client.graphics.world; + +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.Component; +import ru.windcorp.progressia.client.graphics.gui.GUILayer; +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.LayoutFill; +import ru.windcorp.progressia.client.graphics.texture.SimpleTextures; +import ru.windcorp.progressia.test.inv.SlotComponent; + +public class LayerHUD extends GUILayer { + + public LayerHUD(Client client) { + super("LayerHUD", new LayoutFill(15)); + setCursorPolicy(CursorPolicy.INDIFFERENT); + + client.subscribe(this); + } + + @Subscribe + private void onEntityChanged(NewLocalEntityEvent e) { + while (!getRoot().getChildren().isEmpty()) { + getRoot().removeChild(getRoot().getChild(0)); + } + + if (e.getNewEntity() == null) { + return; + } + + Component content = new Group(getName() + ".Content", new LayoutBorderVertical()); + + Group handDisplays = new Group( + getName() + ".Hands", + new LayoutBorderHorizontal(), + new SlotComponent(getName() + ".Hands.LeftHand", e.getNewEntity().getLeftHand(), 0) + .setBackground(SimpleTextures.get("gui/LeftHand")).setScale(4).setLayoutHint(LayoutBorderHorizontal.LEFT), + new SlotComponent(getName() + ".Hands.RightHand", e.getNewEntity().getRightHand(), 0) + .setBackground(SimpleTextures.get("gui/RightHand")).setScale(4).setLayoutHint(LayoutBorderHorizontal.RIGHT) + ); + + content.addChild(handDisplays.setLayoutHint(LayoutBorderVertical.UP)); + + getRoot().addChild(content); + getRoot().requestReassembly(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java index e24c5b9..79d88c2 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java @@ -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.NewLocalEntityEvent; import ru.windcorp.progressia.client.world.WorldRender; import ru.windcorp.progressia.client.world.entity.EntityRenderable; import ru.windcorp.progressia.common.world.entity.EntityData; @@ -82,7 +83,7 @@ public class LocalPlayer { } if (playerEntity != lastKnownEntity) { - getClient().onLocalPlayerEntityChanged(playerEntity, lastKnownEntity); + getClient().postEvent(new NewLocalEntityEvent.Immutable(getClient(), playerEntity, lastKnownEntity)); this.lastKnownEntity = playerEntity; } diff --git a/src/main/java/ru/windcorp/progressia/test/inv/DecoratedSlotComponent.java b/src/main/java/ru/windcorp/progressia/test/inv/DecoratedSlotComponent.java index 5880410..f0b88eb 100644 --- a/src/main/java/ru/windcorp/progressia/test/inv/DecoratedSlotComponent.java +++ b/src/main/java/ru/windcorp/progressia/test/inv/DecoratedSlotComponent.java @@ -28,8 +28,12 @@ public class DecoratedSlotComponent extends Button { private final SlotComponent slotComponent; public DecoratedSlotComponent(String name, ItemContainer container, int index) { + this(name, new SlotComponent(name, container, index)); + } + + public DecoratedSlotComponent(String name, SlotComponent component) { super(name, null, null); - this.slotComponent = new SlotComponent(name, container, index); + this.slotComponent = component; Vec2i size = slotComponent.getPreferredSize().add(2 * BORDER); setPreferredSize(size); diff --git a/src/main/java/ru/windcorp/progressia/test/inv/SlotComponent.java b/src/main/java/ru/windcorp/progressia/test/inv/SlotComponent.java index 2cb13ba..1260c7e 100644 --- a/src/main/java/ru/windcorp/progressia/test/inv/SlotComponent.java +++ b/src/main/java/ru/windcorp/progressia/test/inv/SlotComponent.java @@ -18,11 +18,19 @@ package ru.windcorp.progressia.test.inv; import glm.mat._4.Mat4; +import glm.vec._3.Vec3; +import ru.windcorp.progressia.client.graphics.Colors; +import ru.windcorp.progressia.client.graphics.backend.Usage; +import ru.windcorp.progressia.client.graphics.flat.FlatRenderProgram; import ru.windcorp.progressia.client.graphics.flat.RenderTarget; import ru.windcorp.progressia.client.graphics.font.Font; 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.Shape; +import ru.windcorp.progressia.client.graphics.model.ShapeParts; +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; @@ -32,26 +40,28 @@ import ru.windcorp.progressia.common.world.item.ItemSlot; public class SlotComponent extends Component { static final float TEXTURE_SIZE = 24; - static final float SCALE = 2; private final ItemContainer container; private final int index; - + + private float scale = 2; + private ItemRenderable itemRenderer = null; private int amountDisplayInt = 0; private String amountDisplayString = ""; + private Renderable background = null; + public SlotComponent(String name, ItemContainer container, int index) { super(name); this.container = container; this.index = index; - int side = (int) (TEXTURE_SIZE * SCALE); - setPreferredSize(side, side); + setScale(2); Font sizeFont = new Font().deriveOutlined().withScale(1); - addChild(new DynamicLabel(name + ".Size", sizeFont, () -> amountDisplayString, side)); + addChild(new DynamicLabel(getName() + ".Size", sizeFont, () -> amountDisplayString, getPreferredSize().x)); setLayout(new LayoutAlign(0, 0, 0)); } @@ -60,12 +70,36 @@ public class SlotComponent extends Component { return container.getSlot(index); } + public SlotComponent setScale(float scale) { + this.scale = scale; + + int side = (int) (TEXTURE_SIZE * scale); + setPreferredSize(side, side); + invalidate(); + + return this; + } + + public SlotComponent setBackground(Texture texture) { + background = new Shape( + Usage.STATIC, + FlatRenderProgram.getDefault(), + ShapeParts.createRectangle( + FlatRenderProgram.getDefault(), + texture, + Colors.WHITE, + new Vec3(0, 0, 0), + new Vec3(24, 0, 0), + new Vec3(0, 24, 0), + false + ) + ); + return this; + } + @Override protected void assembleSelf(RenderTarget target) { super.assembleSelf(target); - - updateItemRenderer(); - assembleItem(target); } @@ -90,11 +124,19 @@ public class SlotComponent extends Component { } private void assembleItem(RenderTarget target) { - if (itemRenderer != null) { - target.pushTransform(new Mat4().translate(getX(), getY(), 0).scale(SCALE)); - target.addCustomRenderer(itemRenderer); - target.popTransform(); - } + target.pushTransform(new Mat4().translate(getX(), getY(), 0).scale(scale)); + target.addCustomRenderer(renderer -> { + + updateItemRenderer(); + + if (itemRenderer != null) { + itemRenderer.render(renderer); + } else if (background != null) { + background.render(renderer); + } + + }); + target.popTransform(); } } diff --git a/src/main/resources/assets/textures/gui/LeftHand.png b/src/main/resources/assets/textures/gui/LeftHand.png new file mode 100644 index 0000000..febc326 Binary files /dev/null and b/src/main/resources/assets/textures/gui/LeftHand.png differ diff --git a/src/main/resources/assets/textures/gui/RightHand.png b/src/main/resources/assets/textures/gui/RightHand.png new file mode 100644 index 0000000..55b5049 Binary files /dev/null and b/src/main/resources/assets/textures/gui/RightHand.png differ