diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/ExponentAnimation.java b/src/main/java/ru/windcorp/progressia/client/graphics/ExponentAnimation.java
new file mode 100644
index 0000000..eaeb5d0
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/client/graphics/ExponentAnimation.java
@@ -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 .
+ */
+package ru.windcorp.progressia.client.graphics;
+
+import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
+
+public class ExponentAnimation {
+
+ private final float speed;
+ private float value;
+
+ public ExponentAnimation(float speed, float value) {
+ this.speed = speed;
+ this.value = value;
+ }
+
+ public float getSpeed() {
+ return speed;
+ }
+
+ public float getValue() {
+ return value;
+ }
+
+ public void setValue(float value) {
+ this.value = value;
+ }
+
+ public float update(float target, double timeStep) {
+ float difference = value - target;
+ value += difference * (1 - Math.exp(speed * timeStep));
+
+ return value;
+ }
+
+ public float updateForFrame(float target) {
+ return update(target, GraphicsInterface.getFrameLength());
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java
index 29d8629..add322e 100644
--- a/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java
+++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java
@@ -123,6 +123,36 @@ public class Shapes {
return result;
}
+
+ public static Shape createParallelogram(
+ // Try saying that 10 times fast
+ ShapeRenderProgram program,
+
+ Vec3 origin,
+
+ Vec3 width,
+ Vec3 height,
+
+ Vec4 colorMultiplier,
+
+ Texture texture
+ ) {
+ Shape result = new Shape(
+ Usage.STATIC,
+ program,
+ ShapeParts.createRectangle(
+ program,
+ texture,
+ colorMultiplier,
+ origin,
+ width,
+ height,
+ false
+ )
+ );
+
+ return result;
+ }
public static class PppBuilder {
@@ -297,4 +327,108 @@ public class Shapes {
}
+ public static class PgmBuilder {
+
+ private final ShapeRenderProgram program;
+
+ private final Vec3 origin = new Vec3(0, 0, 0);
+
+ private final Vec3 width = new Vec3(1, 0, 0);
+ private final Vec3 height = new Vec3(0, 1, 0);
+
+ private final Vec4 colorMultiplier = new Vec4(1, 1, 1, 1);
+
+ private final Texture texture;
+
+ public PgmBuilder(ShapeRenderProgram program, Texture texture) {
+ this.program = program;
+ this.texture = texture;
+ }
+
+ public PgmBuilder setOrigin(Vec3 origin) {
+ this.origin.set(origin);
+ return this;
+ }
+
+ public PgmBuilder setOrigin(float x, float y, float z) {
+ this.origin.set(x, y, z);
+ return this;
+ }
+
+ public PgmBuilder setColorMultiplier(Vec4 colorMultiplier) {
+ this.colorMultiplier.set(colorMultiplier);
+ return this;
+ }
+
+ public PgmBuilder setColorMultiplier(float r, float g, float b) {
+ this.colorMultiplier.set(r, g, b, 1);
+ return this;
+ }
+
+ public PgmBuilder setColorMultiplier(float r, float g, float b, float a) {
+ this.colorMultiplier.set(r, g, b, a);
+ return this;
+ }
+
+ public PgmBuilder setWidth(Vec3 vector) {
+ this.width.set(vector);
+ return this;
+ }
+
+ public PgmBuilder setWidth(float x, float y, float z) {
+ this.width.set(x, y, z);
+ return this;
+ }
+
+ public PgmBuilder setWidth(float x) {
+ this.width.set(x, 0, 0);
+ return this;
+ }
+
+ public PgmBuilder setHeight(Vec3 vector) {
+ this.height.set(vector);
+ return this;
+ }
+
+ public PgmBuilder setHeight(float x, float y, float z) {
+ this.height.set(x, y, z);
+ return this;
+ }
+
+ public PgmBuilder setHeight(float y) {
+ this.height.set(0, y, 0);
+ return this;
+ }
+
+ public PgmBuilder setSize(float x, float y) {
+ return this.setWidth(x).setHeight(y);
+ }
+
+ public PgmBuilder setSize(float size) {
+ return this.setSize(size, size);
+ }
+
+ public PgmBuilder centerAt(float x, float y, float z) {
+ origin.set(x, y, z);
+
+ origin.mul(2);
+ origin.sub(width);
+ origin.div(2);
+
+ return this;
+ }
+
+ public Shape create() {
+ return createParallelogram(
+ program,
+ origin,
+ width,
+ height,
+ colorMultiplier,
+ texture
+ );
+ }
+
+ }
+
}
diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/hud/HUDTextures.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/hud/HUDTextures.java
new file mode 100644
index 0000000..2d296be
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/hud/HUDTextures.java
@@ -0,0 +1,43 @@
+/*
+ * 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.hud;
+
+import ru.windcorp.progressia.client.graphics.texture.Atlases;
+import ru.windcorp.progressia.client.graphics.texture.SimpleTexture;
+import ru.windcorp.progressia.client.graphics.texture.Texture;
+import ru.windcorp.progressia.client.graphics.texture.Atlases.AtlasGroup;
+import ru.windcorp.progressia.common.resource.ResourceManager;
+
+public class HUDTextures {
+
+ private static final AtlasGroup HUD_ATLAS_GROUP = new AtlasGroup("HUD", 1 << 12);
+
+ public static Texture getHUDTexture(String name) {
+ return new SimpleTexture(
+ Atlases.getSprite(
+ ResourceManager.getTextureResource("gui/" + name),
+ HUD_ATLAS_GROUP
+ )
+ );
+ }
+
+ public static AtlasGroup getHUDAtlasGroup() {
+ return HUD_ATLAS_GROUP;
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/hud/HandsHUD.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/hud/HandsHUD.java
new file mode 100644
index 0000000..cfd92b1
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/hud/HandsHUD.java
@@ -0,0 +1,136 @@
+/*
+ * 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.hud;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import com.google.common.collect.Maps;
+
+import glm.vec._2.i.Vec2i;
+import ru.windcorp.progressia.client.graphics.ExponentAnimation;
+import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
+import ru.windcorp.progressia.client.graphics.gui.Component;
+import ru.windcorp.progressia.client.graphics.gui.Group;
+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;
+import ru.windcorp.progressia.common.world.entity.SpeciesData.Hand;
+import ru.windcorp.progressia.test.inv.TestInventoryGUIManager;
+
+public class HandsHUD extends Component {
+
+ public class ScaledSlotComponent extends Component {
+
+ private final SlotComponent slotComponent;
+ private final ExponentAnimation selected = new ExponentAnimation(10, 1);
+
+ public ScaledSlotComponent(SlotComponent component) {
+ super(component.getName() + ".Scaled");
+ this.slotComponent = component;
+ addChild(component);
+
+ Vec2i size = slotComponent.getPreferredSize();
+ setPreferredSize(size.x * 2, size.y * 2);
+ slotComponent.setBounds(-size.x / 2, 0, size);
+ }
+
+ @Override
+ protected void assembleChildren(RenderTarget target) {
+ Renderable renderable = slotComponent.assembleToRenderable();
+
+ target.addCustomRenderer(renderer -> {
+ float scale = player.getEntity().getSelectedHand() == slotComponent.getSlot().getContainer() ? 2 : 1;
+ renderer.pushTransform()
+ .translate(getX() + getWidth() / 2, getY(), 0)
+ .scale(selected.updateForFrame(scale));
+
+ renderable.render(renderer);
+
+ renderer.popTransform();
+ });
+ }
+
+ }
+
+ public enum Side {
+ LEFT("Left", LayoutBorderHorizontal.LEFT, 0.0),
+ RIGHT("Right", LayoutBorderHorizontal.RIGHT, 1.0),
+ CENTER("Center", LayoutBorderHorizontal.CENTER, 0.5);
+
+ private final String ccName;
+ private final Object lbhHint;
+ private final double align;
+
+ private Side(String ccName, Object lbhHint, double align) {
+ this.ccName = ccName;
+ this.lbhHint = lbhHint;
+ this.align = align;
+ }
+ }
+
+ private final LocalPlayer player;
+
+ public HandsHUD(String name, LocalPlayer player) {
+ super(name);
+ this.player = player;
+
+ EntityDataPlayer entity = player.getEntity();
+ String speciesId = entity.getSpecies().getId();
+ SpeciesRender speciesRender = SpeciesRenderRegistry.getInstance().get(speciesId);
+
+ Map containers = Maps.toMap(
+ Arrays.asList(Side.values()),
+ side -> new Group(name + "." + side.ccName, new LayoutHorizontal(15))
+ );
+
+ for (int i = 0; i < entity.getHandCount(); ++i) {
+
+ Hand hand = entity.getSpecies().getHands().get(i);
+
+ SlotComponent display = new SlotComponent(name + "." + hand.getName(), entity.getHand(i), 0)
+ .setBackground(speciesRender.getHandBackground(hand), this::shouldRenderHandPlaceholder)
+ .setScale(2);
+
+ Component scaledDisplay = new ScaledSlotComponent(display);
+
+ containers.get(speciesRender.getHandSide(hand)).addChild(scaledDisplay);
+
+ }
+
+ setLayout(new LayoutBorderHorizontal());
+
+ containers.forEach((side, comp) -> {
+ addChild(
+ new Group(name + "." + side.ccName + ".Aligner", new LayoutAlign(side.align, 0.5, 0), comp)
+ .setLayoutHint(side.lbhHint)
+ );
+ });
+
+ }
+
+ private boolean shouldRenderHandPlaceholder() {
+ return TestInventoryGUIManager.layer.hasContainer();
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/hud/PermanentHUD.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/hud/PermanentHUD.java
index 457a537..ae1fcde 100644
--- a/src/main/java/ru/windcorp/progressia/client/graphics/world/hud/PermanentHUD.java
+++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/hud/PermanentHUD.java
@@ -18,35 +18,22 @@
package ru.windcorp.progressia.client.graphics.world.hud;
import ru.windcorp.progressia.client.graphics.gui.Component;
-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.texture.SimpleTextures;
import ru.windcorp.progressia.client.graphics.world.LocalPlayer;
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
-import ru.windcorp.progressia.test.inv.SlotComponent;
public class PermanentHUD extends Component {
public PermanentHUD(String name, LocalPlayer player) {
super(name);
setLayout(new LayoutBorderVertical());
-
+
EntityDataPlayer entity = player.getEntity();
if (entity == null) {
throw new IllegalStateException("Player " + player + " does not have an associated entity");
}
- Group handDisplays = new Group(
- getName() + ".Hands",
- new LayoutBorderHorizontal(),
- new SlotComponent(getName() + ".Hands.LeftHand", entity.getLeftHand(), 0)
- .setBackground(SimpleTextures.get("gui/LeftHand")).setScale(4).setLayoutHint(LayoutBorderHorizontal.LEFT),
- new SlotComponent(getName() + ".Hands.RightHand", entity.getRightHand(), 0)
- .setBackground(SimpleTextures.get("gui/RightHand")).setScale(4).setLayoutHint(LayoutBorderHorizontal.RIGHT)
- );
-
- addChild(handDisplays.setLayoutHint(LayoutBorderVertical.UP));
+ addChild(new HandsHUD(name + ".Hands", player).setLayoutHint(LayoutBorderVertical.UP));
}
}
diff --git a/src/main/java/ru/windcorp/progressia/test/inv/SlotComponent.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/hud/SlotComponent.java
similarity index 82%
rename from src/main/java/ru/windcorp/progressia/test/inv/SlotComponent.java
rename to src/main/java/ru/windcorp/progressia/client/graphics/world/hud/SlotComponent.java
index 1260c7e..48f21c8 100644
--- a/src/main/java/ru/windcorp/progressia/test/inv/SlotComponent.java
+++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/hud/SlotComponent.java
@@ -15,12 +15,10 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-package ru.windcorp.progressia.test.inv;
+package ru.windcorp.progressia.client.graphics.world.hud;
+import java.util.function.BooleanSupplier;
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;
@@ -28,8 +26,7 @@ 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.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;
@@ -52,6 +49,7 @@ public class SlotComponent extends Component {
private String amountDisplayString = "";
private Renderable background = null;
+ private BooleanSupplier backgroundCondition = null;
public SlotComponent(String name, ItemContainer container, int index) {
super(name);
@@ -80,20 +78,18 @@ public class SlotComponent extends Component {
return this;
}
+ public SlotComponent setBackground(Texture texture, BooleanSupplier when) {
+ background = new PgmBuilder(FlatRenderProgram.getDefault(), texture).setSize(TEXTURE_SIZE).create();
+ setBackgroundDisplayCondition(when);
+ 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 setBackground(texture, null);
+ }
+
+ public SlotComponent setBackgroundDisplayCondition(BooleanSupplier backgroundCondition) {
+ this.backgroundCondition = backgroundCondition;
return this;
}
@@ -132,7 +128,9 @@ public class SlotComponent extends Component {
if (itemRenderer != null) {
itemRenderer.render(renderer);
} else if (background != null) {
- background.render(renderer);
+ if (backgroundCondition == null || backgroundCondition.getAsBoolean()) {
+ background.render(renderer);
+ }
}
});
diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderPlayer.java b/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderPlayer.java
new file mode 100644
index 0000000..d14fba4
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderPlayer.java
@@ -0,0 +1,39 @@
+/*
+ * 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.world.entity;
+
+import ru.windcorp.progressia.common.world.entity.EntityData;
+import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
+
+public class EntityRenderPlayer extends EntityRender {
+
+ public EntityRenderPlayer(String id) {
+ super(id);
+ }
+
+ @Override
+ public EntityRenderable createRenderable(EntityData entity) {
+ EntityDataPlayer playerEntity = (EntityDataPlayer) entity;
+
+ String speciesId = playerEntity.getSpecies().getId();
+ SpeciesRender speciesRender = SpeciesRenderRegistry.getInstance().get(speciesId);
+
+ return speciesRender.createRenderable(playerEntity);
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/SpeciesRender.java b/src/main/java/ru/windcorp/progressia/client/world/entity/SpeciesRender.java
new file mode 100644
index 0000000..9f63c2e
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/client/world/entity/SpeciesRender.java
@@ -0,0 +1,50 @@
+/*
+ * 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.world.entity;
+
+import ru.windcorp.progressia.client.graphics.texture.Texture;
+import ru.windcorp.progressia.client.graphics.world.hud.HUDTextures;
+import ru.windcorp.progressia.client.graphics.world.hud.HandsHUD;
+import ru.windcorp.progressia.common.util.namespaces.Namespaced;
+import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
+import ru.windcorp.progressia.common.world.entity.SpeciesData.EquipmentSlot;
+import ru.windcorp.progressia.common.world.entity.SpeciesData.Hand;
+
+public abstract class SpeciesRender extends Namespaced {
+
+ public SpeciesRender(String id) {
+ super(id);
+ }
+
+ public abstract EntityRenderable createRenderable(EntityDataPlayer entity);
+
+ public abstract HandsHUD.Side getHandSide(Hand hand);
+
+ public Texture getTexture(String name) {
+ return HUDTextures.getHUDTexture(getNamespace() + "_" + getName() + "/" + name);
+ }
+
+ public Texture getHandBackground(Hand hand) {
+ return getTexture("Hand" + hand.getName());
+ }
+
+ public Texture getEquipmentSlotBackground(EquipmentSlot slot) {
+ return getTexture("EquipmentSlot" + slot.getName());
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/SpeciesRenderRegistry.java b/src/main/java/ru/windcorp/progressia/client/world/entity/SpeciesRenderRegistry.java
new file mode 100644
index 0000000..3f1176a
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/client/world/entity/SpeciesRenderRegistry.java
@@ -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 .
+ */
+package ru.windcorp.progressia.client.world.entity;
+
+import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry;
+import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
+
+public class SpeciesRenderRegistry extends NamespacedInstanceRegistry {
+
+ private static final SpeciesRenderRegistry INSTANCE = new SpeciesRenderRegistry();
+
+ public static SpeciesRenderRegistry getInstance() {
+ return INSTANCE;
+ }
+
+ public SpeciesRender get(EntityDataPlayer player) {
+ return get(player.getSpecies().getId());
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityDataPlayer.java b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityDataPlayer.java
index 4c9f598..44fb56a 100644
--- a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityDataPlayer.java
+++ b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityDataPlayer.java
@@ -18,41 +18,63 @@
package ru.windcorp.progressia.common.world.entity;
import ru.windcorp.progressia.common.Units;
-import ru.windcorp.progressia.common.collision.AABB;
+import ru.windcorp.progressia.common.state.IntStateField;
import ru.windcorp.progressia.common.state.ObjectStateField;
-import ru.windcorp.progressia.common.world.item.ItemContainerMixedSimple;
import ru.windcorp.progressia.common.world.item.ItemContainerHand;
-import ru.windcorp.progressia.common.world.item.ItemContainerMixed;
+import ru.windcorp.progressia.common.world.item.ItemContainerMixedSimple;
public class EntityDataPlayer extends EntityData {
+
+ private final ObjectStateField speciesDatalet = field("Core:SpeciesDatalet").setShared()
+ .of(SpeciesDataRegistry.getInstance().getCodec()).build();
private final ObjectStateField inventory = field("Core:Inventory").setShared().def(
() -> new ItemContainerMixedSimple("Core:PlayerInventory", Units.get(15, "kg"), Units.get(50, "L"))
).build();
- private final ObjectStateField leftHand = field("Core:LeftHand").setShared().def(
- () -> new ItemContainerHand("Core:PlayerLeftHand", Units.get(10, "kg"), Units.get(5, "L"))
- ).build();
-
- private final ObjectStateField rightHand = field("Core:RightHand").setShared().def(
- () -> new ItemContainerHand("Core:PlayerRightHand", Units.get(10, "kg"), Units.get(5, "L"))
- ).build();
+ private final IntStateField selectedHand = field("Core:SelectedHand").setShared().ofInt().build();
- public EntityDataPlayer(String id) {
+ public EntityDataPlayer(String id, SpeciesData species) {
super(id);
- setCollisionModel(new AABB(0, 0, 1.8f / 2, 0.8f, 0.8f, 1.8f));
+
+ setSpecies(species);
}
- public ItemContainerMixed getInventory() {
+ public ItemContainerMixedSimple getInventory() {
return inventory.get(this);
}
-
- public ItemContainerHand getLeftHand() {
- return leftHand.get(this);
+
+ private void setSpecies(SpeciesData species) {
+ speciesDatalet.setNow(this, species.createDatalet());
+ setCollisionModel(species.getCollisionModel());
}
- public ItemContainerHand getRightHand() {
- return rightHand.get(this);
+ public SpeciesData getSpecies() {
+ return speciesDatalet.get(this).getSpecies();
+ }
+
+ public ItemContainerHand getHand(int index) {
+ return speciesDatalet.get(this).getHands()[index];
+ }
+
+ public int getHandCount() {
+ return speciesDatalet.get(this).getHands().length;
+ }
+
+ public int getEquipmentCount() {
+ return speciesDatalet.get(this).getEquipment().length;
+ }
+
+ public int getSelectedHandIndex() {
+ return selectedHand.get(this);
+ }
+
+ public void setSelectedHandIndexNow(int index) {
+ selectedHand.setNow(this, index);
+ }
+
+ public ItemContainerHand getSelectedHand() {
+ return getHand(getSelectedHandIndex());
}
}
diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/SpeciesCodec.java b/src/main/java/ru/windcorp/progressia/common/world/entity/SpeciesCodec.java
new file mode 100644
index 0000000..5e66c02
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/common/world/entity/SpeciesCodec.java
@@ -0,0 +1,71 @@
+/*
+ * 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.entity;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+import ru.windcorp.progressia.common.state.IOContext;
+import ru.windcorp.progressia.common.state.codec.ObjectCodec;
+
+public class SpeciesCodec extends ObjectCodec {
+
+ public SpeciesCodec() {
+ super(SpeciesDatalet.class);
+ }
+
+ @Override
+ protected SpeciesDatalet doRead(SpeciesDatalet previous, DataInput input, IOContext context) throws IOException {
+ String id = input.readUTF();
+
+ SpeciesDatalet result = previous;
+
+ if (result == null || !result.getSpecies().getId().equals(id)) {
+ SpeciesData species = SpeciesDataRegistry.getInstance().get(id);
+ if (species == null) {
+ throw new IOException("Unknown species ID " + species);
+ }
+ result = species.createDatalet();
+ }
+
+ result.read(input, context);
+
+ return result;
+ }
+
+ @Override
+ protected void doWrite(SpeciesDatalet obj, DataOutput output, IOContext context) throws IOException {
+ output.writeUTF(obj.getSpecies().getId());
+ obj.write(output, context);
+ }
+
+ @Override
+ public SpeciesDatalet copy(SpeciesDatalet object, SpeciesDatalet previous) {
+ SpeciesDatalet result = previous;
+
+ if (result == null || result.getSpecies() != object.getSpecies()) {
+ result = object.getSpecies().createDatalet();
+ }
+
+ object.copy(result);
+
+ return result;
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/SpeciesData.java b/src/main/java/ru/windcorp/progressia/common/world/entity/SpeciesData.java
new file mode 100644
index 0000000..da14acc
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/common/world/entity/SpeciesData.java
@@ -0,0 +1,116 @@
+/*
+ * 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.entity;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import com.google.common.collect.ImmutableList;
+
+import ru.windcorp.progressia.common.collision.CollisionModel;
+import ru.windcorp.progressia.common.util.Named;
+import ru.windcorp.progressia.common.util.namespaces.Namespaced;
+import ru.windcorp.progressia.common.world.item.ItemData;
+
+public abstract class SpeciesData extends Namespaced {
+
+ public static class Hand extends Named {
+
+ private int index = -1;
+
+ public Hand(String name) {
+ super(name);
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ }
+
+ public static class EquipmentSlot extends Named {
+
+ private int index = -1;
+
+ private Predicate filter;
+
+ public EquipmentSlot(String name, Predicate filter) {
+ super(name);
+ this.filter = filter;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public Predicate getFilter() {
+ return filter;
+ }
+
+ }
+
+ private List hands;
+ private List equipmentSlots;
+
+ public SpeciesData(String id) {
+ super(id);
+ }
+
+ public void withHands(Hand... hands) {
+ if (this.hands != null) {
+ throw new IllegalStateException("Hands already set");
+ }
+
+ if (hands.length == 0) {
+ throw new IllegalArgumentException("At least one hand required");
+ }
+
+ this.hands = ImmutableList.copyOf(hands);
+
+ for (int i = 0; i < hands.length; ++i) {
+ hands[i].index = i;
+ }
+ }
+
+ public void withEquipmentSlots(EquipmentSlot... equipmentSlots) {
+ if (this.equipmentSlots != null) {
+ throw new IllegalStateException("Equipment slots already set");
+ }
+
+ this.equipmentSlots = ImmutableList.copyOf(equipmentSlots);
+
+ for (int i = 0; i < equipmentSlots.length; ++i) {
+ equipmentSlots[i].index = i;
+ }
+ }
+
+ public List getHands() {
+ return hands;
+ }
+
+ public List getEquipmentSlots() {
+ return equipmentSlots;
+ }
+
+ public abstract CollisionModel getCollisionModel();
+
+ public SpeciesDatalet createDatalet() {
+ return new SpeciesDatalet(this);
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/SpeciesDataRegistry.java b/src/main/java/ru/windcorp/progressia/common/world/entity/SpeciesDataRegistry.java
new file mode 100644
index 0000000..7c929f0
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/common/world/entity/SpeciesDataRegistry.java
@@ -0,0 +1,37 @@
+/*
+ * 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.entity;
+
+import ru.windcorp.progressia.common.state.codec.ObjectCodec;
+import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry;
+
+public class SpeciesDataRegistry extends NamespacedInstanceRegistry {
+
+ private static final SpeciesDataRegistry INSTANCE = new SpeciesDataRegistry();
+
+ private final ObjectCodec codec = new SpeciesCodec();
+
+ public static SpeciesDataRegistry getInstance() {
+ return INSTANCE;
+ }
+
+ public ObjectCodec getCodec() {
+ return codec;
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/SpeciesDatalet.java b/src/main/java/ru/windcorp/progressia/common/world/entity/SpeciesDatalet.java
new file mode 100644
index 0000000..672f848
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/common/world/entity/SpeciesDatalet.java
@@ -0,0 +1,116 @@
+/*
+ * 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.entity;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+import ru.windcorp.progressia.common.state.Encodable;
+import ru.windcorp.progressia.common.state.IOContext;
+import ru.windcorp.progressia.common.world.entity.SpeciesData.EquipmentSlot;
+import ru.windcorp.progressia.common.world.entity.SpeciesData.Hand;
+import ru.windcorp.progressia.common.world.item.ItemContainerEquipment;
+import ru.windcorp.progressia.common.world.item.ItemContainerHand;
+
+public class SpeciesDatalet implements Encodable {
+
+ private final SpeciesData species;
+
+ private final ItemContainerHand[] hands;
+ private final ItemContainerEquipment[] equipment;
+
+ public SpeciesDatalet(SpeciesData species) {
+ this.species = species;
+
+ this.hands = new ItemContainerHand[species.getHands().size()];
+ for (int i = 0; i < hands.length; ++i) {
+ Hand hand = species.getHands().get(i);
+ this.hands[i] = new ItemContainerHand(species.getId() + "Hand" + hand.getName(), hand);
+ }
+
+ this.equipment = new ItemContainerEquipment[species.getEquipmentSlots().size()];
+ for (int i = 0; i < equipment.length; ++i) {
+ EquipmentSlot equipmentSlot = species.getEquipmentSlots().get(i);
+ this.equipment[i] = new ItemContainerEquipment(
+ species.getId() + "EquipmentSlot" + equipmentSlot.getName(),
+ equipmentSlot
+ );
+ }
+ }
+
+ public SpeciesData getSpecies() {
+ return species;
+ }
+
+ @Override
+ public void read(DataInput input, IOContext context) throws IOException {
+ for (int i = 0; i < hands.length; ++i) {
+ hands[i].read(input, context);
+ }
+
+ for (int i = 0; i < equipment.length; ++i) {
+ equipment[i].read(input, context);
+ }
+ }
+
+ @Override
+ public void write(DataOutput output, IOContext context) throws IOException {
+ for (int i = 0; i < hands.length; ++i) {
+ hands[i].write(output, context);
+ }
+
+ for (int i = 0; i < equipment.length; ++i) {
+ equipment[i].write(output, context);
+ }
+ }
+
+ @Override
+ public void copy(Encodable destination) {
+ SpeciesDatalet other = (SpeciesDatalet) destination;
+
+ if (other.getSpecies() != getSpecies()) {
+ throw new IllegalArgumentException(
+ "Cannot copy datalet of species " + other.getSpecies() + " into datalet of species " + getSpecies()
+ );
+ }
+
+ for (int i = 0; i < hands.length; ++i) {
+ hands[i].copy(other.hands[i]);
+ }
+
+ for (int i = 0; i < equipment.length; ++i) {
+ equipment[i].copy(other.equipment[i]);
+ }
+ }
+
+ /**
+ * @return the hands
+ */
+ public ItemContainerHand[] getHands() {
+ return hands;
+ }
+
+ /**
+ * @return the equipment
+ */
+ public ItemContainerEquipment[] getEquipment() {
+ return equipment;
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/common/world/item/ItemContainerEquipment.java b/src/main/java/ru/windcorp/progressia/common/world/item/ItemContainerEquipment.java
new file mode 100644
index 0000000..2328374
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/common/world/item/ItemContainerEquipment.java
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+import ru.windcorp.progressia.common.Units;
+import ru.windcorp.progressia.common.world.entity.SpeciesData;
+
+public class ItemContainerEquipment extends ItemContainerSingle {
+
+ private static final float EQUIP_MASS_LIMIT = Units.get("15 kg");
+ private static final float EQUIP_VOLUME_LIMIT = Units.get("60 kg");
+
+ private final SpeciesData.EquipmentSlot equipmentSlot;
+
+ public ItemContainerEquipment(String id, SpeciesData.EquipmentSlot equipmentSlot) {
+ super(id, EQUIP_MASS_LIMIT, EQUIP_VOLUME_LIMIT);
+ this.equipmentSlot = equipmentSlot;
+ }
+
+ public SpeciesData.EquipmentSlot getEquipmentSlot() {
+ return equipmentSlot;
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/common/world/item/ItemContainerHand.java b/src/main/java/ru/windcorp/progressia/common/world/item/ItemContainerHand.java
index 9f8c086..33fb9aa 100644
--- a/src/main/java/ru/windcorp/progressia/common/world/item/ItemContainerHand.java
+++ b/src/main/java/ru/windcorp/progressia/common/world/item/ItemContainerHand.java
@@ -17,71 +17,24 @@
*/
package ru.windcorp.progressia.common.world.item;
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.IOException;
-import java.util.function.Consumer;
+import ru.windcorp.progressia.common.Units;
+import ru.windcorp.progressia.common.world.entity.SpeciesData;
+import ru.windcorp.progressia.common.world.entity.SpeciesData.Hand;
-import ru.windcorp.progressia.common.state.Encodable;
-import ru.windcorp.progressia.common.state.IOContext;
-
-public class ItemContainerHand extends ItemContainer {
+public class ItemContainerHand extends ItemContainerSingle {
- private final ItemSlot slot = new ItemSlot();
+ private static final float HAND_MASS_LIMIT = Units.get("10 kg");
+ private static final float HAND_VOLUME_LIMIT = Units.get("5 kg");
- private final float massLimit;
- private final float volumeLimit;
+ private final SpeciesData.Hand hand;
- public ItemContainerHand(String id, float massLimit, float volumeLimit) {
- super(id);
- this.massLimit = massLimit;
- this.volumeLimit = volumeLimit;
-
- slot.setContainer(this);
+ public ItemContainerHand(String id, Hand hand) {
+ super(id, HAND_MASS_LIMIT, HAND_VOLUME_LIMIT);
+ this.hand = hand;
}
-
- @Override
- public void read(DataInput input, IOContext context) throws IOException {
- slot.read(input, context);
- }
-
- @Override
- public void write(DataOutput output, IOContext context) throws IOException {
- slot.write(output, context);
- }
-
- @Override
- public void copy(Encodable destination) {
- slot.copy(((ItemContainerHand) destination).slot);
- }
-
- @Override
- public ItemSlot getSlot(int index) {
- if (index == 0) {
- return slot;
- } else {
- return null;
- }
- }
-
- @Override
- public int getSlotCount() {
- return 1;
- }
-
- @Override
- public void forEach(Consumer action) {
- action.accept(slot);
- }
-
- @Override
- public float getMassLimit() {
- return massLimit;
- }
-
- @Override
- public float getVolumeLimit() {
- return volumeLimit;
+
+ public SpeciesData.Hand getHand() {
+ return hand;
}
}
diff --git a/src/main/java/ru/windcorp/progressia/common/world/item/ItemContainerSingle.java b/src/main/java/ru/windcorp/progressia/common/world/item/ItemContainerSingle.java
new file mode 100644
index 0000000..f930ff9
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/common/world/item/ItemContainerSingle.java
@@ -0,0 +1,91 @@
+/*
+ * 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;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.function.Consumer;
+
+import ru.windcorp.progressia.common.state.Encodable;
+import ru.windcorp.progressia.common.state.IOContext;
+
+public abstract class ItemContainerSingle extends ItemContainer {
+
+ private final ItemSlot slot = new ItemSlot();
+
+ private final float massLimit;
+ private final float volumeLimit;
+
+ public ItemContainerSingle(String id, float massLimit, float volumeLimit) {
+ super(id);
+ this.massLimit = massLimit;
+ this.volumeLimit = volumeLimit;
+
+ slot.setContainer(this);
+ }
+
+ @Override
+ public void read(DataInput input, IOContext context) throws IOException {
+ slot.read(input, context);
+ }
+
+ @Override
+ public void write(DataOutput output, IOContext context) throws IOException {
+ slot.write(output, context);
+ }
+
+ @Override
+ public void copy(Encodable destination) {
+ slot.copy(((ItemContainerSingle) destination).slot);
+ }
+
+ @Override
+ public ItemSlot getSlot(int index) {
+ if (index == 0) {
+ return slot;
+ } else {
+ return null;
+ }
+ }
+
+ public ItemSlot slot() {
+ return slot;
+ }
+
+ @Override
+ public int getSlotCount() {
+ return 1;
+ }
+
+ @Override
+ public void forEach(Consumer action) {
+ action.accept(slot);
+ }
+
+ @Override
+ public float getMassLimit() {
+ return massLimit;
+ }
+
+ @Override
+ public float getVolumeLimit() {
+ return volumeLimit;
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/test/TestEntityRenderHuman.java b/src/main/java/ru/windcorp/progressia/test/HumanModelFactory.java
similarity index 93%
rename from src/main/java/ru/windcorp/progressia/test/TestEntityRenderHuman.java
rename to src/main/java/ru/windcorp/progressia/test/HumanModelFactory.java
index 388d89c..6c44171 100644
--- a/src/main/java/ru/windcorp/progressia/test/TestEntityRenderHuman.java
+++ b/src/main/java/ru/windcorp/progressia/test/HumanModelFactory.java
@@ -30,15 +30,14 @@ import ru.windcorp.progressia.client.graphics.texture.ComplexTexture;
import ru.windcorp.progressia.client.graphics.texture.TexturePrimitive;
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
import ru.windcorp.progressia.client.world.entity.HumanoidModel;
-import ru.windcorp.progressia.client.world.entity.EntityRender;
import ru.windcorp.progressia.client.world.entity.EntityRenderRegistry;
import ru.windcorp.progressia.client.world.entity.EntityRenderable;
import ru.windcorp.progressia.common.util.FloatMathUtil;
-import ru.windcorp.progressia.common.world.entity.EntityData;
+import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
import static java.lang.Math.*;
-public class TestEntityRenderHuman extends EntityRender {
+public class HumanModelFactory {
private static final float SECOND_LAYER_OFFSET = 1 / 12f;
@@ -51,9 +50,7 @@ public class TestEntityRenderHuman extends EntityRender {
private final TexturePrimitive skin;
- public TestEntityRenderHuman(String id) {
- super(id);
-
+ public HumanModelFactory() {
this.skin = fetchSkin();
ComplexTexture texture = new ComplexTexture(
@@ -203,8 +200,7 @@ public class TestEntityRenderHuman extends EntityRender {
return b.build();
}
- @Override
- public EntityRenderable createRenderable(EntityData entity) {
+ public EntityRenderable createRenderable(EntityDataPlayer entity) {
return new HumanoidModel(
entity,
@@ -237,7 +233,7 @@ public class TestEntityRenderHuman extends EntityRender {
0.0f
),
- 1.8f / (3 + 3 + 2)
+ SpeciesDataHuman.HEIGHT / (3 + 3 + 2)
)
.setWalkingArmSwing((float) toRadians(30))
.setWalkingLegSwing((float) toRadians(50))
diff --git a/src/main/java/ru/windcorp/progressia/test/SpeciesDataHuman.java b/src/main/java/ru/windcorp/progressia/test/SpeciesDataHuman.java
new file mode 100644
index 0000000..19889c5
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/test/SpeciesDataHuman.java
@@ -0,0 +1,42 @@
+/*
+ * 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.test;
+
+import ru.windcorp.progressia.common.Units;
+import ru.windcorp.progressia.common.collision.AABB;
+import ru.windcorp.progressia.common.collision.CollisionModel;
+import ru.windcorp.progressia.common.world.entity.SpeciesData;
+
+public class SpeciesDataHuman extends SpeciesData {
+
+ public static final float HEIGHT = Units.get("180 cm");
+ public static final float WIDTH = Units.get("80 cm");
+
+ public SpeciesDataHuman(String id) {
+ super(id);
+
+ withHands(new Hand("Right"), new Hand("Left"));
+ withEquipmentSlots(/* ._. nope */);
+ }
+
+ @Override
+ public CollisionModel getCollisionModel() {
+ return new AABB(0, 0, HEIGHT / 2, WIDTH, WIDTH, HEIGHT);
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/test/SpeciesRenderHuman.java b/src/main/java/ru/windcorp/progressia/test/SpeciesRenderHuman.java
new file mode 100644
index 0000000..43a6299
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/test/SpeciesRenderHuman.java
@@ -0,0 +1,44 @@
+/*
+ * 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.test;
+
+import ru.windcorp.progressia.client.graphics.world.hud.HandsHUD.Side;
+import ru.windcorp.progressia.client.world.entity.EntityRenderable;
+import ru.windcorp.progressia.client.world.entity.SpeciesRender;
+import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
+import ru.windcorp.progressia.common.world.entity.SpeciesData.Hand;
+
+public class SpeciesRenderHuman extends SpeciesRender {
+
+ private final HumanModelFactory modelFactory = new HumanModelFactory();
+
+ public SpeciesRenderHuman(String id) {
+ super(id);
+ }
+
+ @Override
+ public EntityRenderable createRenderable(EntityDataPlayer entity) {
+ return modelFactory.createRenderable(entity);
+ }
+
+ @Override
+ public Side getHandSide(Hand hand) {
+ return hand.getIndex() == 0 ? Side.RIGHT : Side.LEFT;
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java
index 5206620..8b39117 100644
--- a/src/main/java/ru/windcorp/progressia/test/TestContent.java
+++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java
@@ -283,15 +283,23 @@ public class TestContent {
}
private static void registerEntities() {
- registerEntity("Core:Player", EntityDataPlayer::new);
- register(new TestEntityRenderHuman("Core:Player"));
- register(new EntityLogic("Core:Player"));
+ registerPlayer();
registerEntity("Test:Statie", TestEntityDataStatie::new);
register(new TestEntityRenderStatie("Test:Statie"));
register(new TestEntityLogicStatie("Test:Statie"));
}
+ private static void registerPlayer() {
+ SpeciesData human = new SpeciesDataHuman("Core:Human");
+ SpeciesDataRegistry.getInstance().register(human);
+ SpeciesRenderRegistry.getInstance().register(new SpeciesRenderHuman("Core:Human"));
+
+ registerEntity("Core:Player", id -> new EntityDataPlayer(id, human));
+ register(new EntityRenderPlayer("Core:Player"));
+ register(new EntityLogic("Core:Player"));
+ }
+
private static void regsiterControls() {
ControlDataRegistry data = ControlDataRegistry.getInstance();
ControlTriggerRegistry triggers = ControlTriggerRegistry.getInstance();
diff --git a/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java b/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java
index 46bdacc..9a9582e 100644
--- a/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java
+++ b/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java
@@ -84,6 +84,7 @@ public class TestPlayerControls {
private double lastSpacePress = Double.NEGATIVE_INFINITY;
private double lastSprintPress = Double.NEGATIVE_INFINITY;
+ private double lastCtrlPress = Double.NEGATIVE_INFINITY;
private int selectedBlock = 0;
private int selectedTile = 0;
@@ -250,6 +251,13 @@ public class TestPlayerControls {
return false;
switchPlacingMode();
break;
+
+ case GLFW.GLFW_KEY_LEFT_CONTROL:
+ case GLFW.GLFW_KEY_RIGHT_CONTROL:
+ if (event.isRepeat())
+ return false;
+ handleCtrl(event);
+ break;
default:
return false;
@@ -435,8 +443,60 @@ public class TestPlayerControls {
isBlockSelected = !isBlockSelected;
updateGUI();
}
+
+ public void handleCtrlIfApplicable(Input input) {
+ if (input.getEvent() instanceof KeyEvent) {
+ KeyEvent ke = (KeyEvent) input.getEvent();
+ if (ke.isRepeat()) {
+ return;
+ }
+ if (ke.getKey() == GLFW.GLFW_KEY_LEFT_CONTROL || ke.getKey() == GLFW.GLFW_KEY_RIGHT_CONTROL) {
+ handleCtrl(ke);
+ input.consume();
+ }
+ }
+ }
- public EntityData getEntity() {
+ private void handleCtrl(KeyEvent event) {
+ if (ClientState.getInstance() == null || !ClientState.getInstance().isReady()) {
+ return;
+ }
+
+ double now = GraphicsInterface.getTime();
+ int change = 0;
+
+ if (event.isPress()) {
+ change = +1;
+ lastCtrlPress = now;
+ } else {
+ if (now - lastCtrlPress > Units.get("200 ms")) {
+ change = -1;
+ lastCtrlPress = Double.NEGATIVE_INFINITY;
+ }
+ }
+
+ if (change == 0) {
+ return;
+ }
+
+ if (event.hasShift()) {
+ change *= -1;
+ }
+
+ int selected = getEntity().getSelectedHandIndex();
+ int maxSelected = getEntity().getHandCount() - 1;
+
+ selected += change;
+ if (selected < 0) {
+ selected = maxSelected;
+ } else if (selected > maxSelected) {
+ selected = 0;
+ }
+
+ getEntity().setSelectedHandIndexNow(selected);
+ }
+
+ public EntityDataPlayer getEntity() {
return getPlayer().getEntity();
}
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 f0b88eb..10889b4 100644
--- a/src/main/java/ru/windcorp/progressia/test/inv/DecoratedSlotComponent.java
+++ b/src/main/java/ru/windcorp/progressia/test/inv/DecoratedSlotComponent.java
@@ -20,6 +20,7 @@ package ru.windcorp.progressia.test.inv;
import glm.vec._2.i.Vec2i;
import ru.windcorp.progressia.client.graphics.gui.Button;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutFill;
+import ru.windcorp.progressia.client.graphics.world.hud.SlotComponent;
import ru.windcorp.progressia.common.world.item.ItemContainer;
import ru.windcorp.progressia.common.world.item.ItemSlot;
diff --git a/src/main/java/ru/windcorp/progressia/test/inv/HandSlots.java b/src/main/java/ru/windcorp/progressia/test/inv/HandSlots.java
index 005a36b..828c029 100644
--- a/src/main/java/ru/windcorp/progressia/test/inv/HandSlots.java
+++ b/src/main/java/ru/windcorp/progressia/test/inv/HandSlots.java
@@ -18,93 +18,135 @@
package ru.windcorp.progressia.test.inv;
import glm.vec._2.i.Vec2i;
-import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
+import ru.windcorp.progressia.client.graphics.ExponentAnimation;
import ru.windcorp.progressia.client.graphics.backend.InputTracker;
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
import ru.windcorp.progressia.client.graphics.gui.Component;
import ru.windcorp.progressia.client.graphics.model.Renderable;
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
+import ru.windcorp.progressia.client.graphics.world.hud.SlotComponent;
+import ru.windcorp.progressia.client.world.entity.SpeciesRender;
+import ru.windcorp.progressia.client.world.entity.SpeciesRenderRegistry;
+import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
+import ru.windcorp.progressia.common.world.entity.SpeciesData.Hand;
+import ru.windcorp.progressia.common.world.item.ItemContainerHand;
public class HandSlots extends Component {
- private final SlotComponent left;
- private final SlotComponent right;
+ private class CursorBoundSlot {
- /**
- * Right is 0, left is 1
- */
- private float selection = 0;
- private static final float ANIMATION_SPEED = 10f;
+ private final SlotComponent component;
+ private final Renderable renderable;
- public HandSlots(String name, SlotComponent left, SlotComponent right) {
- super(name);
- this.left = left;
- this.right = right;
+ /**
+ * 0 is not selected, 1 is selected
+ */
+ private final ExponentAnimation selection = new ExponentAnimation(10, 0);
+ private final double angle;
- addChild(left);
- addChild(right);
- setLayout(null);
+ public CursorBoundSlot(SlotComponent component, double angle) {
+ this.component = component;
+ this.angle = angle;
+
+ Vec2i size = component.getPreferredSize();
+ component.setBounds(-size.x / 2, -size.y / 2, size);
+
+ this.renderable = component.assembleToRenderable();
+
+ if (player.getHandCount() == 1) {
+ // Disable opening animation hint
+ selection.setValue(1);
+ }
+ }
+
+ public void render(ShapeRenderHelper renderer) {
+
+ float target = player.getSelectedHand() == component.getSlot().getContainer() ? 1 : 0;
+ float sel = selection.updateForFrame(target);
+
+ float distance = HandSlots.this.distance * (1 - sel);
+ float x = (float) Math.cos(angle) * distance;
+ float y = (float) Math.sin(angle) * distance;
+ float scale = 0.5f + 0.5f * sel;
+
+ renderer.pushTransform().translate(x, y, 0).scale(scale);
+
+ boolean popColor = false;
+ if (sel > 0.5f && component.getSlot().isEmpty()) {
+ renderer.pushColorMultiplier().mul(1, 1, 1, 1 - 2 * (sel - 0.5f));
+ popColor = true;
+ }
+
+ renderable.render(renderer);
+
+ if (popColor) {
+ renderer.popColorMultiplier();
+ }
+
+ renderer.popTransform();
+
+ }
- centerAtOrigin(left);
- centerAtOrigin(right);
- layoutSelf();
}
- private static void centerAtOrigin(Component component) {
- Vec2i size = component.getPreferredSize();
- component.setBounds(-size.x / 2, -size.y / 2, size);
+ private final EntityDataPlayer player;
+
+ private final float distance = 50;
+ private final double startAngle = Math.PI / 4;
+ private final double endAngle = -3 * Math.PI / 4;
+
+ private final CursorBoundSlot[] slots;
+
+ public HandSlots(String name, EntityDataPlayer player) {
+ super(name);
+ this.player = player;
+
+ this.slots = new CursorBoundSlot[player.getHandCount()];
+
+ // This produces NaN when there is only one hand, but then it is unused
+ double angleStep = (endAngle - startAngle) / (slots.length - 1);
+
+ double angle = startAngle;
+ for (int i = 0; i < slots.length; ++i) {
+
+ SpeciesRender speciesRender = SpeciesRenderRegistry.getInstance().get(player);
+
+ ItemContainerHand container = player.getHand(i);
+ Hand hand = container.getHand();
+
+ SlotComponent component = new SlotComponent(name + ".Hand" + hand.getName(), container, 0)
+ .setBackground(speciesRender.getHandBackground(hand));
+
+ addChild(component);
+
+ slots[i] = new CursorBoundSlot(component, angle);
+
+ angle += angleStep;
+
+ }
+
+ setLayout(null);
}
@Override
protected void assembleChildren(RenderTarget target) {
- Renderable leftRenderable = left.assembleToRenderable();
- Renderable rightRenderable = right.assembleToRenderable();
-
target.addCustomRenderer(renderer -> {
- tickAnimation();
-
renderer.pushTransform().translate(
(float) InputTracker.getCursorX(),
(float) InputTracker.getCursorY(),
0
);
- if (selection > 0.5) {
- renderHand(renderer, leftRenderable, selection, -1);
- renderHand(renderer, rightRenderable, 1 - selection, +1);
- } else {
- renderHand(renderer, rightRenderable, 1 - selection, +1);
- renderHand(renderer, leftRenderable, selection, -1);
+ for (CursorBoundSlot slot : slots) {
+ slot.render(renderer);
}
-
+
renderer.popTransform();
});
}
-
- private float stretch(float t, float zero, float one) {
- return zero * (1 - t) + one * t;
- }
-
- private void renderHand(ShapeRenderHelper renderer, Renderable renderable, float selected, float direction) {
-
- float offsetX = direction * stretch(selected, 40, 0);
- float offsetY = direction * stretch(selected, 30, 0);
- float scale = selected < 0.5 ? stretch(selected * 2, 0.6f, 1.0f) : 1;
-
- renderer.pushTransform().translate(offsetX, offsetY, 0).scale(scale);
- renderable.render(renderer);
- renderer.popTransform();
-
- }
-
- private void tickAnimation() {
- float desired = InventoryScreen.isLeftHandSelected() ? 1 : 0;
- float difference = selection - desired;
- selection += difference * (1 - Math.exp(ANIMATION_SPEED * GraphicsInterface.getFrameLength()));
- }
}
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 473fc81..863279e 100644
--- a/src/main/java/ru/windcorp/progressia/test/inv/InventoryScreen.java
+++ b/src/main/java/ru/windcorp/progressia/test/inv/InventoryScreen.java
@@ -20,8 +20,6 @@ package ru.windcorp.progressia.test.inv;
import java.util.function.Consumer;
import java.util.function.Supplier;
-import org.lwjgl.glfw.GLFW;
-
import ru.windcorp.progressia.client.graphics.Colors;
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
import ru.windcorp.progressia.client.graphics.gui.BasicButton;
@@ -35,7 +33,6 @@ import ru.windcorp.progressia.client.graphics.input.WheelScrollEvent;
import ru.windcorp.progressia.client.graphics.input.bus.InputListener;
import ru.windcorp.progressia.common.Units;
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
-import ru.windcorp.progressia.common.world.item.ItemContainer;
import ru.windcorp.progressia.common.world.item.ItemSlot;
import ru.windcorp.progressia.common.world.item.Items;
@@ -43,16 +40,9 @@ public class InventoryScreen extends Component {
private static final double MIN_PICK_ALL_DELAY = Units.get("0.5 s");
- private static boolean isLeftHandSelected = false;
- private static double controlStart = Double.NEGATIVE_INFINITY;
-
- public static boolean isLeftHandSelected() {
- return isLeftHandSelected;
- }
-
- private final ItemContainer leftHand;
- private final ItemContainer rightHand;
private final InventoryComponent mainInventory;
+
+ private final EntityDataPlayer player;
private double lastLeftClick = Double.NEGATIVE_INFINITY;
private ItemSlot lastLeftClickSlot = null;
@@ -60,10 +50,9 @@ public class InventoryScreen extends Component {
public InventoryScreen(String name, InventoryComponent mainInventory, EntityDataPlayer player) {
super(name);
- isLeftHandSelected = false;
this.mainInventory = mainInventory;
- this.leftHand = player.getLeftHand();
- this.rightHand = player.getRightHand();
+
+ this.player = player;
setLayout(new LayoutFill(0));
@@ -73,39 +62,15 @@ public class InventoryScreen extends Component {
mainInventoryPanel.addChild(mainInventory);
addChild(Components.center(mainInventoryPanel));
- SlotComponent leftComponent = new SlotComponent(name + ".HandLeft", leftHand, 0);
- SlotComponent rightComponent = new SlotComponent(name + ".HandRight", rightHand, 0);
-
- addChild(new HandSlots(name + ".Hands", leftComponent, rightComponent));
+ addChild(new HandSlots(name + ".Hands", player));
addListeners(mainInventory);
mainInventory.focusNext();
- mainInventory.addListener(KeyEvent.class, input -> {
- if (input.getKey() == GLFW.GLFW_KEY_LEFT_CONTROL || input.getKey() == GLFW.GLFW_KEY_RIGHT_CONTROL) {
- double now = GraphicsInterface.getTime();
- if (input.isPress()) {
- isLeftHandSelected = !isLeftHandSelected;
- controlStart = now;
- } else if (input.isRelease()) {
- if (now - controlStart > Units.get("200 ms")) {
- isLeftHandSelected = !isLeftHandSelected;
- controlStart = Double.NEGATIVE_INFINITY;
- }
- }
-
- return true;
- }
- return false;
- });
}
private void addListeners(InventoryComponent mainInventory) {
-
- ItemSlot left = leftHand.getSlot(0);
- ItemSlot right = rightHand.getSlot(0);
-
- Supplier handSlot = () -> isLeftHandSelected() ? left : right;
+ Supplier handSlot = () -> player.getSelectedHand().slot();
Consumer pickAll = createPickAllAction(handSlot);
@@ -139,10 +104,6 @@ public class InventoryScreen extends Component {
lastLeftClickSlot = invSlot;
}
- if (!success && !leftHand.getSlot(0).isEmpty() && rightHand.getSlot(0).isEmpty()) {
- success = Items.pour(leftHand.getSlot(0), invSlot) != 0;
- }
-
if (!success) {
success = Items.pour(handSlot, invSlot) != 0;
}
diff --git a/src/main/java/ru/windcorp/progressia/test/inv/TestInventoryGUILayer.java b/src/main/java/ru/windcorp/progressia/test/inv/TestInventoryGUILayer.java
index 8370027..b91da2f 100644
--- a/src/main/java/ru/windcorp/progressia/test/inv/TestInventoryGUILayer.java
+++ b/src/main/java/ru/windcorp/progressia/test/inv/TestInventoryGUILayer.java
@@ -27,6 +27,7 @@ import ru.windcorp.progressia.client.graphics.input.KeyEvent;
import ru.windcorp.progressia.client.graphics.input.bus.Input;
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
import ru.windcorp.progressia.common.world.item.ItemContainerMixed;
+import ru.windcorp.progressia.test.TestPlayerControls;
public class TestInventoryGUILayer extends GUILayer {
@@ -38,6 +39,10 @@ public class TestInventoryGUILayer extends GUILayer {
super("Inventory", new LayoutFill(0));
setCursorPolicy(CursorPolicy.INDIFFERENT);
}
+
+ public boolean hasContainer() {
+ return container != null;
+ }
public void setContainer(ItemContainerMixed container, EntityDataPlayer player) {
this.container = container;
@@ -83,6 +88,8 @@ public class TestInventoryGUILayer extends GUILayer {
}
}
}
+
+ TestPlayerControls.getInstance().handleCtrlIfApplicable(input);
super.handleInput(input);
input.consume();
diff --git a/src/main/java/ru/windcorp/progressia/test/inv/TestInventoryGUIManager.java b/src/main/java/ru/windcorp/progressia/test/inv/TestInventoryGUIManager.java
index 0181a3c..287db88 100644
--- a/src/main/java/ru/windcorp/progressia/test/inv/TestInventoryGUIManager.java
+++ b/src/main/java/ru/windcorp/progressia/test/inv/TestInventoryGUIManager.java
@@ -24,7 +24,7 @@ import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
public class TestInventoryGUIManager {
- private static TestInventoryGUILayer layer;
+ public static TestInventoryGUILayer layer;
public static void setup() {
layer = new TestInventoryGUILayer();
diff --git a/src/main/resources/assets/textures/gui/LeftHand.png b/src/main/resources/assets/textures/gui/Core_Human/HandLeft.png
similarity index 100%
rename from src/main/resources/assets/textures/gui/LeftHand.png
rename to src/main/resources/assets/textures/gui/Core_Human/HandLeft.png
diff --git a/src/main/resources/assets/textures/gui/RightHand.png b/src/main/resources/assets/textures/gui/Core_Human/HandRight.png
similarity index 100%
rename from src/main/resources/assets/textures/gui/RightHand.png
rename to src/main/resources/assets/textures/gui/Core_Human/HandRight.png