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