diff --git a/src/main/java/ru/windcorp/progressia/client/ClientState.java b/src/main/java/ru/windcorp/progressia/client/ClientState.java index 31c366e..36d36ed 100644 --- a/src/main/java/ru/windcorp/progressia/client/ClientState.java +++ b/src/main/java/ru/windcorp/progressia/client/ClientState.java @@ -26,6 +26,7 @@ import ru.windcorp.progressia.server.ServerState; import ru.windcorp.progressia.test.LayerAbout; import ru.windcorp.progressia.test.LayerTestUI; import ru.windcorp.progressia.test.TestContent; +import ru.windcorp.progressia.test.inv.TestInventoryGUIManager; public class ClientState { @@ -55,6 +56,7 @@ public class ClientState { GUI.addBottomLayer(new LayerWorld(client)); GUI.addTopLayer(new LayerTestUI()); + TestInventoryGUIManager.setup(); GUI.addTopLayer(new LayerAbout()); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/GUI.java b/src/main/java/ru/windcorp/progressia/client/graphics/GUI.java index bb4d85b..f29aeed 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/GUI.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/GUI.java @@ -77,6 +77,12 @@ public class GUI { layer.onRemoved(); }); } + + public static void updateLayer(Layer layer) { + modify(layers -> { + // Do nothing + }); + } private static void modify(LayerStackModification mod) { MODIFICATION_QUEUE.add(mod); diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/font/Font.java b/src/main/java/ru/windcorp/progressia/client/graphics/font/Font.java index 591ff83..a40e738 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/font/Font.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/font/Font.java @@ -32,20 +32,23 @@ public class Font { private final int style; private final float align; private final Vec4 color; + + private final int scale; - public Font(Typeface typeface, int style, float align, Vec4 color) { + public Font(Typeface typeface, int style, float align, Vec4 color, int scale) { this.typeface = typeface; this.style = style; this.align = align; this.color = color; + this.scale = scale; } - public Font(Typeface typeface, int style, float align, int color) { - this(typeface, style, align, Colors.toVector(color)); + public Font(Typeface typeface, int style, float align, int color, int scale) { + this(typeface, style, align, Colors.toVector(color), scale); } public Font(Typeface typeface) { - this(typeface, Typeface.Style.PLAIN, Typeface.ALIGN_LEFT, Colors.WHITE); + this(typeface, Typeface.Style.PLAIN, Typeface.ALIGN_LEFT, Colors.WHITE, 2); } public Font() { @@ -67,31 +70,63 @@ public class Font { public Vec4 getColor() { return color; } - - public Renderable assemble( - CharSequence chars, - float maxWidth - ) { - return typeface.assembleStatic(chars, style, align, maxWidth, color); + + public int getScale() { + return scale; + } + + private Renderable applyScale(Renderable unscaled) { + if (scale == 1) { + return unscaled; + } + + return renderer -> { + renderer.pushTransform().scale(scale); + unscaled.render(renderer); + renderer.popTransform(); + }; } - public Renderable assembleDynamic( - Supplier supplier, - float maxWidth - ) { - return typeface.assembleDynamic(supplier, style, align, maxWidth, color); + public Renderable assemble(CharSequence chars, float maxWidth) { + return applyScale(typeface.assembleStatic(chars, style, align, maxWidth, color)); + } + + public Renderable assembleDynamic(Supplier supplier, float maxWidth) { + return applyScale(typeface.assembleDynamic(supplier, style, align, maxWidth, color)); + } + + public Renderable assemble(CharSequence chars) { + return assemble(chars, Float.POSITIVE_INFINITY); + } + + public Renderable assembleDynamic(Supplier supplier) { + return assembleDynamic(supplier, Float.POSITIVE_INFINITY); } public int getWidth(CharSequence chars, float maxWidth) { - return typeface.getWidth(chars, style, align, maxWidth); + return scale * typeface.getWidth(chars, style, align, maxWidth); } public int getHeight(CharSequence chars, float maxWidth) { - return typeface.getHeight(chars, style, align, maxWidth); + return scale * typeface.getHeight(chars, style, align, maxWidth); } public Vec2i getSize(CharSequence chars, float maxWidth, Vec2i result) { - return typeface.getSize(chars, style, align, maxWidth, result); + result = typeface.getSize(chars, style, align, maxWidth, result); + result.mul(scale); + return result; + } + + public int getWidth(CharSequence chars) { + return getWidth(chars, Float.POSITIVE_INFINITY); + } + + public int getHeight(CharSequence chars) { + return getHeight(chars, Float.POSITIVE_INFINITY); + } + + public Vec2i getSize(CharSequence chars, Vec2i result) { + return getSize(chars, Float.POSITIVE_INFINITY, result); } public boolean supports(char c) { @@ -106,7 +141,7 @@ public class Font { * @return the new font */ public Font withStyle(int style) { - return new Font(getTypeface(), style, getAlign(), getColor()); + return new Font(getTypeface(), style, getAlign(), getColor(), getScale()); } public Font deriveBold() { @@ -158,15 +193,19 @@ public class Font { } public Font withAlign(float align) { - return new Font(getTypeface(), getStyle(), align, getColor()); + return new Font(getTypeface(), getStyle(), align, getColor(), getScale()); } public Font withColor(Vec4 color) { - return new Font(getTypeface(), getStyle(), getAlign(), color); + return new Font(getTypeface(), getStyle(), getAlign(), color, getScale()); } public Font withColor(int color) { - return new Font(getTypeface(), getStyle(), getAlign(), color); + return new Font(getTypeface(), getStyle(), getAlign(), color, getScale()); + } + + public Font withScale(int scale) { + return new Font(getTypeface(), getStyle(), getAlign(), getColor(), scale); } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/BasicButton.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/BasicButton.java index cd30152..464a6bf 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/BasicButton.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/BasicButton.java @@ -45,10 +45,15 @@ public abstract class BasicButton extends Component { public BasicButton(String name, String label, Font labelFont) { super(name); - this.label = new Label(name + ".Label", labelFont, label); setLayout(new LayoutAlign(10)); - addChild(this.label); + + if (label == null) { + this.label = null; + } else { + this.label = new Label(name + ".Label", labelFont, label); + addChild(this.label); + } setFocusable(true); reassembleAt(ARTrigger.HOVER, ARTrigger.FOCUS, ARTrigger.ENABLE); @@ -148,4 +153,8 @@ public abstract class BasicButton extends Component { return label; } + public boolean hasLabel() { + return label != null; + } + } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Button.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Button.java index bbeb361..80d59dc 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Button.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Button.java @@ -25,10 +25,13 @@ import ru.windcorp.progressia.client.graphics.Colors; public class Button extends BasicButton { + public static final int MARGIN = 2; + public static final int BORDER = 2; + public Button(String name, String label, Font labelFont) { super(name, label, labelFont); } - + public Button(String name, String label) { this(name, label, new Font()); } @@ -36,7 +39,7 @@ public class Button extends BasicButton { @Override protected void assembleSelf(RenderTarget target) { // Border - + Vec4 borderColor; if (isPressed() || isHovered() || isFocused()) { borderColor = Colors.BLUE; @@ -44,9 +47,9 @@ public class Button extends BasicButton { borderColor = Colors.LIGHT_GRAY; } target.fill(getX(), getY(), getWidth(), getHeight(), borderColor); - + // Inside area - + if (isPressed()) { // Do nothing } else { @@ -56,22 +59,30 @@ public class Button extends BasicButton { } else { backgroundColor = Colors.WHITE; } - target.fill(getX() + 2, getY() + 2, getWidth() - 4, getHeight() - 4, backgroundColor); + target.fill( + getX() + MARGIN, + getY() + MARGIN, + getWidth() - 2 * MARGIN, + getHeight() - 2 * MARGIN, + backgroundColor + ); } - + // Change label font color - - if (isPressed()) { - getLabel().setFont(getLabel().getFont().withColor(Colors.WHITE)); - } else { - getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK)); + + if (hasLabel()) { + if (isPressed()) { + getLabel().setFont(getLabel().getFont().withColor(Colors.WHITE)); + } else { + getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK)); + } } } - + @Override protected void postAssembleSelf(RenderTarget target) { // Apply disable tint - + if (!isEnabled()) { target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF)); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/DynamicLabel.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/DynamicLabel.java index bddad7b..7d24789 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/DynamicLabel.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/DynamicLabel.java @@ -33,7 +33,7 @@ public class DynamicLabel extends Component { super(name); this.font = font; this.contents = contents; - setPreferredSize(width, font.getHeight("", Float.POSITIVE_INFINITY) * 2); + setPreferredSize(width, font.getHeight("", Float.POSITIVE_INFINITY)); } public Font getFont() { @@ -46,7 +46,7 @@ public class DynamicLabel extends Component { @Override protected void assembleSelf(RenderTarget target) { - target.pushTransform(new Mat4().identity().translate(getX(), getY(), -1000).scale(2)); + target.pushTransform(new Mat4().identity().translate(getX(), getY(), -1000)); target.addCustomRenderer(font.assembleDynamic(getContentSupplier(), Float.POSITIVE_INFINITY)); target.popTransform(); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Label.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Label.java index a87ed3b..e582ef5 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Label.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Label.java @@ -70,7 +70,7 @@ public class Label extends Component { public void update() { currentText = contents.get(); - currentSize = font.getSize(currentText, maxWidth, null).mul(2); + currentSize = font.getSize(currentText, maxWidth, null); requestReassembly(); } @@ -99,12 +99,8 @@ public class Label extends Component { protected void assembleSelf(RenderTarget target) { float startX = getX() + font.getAlign() * (getWidth() - currentSize.x); - target.pushTransform( - new Mat4().identity().translate(startX, getY(), 0).scale(2) - ); - + target.pushTransform(new Mat4().identity().translate(startX, getY(), 0)); target.addCustomRenderer(font.assemble(currentText, maxWidth)); - target.popTransform(); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java index 620185b..e24c5b9 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java @@ -15,20 +15,23 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.world; +import org.apache.logging.log4j.LogManager; + import ru.windcorp.progressia.client.Client; import ru.windcorp.progressia.client.world.WorldRender; import ru.windcorp.progressia.client.world.entity.EntityRenderable; import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.entity.EntityDataPlayer; public class LocalPlayer { private final Client client; private long entityId = EntityData.NULL_ENTITY_ID; - private EntityData lastKnownEntity = null; + private EntityDataPlayer lastKnownEntity = null; private final Selection selection = new Selection(); @@ -59,19 +62,31 @@ public class LocalPlayer { return getEntity() != null; } - public EntityData getEntity() { + public EntityDataPlayer getEntity() { if (!hasEntityId()) { return null; } EntityData entity = getClient().getWorld().getData().getEntity(getEntityId()); + EntityDataPlayer playerEntity; - if (entity != lastKnownEntity) { - getClient().onLocalPlayerEntityChanged(entity, lastKnownEntity); - this.lastKnownEntity = entity; + if (entity == null || entity instanceof EntityDataPlayer) { + playerEntity = (EntityDataPlayer) entity; + } else { + LogManager.getLogger().warn( + "Entity ID of local player is {}, but the entity is not an EntityDataPlayer: {}", + EntityData.formatEntityId(getEntityId()), + entity + ); + playerEntity = null; } - return entity; + if (playerEntity != lastKnownEntity) { + getClient().onLocalPlayerEntityChanged(playerEntity, lastKnownEntity); + this.lastKnownEntity = playerEntity; + } + + return playerEntity; } public Selection getSelection() { diff --git a/src/main/java/ru/windcorp/progressia/client/world/UpdatingRenderable.java b/src/main/java/ru/windcorp/progressia/client/world/UpdatingRenderable.java new file mode 100644 index 0000000..cc6120e --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/world/UpdatingRenderable.java @@ -0,0 +1,51 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.client.world; + +import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; +import ru.windcorp.progressia.client.graphics.model.Renderable; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; + +public abstract class UpdatingRenderable implements Renderable { + + private long stateComputedForFrame = -1; + + /** + * Updates the state of this model. This method is invoked exactly once per + * renderable per frame before this model is queried for the first time. + */ + protected void update() { + // Do nothing + } + + protected void updateIfNecessary() { + if (stateComputedForFrame != GraphicsInterface.getFramesRendered()) { + update(); + stateComputedForFrame = GraphicsInterface.getFramesRendered(); + } + } + + @Override + public final void render(ShapeRenderHelper renderer) { + updateIfNecessary(); + doRender(renderer); + } + + protected abstract void doRender(ShapeRenderHelper renderer); + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderable.java b/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderable.java index 1749ffb..154b366 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderable.java +++ b/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderable.java @@ -19,45 +19,18 @@ package ru.windcorp.progressia.client.world.entity; import glm.vec._3.Vec3; -import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; -import ru.windcorp.progressia.client.graphics.model.Renderable; -import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; +import ru.windcorp.progressia.client.world.UpdatingRenderable; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.EntityGeneric; -public abstract class EntityRenderable implements Renderable, EntityGeneric { +public abstract class EntityRenderable extends UpdatingRenderable implements EntityGeneric { private final EntityData data; - - private long stateComputedForFrame = -1; public EntityRenderable(EntityData data) { this.data = data; } - /** - * Updates the state of this model. This method is invoked exactly once per - * renderable per frame before this entity is queried for the first time. - */ - protected void update() { - // Do nothing - } - - private void updateIfNecessary() { - if (stateComputedForFrame != GraphicsInterface.getFramesRendered()) { - update(); - stateComputedForFrame = GraphicsInterface.getFramesRendered(); - } - } - - @Override - public final void render(ShapeRenderHelper renderer) { - updateIfNecessary(); - doRender(renderer); - } - - protected abstract void doRender(ShapeRenderHelper renderer); - public EntityData getData() { return data; } diff --git a/src/main/java/ru/windcorp/progressia/client/world/item/ItemRender.java b/src/main/java/ru/windcorp/progressia/client/world/item/ItemRender.java new file mode 100644 index 0000000..02d1df0 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/world/item/ItemRender.java @@ -0,0 +1,31 @@ +/* + * 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.item; + +import ru.windcorp.progressia.common.util.namespaces.Namespaced; +import ru.windcorp.progressia.common.world.item.ItemData; + +public abstract class ItemRender extends Namespaced { + + public ItemRender(String id) { + super(id); + } + + public abstract ItemRenderable createRenderable(ItemData data); + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/item/ItemRenderRegistry.java b/src/main/java/ru/windcorp/progressia/client/world/item/ItemRenderRegistry.java new file mode 100644 index 0000000..00fd62d --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/world/item/ItemRenderRegistry.java @@ -0,0 +1,51 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world.item; + +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; +import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; + +public class ItemRenderRegistry extends NamespacedInstanceRegistry { + + private static final ItemRenderRegistry INSTANCE = new ItemRenderRegistry(); + + private static final AtlasGroup ITEMS_ATLAS_GROUP = new AtlasGroup("Items", 1 << 12); + + public static ItemRenderRegistry getInstance() { + return INSTANCE; + } + + public static Texture getItemTexture(String name) { + return new SimpleTexture( + Atlases.getSprite( + ResourceManager.getTextureResource("items/" + name), + ITEMS_ATLAS_GROUP + ) + ); + } + + public static AtlasGroup getItemsAtlasGroup() { + return ITEMS_ATLAS_GROUP; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/item/ItemRenderSimple.java b/src/main/java/ru/windcorp/progressia/client/world/item/ItemRenderSimple.java new file mode 100644 index 0000000..f779ddc --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/world/item/ItemRenderSimple.java @@ -0,0 +1,69 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.client.world.item; + +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.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.ShapeRenderHelper; +import ru.windcorp.progressia.client.graphics.texture.Texture; +import ru.windcorp.progressia.common.world.item.ItemData; + +public class ItemRenderSimple extends ItemRender { + + private Texture texture; + private Renderable renderable; + + public ItemRenderSimple(String id, Texture texture) { + super(id); + this.texture = texture; + + this.renderable = 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 + ) + ); + } + + public Texture getTexture() { + return texture; + } + + @Override + public ItemRenderable createRenderable(ItemData data) { + return new ItemRenderable(data) { + @Override + protected void doRender(ShapeRenderHelper renderer) { + renderable.render(renderer); + } + }; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/item/ItemRenderable.java b/src/main/java/ru/windcorp/progressia/client/world/item/ItemRenderable.java new file mode 100644 index 0000000..0e8a6d5 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/world/item/ItemRenderable.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.item; + +import ru.windcorp.progressia.client.world.UpdatingRenderable; +import ru.windcorp.progressia.common.world.item.ItemData; + +public abstract class ItemRenderable extends UpdatingRenderable { + + private final ItemData data; + + public ItemRenderable(ItemData data) { + this.data = data; + } + + public ItemData getData() { + return data; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/Units.java b/src/main/java/ru/windcorp/progressia/common/Units.java index 842e378..cdaef34 100644 --- a/src/main/java/ru/windcorp/progressia/common/Units.java +++ b/src/main/java/ru/windcorp/progressia/common/Units.java @@ -65,6 +65,8 @@ public class Units { // Volume public static final float CUBIC_CENTIMETERS = CENTIMETERS * CENTIMETERS * CENTIMETERS; + @RegisteredUnit("L") + public static final float LITERS = (10 * CENTIMETERS) * (10 * CENTIMETERS) * (10 * CENTIMETERS); public static final float CUBIC_METERS = METERS * METERS * METERS; public static final float CUBIC_MILLIMETERS = MILLIMETERS * MILLIMETERS * MILLIMETERS; public static final float CUBIC_KILOMETERS = KILOMETERS * KILOMETERS * KILOMETERS; diff --git a/src/main/java/ru/windcorp/progressia/common/state/StatefulObjectRegistry.java b/src/main/java/ru/windcorp/progressia/common/state/StatefulObjectRegistry.java index aa082a6..25cbf92 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/StatefulObjectRegistry.java +++ b/src/main/java/ru/windcorp/progressia/common/state/StatefulObjectRegistry.java @@ -42,6 +42,16 @@ public class StatefulObjectRegistry { */ T build(); } + + @FunctionalInterface + public static interface IdFactory { + /** + * Initializes a new, independent instance of the stateful object. + * + * @return the created object + */ + T build(String id); + } protected static class Type extends Namespaced { @@ -110,5 +120,9 @@ public class StatefulObjectRegistry { public void register(String id, Factory factory) { registry.register(new Type<>(id, factory)); } + + public void register(String id, IdFactory factory) { + register(id, () -> factory.build(id)); + } } 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 new file mode 100644 index 0000000..323d781 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityDataPlayer.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.common.world.entity; + +import ru.windcorp.progressia.common.Units; +import ru.windcorp.progressia.common.collision.AABB; +import ru.windcorp.progressia.common.state.ObjectStateField; +import ru.windcorp.progressia.common.world.item.DefaultItemContainer; +import ru.windcorp.progressia.common.world.item.ItemContainer; + +public class EntityDataPlayer extends EntityData { + + private final ObjectStateField inventory = field("Core:Inventory").setShared().def( + () -> new DefaultItemContainer("Core:PlayerInventory", Units.get(15, "kg"), Units.get(50, "L")) + ).build(); + + public EntityDataPlayer(String id) { + super(id); + + setCollisionModel(new AABB(0, 0, 1.8f / 2, 0.8f, 0.8f, 1.8f)); + } + + public ItemContainer getInventory() { + return inventory.get(this); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ItemGeneric.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ItemGeneric.java new file mode 100644 index 0000000..d3fd64c --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ItemGeneric.java @@ -0,0 +1,24 @@ +/* + * 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.generic; + +public interface ItemGeneric { + + String getId(); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/item/DefaultItemContainer.java b/src/main/java/ru/windcorp/progressia/common/world/item/DefaultItemContainer.java new file mode 100644 index 0000000..40d47db --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/item/DefaultItemContainer.java @@ -0,0 +1,53 @@ +/* + * 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.util.ArrayList; + +public class DefaultItemContainer extends ItemContainer { + + private final float massLimit; + private final float volumeLimit; + + public DefaultItemContainer(String id, float massLimit, float volumeLimit) { + super(id, new ArrayList<>()); + this.massLimit = massLimit; + this.volumeLimit = volumeLimit; + } + + @Override + public void addSlots(int amount) { + synchronized (getSlots()) { + ((ArrayList) list).ensureCapacity(list.size() + amount); + for (int i = 0; i < amount; ++i) { + list.add(new ItemSlot()); + } + } + } + + @Override + public float getMassLimit() { + return massLimit; + } + + @Override + public float getVolumeLimit() { + return volumeLimit; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/item/ItemContainer.java b/src/main/java/ru/windcorp/progressia/common/world/item/ItemContainer.java new file mode 100644 index 0000000..027420b --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/item/ItemContainer.java @@ -0,0 +1,165 @@ +/* + * 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.Collections; +import java.util.List; + +import ru.windcorp.progressia.common.state.Encodable; +import ru.windcorp.progressia.common.state.IOContext; +import ru.windcorp.progressia.common.util.namespaces.Namespaced; + +/** + * A collection of {@link ItemSlot}s representing a single storage unit. The set + * of slots is dynamic: new slots may be added and existing slots may be removed + * at will. A container may impose limits on the maximum total mass and volume + * of its contents, although this is not enforced on data structure level. + */ +public abstract class ItemContainer extends Namespaced implements Encodable { + + private final List synchronizedListView; + protected final List list; + + public ItemContainer(String id, List list) { + super(id); + this.list = list; + this.synchronizedListView = Collections.synchronizedList(list); + } + + /** + * Retrieves the modifiable {@link List} of all slots. Edits commissioned + * through the returned object update the state of the container. + *

+ * It should be assumed that the returned list is + * {@linkplain Collections#synchronizedList(List) synchronized}. + * + * @return a list view of this container + */ + public final List getSlots() { + return this.synchronizedListView; + } + + /** + * Appends additional empty slots to the end of this container. + * + * @param amount the amount of slots to add + */ + public abstract void addSlots(int amount); + + /** + * Computes and returns the mass limit that the container imposes. + * + * @return the maximum allowed total mass of the container's contents, or + * {@code Float.POSITIVE_INFINITY} to indicate that no upper + * boundary is set + */ + public abstract float getMassLimit(); + + /** + * Computes and returns the volume limit that the container imposes. + * + * @return the maximum allowed total volume of the container's contents, or + * {@code Float.POSITIVE_INFINITY} to indicate that no upper + * boundary is set + */ + public abstract float getVolumeLimit(); + + @Override + public synchronized void read(DataInput input, IOContext context) throws IOException { + List slots = getSlots(); + synchronized (slots) { + + int needSlots = input.readInt(); + int hasSlots = slots.size(); + + int costOfResetting = needSlots; + int costOfEditing = Math.abs(needSlots - hasSlots); + + if (costOfResetting < costOfEditing) { + slots.clear(); + addSlots(needSlots); + } else { + while (slots.size() > needSlots) { + getSlots().remove(slots.size() - 1); + } + + if (slots.size() < needSlots) { + addSlots(needSlots - slots.size()); + } + } + + for (int i = 0; i < needSlots; ++i) { + slots.get(i).read(input, context); + } + + } + } + + @Override + public synchronized void write(DataOutput output, IOContext context) throws IOException { + List slots = getSlots(); + synchronized (slots) { + + output.writeInt(slots.size()); + for (int i = 0; i < slots.size(); ++i) { + slots.get(i).write(output, context); + } + + } + } + + @Override + public void copy(Encodable destination) { + ItemContainer container = (ItemContainer) destination; + List mySlots = this.getSlots(); + List containerSlots = container.getSlots(); + + synchronized (mySlots) { + synchronized (containerSlots) { + + int needSlots = mySlots.size(); + int hasSlots = containerSlots.size(); + + int costOfResetting = needSlots; + int costOfEditing = Math.abs(needSlots - hasSlots); + + if (costOfResetting < costOfEditing) { + containerSlots.clear(); + container.addSlots(needSlots); + } else { + while (containerSlots.size() > needSlots) { + getSlots().remove(containerSlots.size() - 1); + } + + if (containerSlots.size() < needSlots) { + addSlots(needSlots - containerSlots.size()); + } + } + + for (int i = 0; i < needSlots; ++i) { + mySlots.get(i).copy(containerSlots.get(i)); + } + + } + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/item/ItemData.java b/src/main/java/ru/windcorp/progressia/common/world/item/ItemData.java new file mode 100644 index 0000000..dcd844e --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/item/ItemData.java @@ -0,0 +1,103 @@ +/* + * 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.state.IntStateField; +import ru.windcorp.progressia.common.state.StatefulObject; +import ru.windcorp.progressia.common.world.generic.ItemGeneric; + +/** + * A collection of identical items identified by their ID, properties and + * amount, able to reside in a slot. Also known as an item stack. + *

+ * An empty stack does not have an {@code ItemData} representation; stack size + * is at least 1. + */ +public abstract class ItemData extends StatefulObject implements ItemGeneric { + + private final IntStateField size = field("Core:Size").setShared().ofInt().build(); + + public ItemData(String id) { + super(ItemDataRegistry.getInstance(), id); + size.setNow(this, 1); + } + + /** + * Returns the amount of individual items represented by this item stack. + * + * @return the size of this stack + */ + public final int getSize() { + return size.get(this); + } + + /** + * Sets the amount of items represented by this item stack. + * + * @param size the new size of this stack, strictly positive + */ + public final void setSizeNow(int size) { + if (size <= 0) { + throw new IllegalArgumentException("size cannot be negative, given size " + size); + } + this.size.setNow(this, size); + } + + /** + * Computes and returns the total mass of this item stack. It is defined as + * the item's unit mass (see {@link #getUnitMass()}) multiplied by the + * amount of items in the stack. + * + * @return the mass of this stack + * @see #getUnitMass() + */ + public final float getMass() { + return getUnitMass() * getSize(); + } + + /** + * Computes and returns the mass of a single unit (single item) of this item + * stack. + * + * @return the mass of a single item in this stack + * @see #getMass() + */ + public abstract float getUnitMass(); + + /** + * Computes and returns the total volume of this item stack. It is defined + * as the item's unit volume (see {@link #getUnitVolume()}) multiplied by + * the amount of items in the stack. + * + * @return the mass of this stack + * @see #getUnitVolume() + */ + public final float getVolume() { + return getUnitVolume() * getSize(); + } + + /** + * Computes and returns the volume of a single unit (single item) of this + * item stack. + * + * @return the volume of a single item in this stack + * @see #getVolume() + */ + public abstract float getUnitVolume(); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/item/ItemDataRegistry.java b/src/main/java/ru/windcorp/progressia/common/world/item/ItemDataRegistry.java new file mode 100644 index 0000000..bb99926 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/item/ItemDataRegistry.java @@ -0,0 +1,30 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.item; + +import ru.windcorp.progressia.common.state.StatefulObjectRegistry; + +public class ItemDataRegistry extends StatefulObjectRegistry { + + private static final ItemDataRegistry INSTANCE = new ItemDataRegistry(); + + public static ItemDataRegistry getInstance() { + return INSTANCE; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/item/ItemDataSimple.java b/src/main/java/ru/windcorp/progressia/common/world/item/ItemDataSimple.java new file mode 100644 index 0000000..68a366e --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/item/ItemDataSimple.java @@ -0,0 +1,41 @@ +/* + * 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; + +public class ItemDataSimple extends ItemData { + + private final float unitMass; + private final float unitVolume; + + public ItemDataSimple(String id, float unitMass, float unitVolume) { + super(id); + this.unitMass = unitMass; + this.unitVolume = unitVolume; + } + + @Override + public float getUnitMass() { + return unitMass; + } + + @Override + public float getUnitVolume() { + return unitVolume; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/item/ItemSlot.java b/src/main/java/ru/windcorp/progressia/common/world/item/ItemSlot.java new file mode 100644 index 0000000..45d5478 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/item/ItemSlot.java @@ -0,0 +1,89 @@ +/* + * 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 ru.windcorp.progressia.common.state.Encodable; +import ru.windcorp.progressia.common.state.IOContext; + +/** + * An entity optionally containing an {@link ItemData}. Item slots are typically + * found in {@link ItemContainer}s. + */ +public class ItemSlot implements Encodable { + + private ItemData contents; + + /** + * Retrieves the contents of this slot. + * + * @return the stored {@link ItemData} or {@code null} + */ + public synchronized final ItemData getContents() { + return contents; + } + + /** + * Sets the new contents of this slot. If an item stack was present + * previously, it is discarded. + * + * @param contents the new contents of this slot or {@code null} to clear + * the slot + */ + public synchronized final void setContents(ItemData contents) { + this.contents = contents; + } + + @Override + public synchronized void read(DataInput input, IOContext context) throws IOException { + if (input.readBoolean()) { + String id = input.readUTF(); + contents = ItemDataRegistry.getInstance().create(id); + contents.read(input, context); + } else { + contents = null; + } + } + + @Override + public synchronized void write(DataOutput output, IOContext context) throws IOException { + output.writeBoolean(contents != null); + if (contents != null) { + output.writeUTF(contents.getId()); + contents.write(output, context); + } + } + + @Override + public void copy(Encodable destination) { + ItemSlot slot = (ItemSlot) destination; + + if (this.contents == null) { + slot.contents = null; + } else { + if (slot.contents == null || !slot.contents.isLike(this.contents)) { + slot.contents = ItemDataRegistry.getInstance().create(this.contents.getId()); + } + this.contents.copy(slot.contents); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/PlayerManager.java b/src/main/java/ru/windcorp/progressia/server/PlayerManager.java index f762778..d33b4d7 100644 --- a/src/main/java/ru/windcorp/progressia/server/PlayerManager.java +++ b/src/main/java/ru/windcorp/progressia/server/PlayerManager.java @@ -25,7 +25,10 @@ import java.util.Collections; import glm.vec._3.Vec3; import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.entity.EntityDataPlayer; import ru.windcorp.progressia.common.world.entity.EntityDataRegistry; +import ru.windcorp.progressia.common.world.item.ItemData; +import ru.windcorp.progressia.common.world.item.ItemDataRegistry; import ru.windcorp.progressia.server.events.PlayerJoinedEvent; import ru.windcorp.progressia.test.TestContent; @@ -58,16 +61,22 @@ public class PlayerManager { } } - private EntityData spawnPlayerEntity(String login) { - EntityData player = EntityDataRegistry.getInstance().create("Test:Player"); - - player.setEntityId(TestContent.PLAYER_ENTITY_ID); - player.setPosition(getServer().getWorld().getGenerator().suggestSpawnLocation()); + private EntityDataPlayer spawnPlayerEntity(String login) { + EntityDataPlayer player = (EntityDataPlayer) EntityDataRegistry.getInstance().create("Core:Player"); + player.getInventory().addSlots(10); + + ItemData stack = ItemDataRegistry.getInstance().create("Test:MoonTypeIceCream"); + stack.setSizeNow(5); + player.getInventory().getSlots().get(3).setContents(stack); + + player.getInventory().getSlots().get(6).setContents(ItemDataRegistry.getInstance().create("Test:MoonTypeIceCream")); + + player.setPosition(getServer().getWorld().getGenerator().suggestSpawnLocation()); player.setUpVector(new Vec3(0, 0, 1)); player.setLookingAt(new Vec3(2, 1, 0)); - - getServer().getWorld().getData().addEntity(player); + + getServer().getWorld().spawnEntity(player); return player; } diff --git a/src/main/java/ru/windcorp/progressia/test/TestBlockLogicStatieSpawner.java b/src/main/java/ru/windcorp/progressia/test/TestBlockLogicStatieSpawner.java index 99335ae..258e9f3 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestBlockLogicStatieSpawner.java +++ b/src/main/java/ru/windcorp/progressia/test/TestBlockLogicStatieSpawner.java @@ -21,6 +21,7 @@ import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.entity.EntityDataRegistry; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.block.TickableBlock; import ru.windcorp.progressia.server.world.context.ServerBlockContext; @@ -36,7 +37,7 @@ public class TestBlockLogicStatieSpawner extends BlockLogic implements TickableB @Override public void tick(ServerBlockContext context) { Vec3i loc = context.toAbsolute(context.getLocation(), null); - EntityData entity = new TestEntityDataStatie(); + EntityData entity = EntityDataRegistry.getInstance().create("Test:Statie"); entity.setPosition(new Vec3(loc.x, loc.y, loc.z)); context.addEntity(entity); diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java index 9ad6518..2582fb8 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestContent.java +++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java @@ -20,6 +20,7 @@ package ru.windcorp.progressia.test; import static ru.windcorp.progressia.client.world.block.BlockRenderRegistry.getBlockTexture; import static ru.windcorp.progressia.client.world.tile.TileRenderRegistry.getTileTexture; +import static ru.windcorp.progressia.client.world.item.ItemRenderRegistry.getItemTexture; import java.util.ArrayList; import java.util.Arrays; @@ -27,7 +28,6 @@ import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.function.Consumer; import org.lwjgl.glfw.GLFW; import glm.vec._3.i.Vec3i; @@ -42,15 +42,21 @@ import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerRegistry; import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSimple; import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSurface; import ru.windcorp.progressia.client.world.entity.*; +import ru.windcorp.progressia.client.world.item.ItemRender; +import ru.windcorp.progressia.client.world.item.ItemRenderRegistry; +import ru.windcorp.progressia.client.world.item.ItemRenderSimple; import ru.windcorp.progressia.client.world.tile.*; -import ru.windcorp.progressia.common.collision.AABB; +import ru.windcorp.progressia.common.Units; import ru.windcorp.progressia.common.collision.CollisionModel; import ru.windcorp.progressia.common.comms.controls.*; -import ru.windcorp.progressia.common.state.StatefulObjectRegistry.Factory; +import ru.windcorp.progressia.common.state.StatefulObjectRegistry.IdFactory; import ru.windcorp.progressia.common.world.GravityModelRegistry; import ru.windcorp.progressia.common.world.block.*; import ru.windcorp.progressia.common.world.entity.*; import ru.windcorp.progressia.common.world.io.ChunkIO; +import ru.windcorp.progressia.common.world.item.ItemData; +import ru.windcorp.progressia.common.world.item.ItemDataRegistry; +import ru.windcorp.progressia.common.world.item.ItemDataSimple; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.tile.*; import ru.windcorp.progressia.server.Server; @@ -64,12 +70,11 @@ import ru.windcorp.progressia.server.world.generation.planet.PlanetGravityModel; import ru.windcorp.progressia.server.world.tile.*; import ru.windcorp.progressia.test.Rocks.RockType; import ru.windcorp.progressia.test.gen.TestGravityModel; +import ru.windcorp.progressia.test.inv.TestInventoryGUIManager; public class TestContent { public static final String PLAYER_LOGIN = "Sasha"; - public static final long PLAYER_ENTITY_ID = 0x42; - public static final long STATIE_ENTITY_ID = 0xDEADBEEF; public static final List PLACEABLE_BLOCKS = new ArrayList<>(); public static final List PLACEABLE_TILES = new ArrayList<>(); @@ -85,6 +90,7 @@ public class TestContent { private static void registerWorldContent() { registerBlocks(); registerTiles(); + registerItems(); registerEntities(); } @@ -235,6 +241,10 @@ public class TestContent { PLACEABLE_TILES.removeIf(b -> placeableBlacklist.contains(b.getId())); PLACEABLE_TILES.sort(Comparator.comparing(TileData::getId)); } + + private static void registerItems() { + registerSimplestItem("MoonTypeIceCream", Units.get("200 g"), Units.get("1 L")); + } private static void registerSimplestBlock(String name) { String id = "Test:" + name; @@ -263,14 +273,19 @@ public class TestContent { register(new TileRenderHerb(id, getTileTexture(name), maxCount)); register(new HangingTileLogic(id)); } + + private static void registerSimplestItem(String name, float mass, float volume) { + String id = "Test:" + name; + registerItem(id, s -> new ItemDataSimple(s, mass, volume)); + register(new ItemRenderSimple(id, getItemTexture(name))); + } private static void registerEntities() { - float scale = 1.8f / 8; - registerEntityData("Test:Player", e -> e.setCollisionModel(new AABB(0, 0, 4 * scale, 0.8f, 0.8f, 1.8f))); - register(new TestEntityRenderHuman("Test:Player")); - register(new EntityLogic("Test:Player")); + registerEntity("Core:Player", EntityDataPlayer::new); + register(new TestEntityRenderHuman("Core:Player")); + register(new EntityLogic("Core:Player")); - register("Test:Statie", TestEntityDataStatie::new); + registerEntity("Test:Statie", TestEntityDataStatie::new); register(new TestEntityRenderStatie("Test:Statie")); register(new TestEntityLogicStatie("Test:Statie")); } @@ -325,6 +340,15 @@ public class TestContent { KeyMatcher.of(GLFW.GLFW_KEY_M).matcher() ) ); + + triggers.register( + ControlTriggers.localOf( + "Test:OpenInventory", + KeyEvent.class, + TestInventoryGUIManager::openGUI, + KeyMatcher.of(GLFW.GLFW_KEY_E).matcher() + ) + ); } private static void register(BlockData x) { @@ -334,28 +358,18 @@ public class TestContent { private static void register(TileData x) { TileDataRegistry.getInstance().register(x); } - - private static void register( + + private static void registerItem(String id, IdFactory factory) { + ItemDataRegistry.getInstance().register(id, factory); + } + + private static void registerEntity( String id, - Factory factory + IdFactory factory ) { EntityDataRegistry.getInstance().register(id, factory); } - private static void registerEntityData( - String id, - Consumer transform - ) { - EntityDataRegistry.getInstance().register(id, new Factory() { - @Override - public EntityData build() { - EntityData entity = new EntityData(id); - transform.accept(entity); - return entity; - } - }); - } - private static void register(BlockRender x) { BlockRenderRegistry.getInstance().register(x); } @@ -363,6 +377,10 @@ public class TestContent { private static void register(TileRender x) { TileRenderRegistry.getInstance().register(x); } + + private static void register(ItemRender x) { + ItemRenderRegistry.getInstance().register(x); + } private static void register(EntityRender x) { EntityRenderRegistry.getInstance().register(x); diff --git a/src/main/java/ru/windcorp/progressia/test/TestEntityDataStatie.java b/src/main/java/ru/windcorp/progressia/test/TestEntityDataStatie.java index 94f5043..0e26c72 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestEntityDataStatie.java +++ b/src/main/java/ru/windcorp/progressia/test/TestEntityDataStatie.java @@ -26,10 +26,6 @@ public class TestEntityDataStatie extends EntityData { private final IntStateField size = field("Test:Size").setShared().ofInt().build(); - public TestEntityDataStatie() { - this("Test:Statie"); - } - protected TestEntityDataStatie(String id) { super(id); setCollisionModel(new AABB(0, 0, 0, 1, 1, 1)); diff --git a/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java b/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java index ee42396..46bdacc 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java +++ b/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java @@ -15,7 +15,7 @@ * 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 glm.Glm; @@ -41,6 +41,7 @@ import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.entity.EntityDataPlayer; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.server.ServerState; @@ -114,8 +115,9 @@ public class TestPlayerControls { desiredVelocity.normalize(); } desiredVelocity.z = movementUp; - movementTransform.mul_(desiredVelocity); // bug in jglm, .mul() and .mul_() are - // swapped + movementTransform.mul_(desiredVelocity); // bug in jglm, .mul() and + // .mul_() are + // swapped desiredVelocity.mul(speed); Vec3 newVelocity = new Vec3() @@ -134,8 +136,8 @@ public class TestPlayerControls { player.getVelocity().set(newVelocity); // THIS IS TERRIBLE TEST - EntityData serverEntity = ServerState.getInstance().getWorld().getData() - .getEntity(TestContent.PLAYER_ENTITY_ID); + EntityData serverEntity = ServerState.getInstance().getWorld().getEntities().stream() + .filter(EntityDataPlayer.class::isInstance).findAny().orElse(null); if (serverEntity != null) { serverEntity.setPosition(player.getPosition()); } @@ -146,15 +148,21 @@ public class TestPlayerControls { if (mat == null) { mat = new Mat3(); } - + Vec3 f = player.getForwardVector(null); Vec3 u = player.getUpVector(); Vec3 s = u.cross_(f); - + return mat.set( - +f.x, +f.y, +f.z, - -s.x, -s.y, -s.z, - +u.x, +u.y, +u.z + +f.x, + +f.y, + +f.z, + -s.x, + -s.y, + -s.z, + +u.x, + +u.y, + +u.z ); } @@ -201,7 +209,7 @@ public class TestPlayerControls { case GLFW.GLFW_KEY_ESCAPE: if (!event.isPress()) return false; - + handleEscape(); break; @@ -296,7 +304,7 @@ public class TestPlayerControls { } Vec3 up = getEntity().getUpVector(); - + getEntity().getVelocity().add( up.x * JUMP_VELOCITY, up.y * JUMP_VELOCITY, @@ -359,31 +367,31 @@ public class TestPlayerControls { final double yawScale = -0.002f; final double pitchScale = -yawScale; - final double pitchExtremum = Math.PI/2 * 0.95f; - + final double pitchExtremum = Math.PI / 2 * 0.95f; + double yawChange = event.getChangeX() * yawScale; double pitchChange = event.getChangeY() * pitchScale; EntityData player = getEntity(); - + double startPitch = player.getPitch(); double endPitch = startPitch + pitchChange; endPitch = Glm.clamp(endPitch, -pitchExtremum, +pitchExtremum); pitchChange = endPitch - startPitch; - + Mat4 mat = Matrices.grab4(); - Vec3 lookingAt = Vectors.grab3(); + Vec3 lookingAt = Vectors.grab3(); Vec3 rightVector = Vectors.grab3(); rightVector.set(player.getLookingAt()).cross(player.getUpVector()).normalize(); - + mat.identity() .rotate((float) yawChange, player.getUpVector()) .rotate((float) pitchChange, rightVector); - + VectorUtil.applyMat4(player.getLookingAt(), mat, lookingAt); player.setLookingAt(lookingAt); - + Vectors.release(rightVector); Vectors.release(lookingAt); Matrices.release(mat); diff --git a/src/main/java/ru/windcorp/progressia/test/inv/InventoryComponent.java b/src/main/java/ru/windcorp/progressia/test/inv/InventoryComponent.java new file mode 100644 index 0000000..425dd2f --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/inv/InventoryComponent.java @@ -0,0 +1,57 @@ +/* + * 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.inv; + +import glm.vec._2.i.Vec2i; +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.LayoutGrid; +import ru.windcorp.progressia.common.world.item.ItemContainer; +import ru.windcorp.progressia.common.world.item.ItemSlot; + +public class InventoryComponent extends Component { + + private final TestInventoryGUILayer layer; + private final Group slots = new Group("Inventory.Slots", new LayoutGrid(15)); + + public InventoryComponent(TestInventoryGUILayer layer) { + super("Inventory"); + this.layer = layer; + + setLayout(new LayoutBorderHorizontal(15)); + addChild(slots.setLayoutHint(LayoutBorderHorizontal.CENTER)); + + getContainer().getSlots().forEach(this::addSlot); + } + + private void addSlot(ItemSlot slot) { + final int maxX = 6; + int i = slots.getChildren().size(); + + SlotComponent component = new SlotComponent("Inventory.Slot" + i, slot); + + Vec2i pos = new Vec2i(i % maxX, i / maxX); + slots.addChild(component.setLayoutHint(pos)); + } + + private ItemContainer getContainer() { + return layer.container; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/inv/SlotComponent.java b/src/main/java/ru/windcorp/progressia/test/inv/SlotComponent.java new file mode 100644 index 0000000..d9adf69 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/inv/SlotComponent.java @@ -0,0 +1,96 @@ +/* + * 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.inv; + +import glm.mat._4.Mat4; +import ru.windcorp.progressia.client.graphics.flat.RenderTarget; +import ru.windcorp.progressia.client.graphics.font.Font; +import ru.windcorp.progressia.client.graphics.gui.Button; +import ru.windcorp.progressia.client.graphics.gui.DynamicLabel; +import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign; +import ru.windcorp.progressia.client.world.item.ItemRenderRegistry; +import ru.windcorp.progressia.client.world.item.ItemRenderable; +import ru.windcorp.progressia.common.world.item.ItemData; +import ru.windcorp.progressia.common.world.item.ItemSlot; + +public class SlotComponent extends Button { + + private static final float TEXTURE_SIZE = 24; + private static final float SCALE = 2; + + private final ItemSlot slot; + private ItemRenderable itemRenderer = null; + + private int sizeDisplayInt = 0; + private String sizeDisplayString = ""; + + public SlotComponent(String name, ItemSlot slot) { + super(name, null, null); + this.slot = slot; + + int side = (int) (TEXTURE_SIZE * SCALE) + 2 * BORDER; + setPreferredSize(side, side); + + Font sizeFont = new Font().deriveOutlined().withScale(1); + addChild(new DynamicLabel(name + ".Size", sizeFont, () -> sizeDisplayString, side - 2 * MARGIN)); + + setLayout(new LayoutAlign(0, 0, MARGIN)); + } + + public ItemSlot getSlot() { + return slot; + } + + @Override + protected void assembleSelf(RenderTarget target) { + super.assembleSelf(target); + + updateItemRenderer(); + + assembleItem(target); + } + + private void updateItemRenderer() { + ItemData contents = slot.getContents(); + + if (contents == null) { + itemRenderer = null; + sizeDisplayInt = 0; + sizeDisplayString = ""; + } else { + if (itemRenderer == null || itemRenderer.getData() != contents) { + itemRenderer = ItemRenderRegistry.getInstance().get(contents.getId()).createRenderable(contents); + } + + int newSize = contents.getSize(); + if (newSize != sizeDisplayInt) { + sizeDisplayInt = newSize; + sizeDisplayString = newSize == 1 ? "" : Integer.toString(newSize); + } + } + } + + private void assembleItem(RenderTarget target) { + if (itemRenderer != null) { + target.pushTransform(new Mat4().translate(getX() + BORDER, getY() + BORDER, 0).scale(SCALE)); + target.addCustomRenderer(itemRenderer); + target.popTransform(); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/inv/TestInventoryGUILayer.java b/src/main/java/ru/windcorp/progressia/test/inv/TestInventoryGUILayer.java new file mode 100644 index 0000000..0498972 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/inv/TestInventoryGUILayer.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.test.inv; + +import org.lwjgl.glfw.GLFW; + +import ru.windcorp.progressia.client.graphics.GUI; +import ru.windcorp.progressia.client.graphics.gui.menu.MenuLayer; +import ru.windcorp.progressia.client.graphics.input.InputEvent; +import ru.windcorp.progressia.client.graphics.input.KeyEvent; +import ru.windcorp.progressia.client.graphics.input.bus.Input; +import ru.windcorp.progressia.common.world.item.ItemContainer; + +public class TestInventoryGUILayer extends MenuLayer { + + ItemContainer container; + private InventoryComponent display = null; + + public TestInventoryGUILayer() { + super("Inventory"); + setCursorPolicy(CursorPolicy.INDIFFERENT); + + addTitle(); // pppffffttt + } + + public void setContainer(ItemContainer container) { + this.container = container; + + getContent().removeChild(display); + display = null; + + if (container != null) { + display = new InventoryComponent(this); + getContent().addChild(display); + invalidate(); + + setCursorPolicy(CursorPolicy.REQUIRE); + } else { + setCursorPolicy(CursorPolicy.INDIFFERENT); + } + + GUI.updateLayer(this); + } + + @Override + protected Runnable getCloseAction() { + return () -> setContainer(null); + } + + @Override + protected void doRender() { + if (container != null) { + super.doRender(); + } + } + + @Override + protected void handleInput(Input input) { + if (container != null) { + if (!input.isConsumed()) { + InputEvent event = input.getEvent(); + + if (event instanceof KeyEvent) { + KeyEvent keyEvent = (KeyEvent) event; + if (keyEvent.isPress() && keyEvent.getKey() == GLFW.GLFW_KEY_E) { + getCloseAction().run(); + input.consume(); + } + } + } + + super.handleInput(input); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/inv/TestInventoryGUIManager.java b/src/main/java/ru/windcorp/progressia/test/inv/TestInventoryGUIManager.java new file mode 100644 index 0000000..6af3966 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/inv/TestInventoryGUIManager.java @@ -0,0 +1,59 @@ +/* + * 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.inv; + +import ru.windcorp.progressia.client.Client; +import ru.windcorp.progressia.client.ClientState; +import ru.windcorp.progressia.client.graphics.GUI; +import ru.windcorp.progressia.common.world.entity.EntityDataPlayer; + +public class TestInventoryGUIManager { + + private static TestInventoryGUILayer layer; + + public static void setup() { + layer = new TestInventoryGUILayer(); + GUI.addTopLayer(layer); + } + + public static void shutdown() { + GUI.getLayers().stream().filter(TestInventoryGUILayer.class::isInstance).forEach(GUI::removeLayer); + layer = null; + } + + public static void openGUI() { + + Client client = ClientState.getInstance(); + if (client == null) { + return; + } + + if (layer == null) { + return; + } + + EntityDataPlayer entity = client.getLocalPlayer().getEntity(); + if (entity == null) { + return; + } + + layer.setContainer(entity.getInventory()); + + } + +} diff --git a/src/main/resources/assets/languages/en-US.lang b/src/main/resources/assets/languages/en-US.lang index e2ff70b..b4123f8 100644 --- a/src/main/resources/assets/languages/en-US.lang +++ b/src/main/resources/assets/languages/en-US.lang @@ -21,4 +21,5 @@ LayerTestGUI.PlacementModeHint = (Blocks %s Tiles: Ctrl + Mouse Wheel) LayerTestGUI.IsFullscreen = Fullscreen: %5s (F11) LayerTestGUI.IsVSync = VSync: %5s (F12) -LayerButtonTest.Title = Button Test \ No newline at end of file +LayerButtonTest.Title = Button Test +LayerInventory.Title = Player \ No newline at end of file diff --git a/src/main/resources/assets/languages/ru-RU.lang b/src/main/resources/assets/languages/ru-RU.lang index 97935d6..f18bd71 100644 --- a/src/main/resources/assets/languages/ru-RU.lang +++ b/src/main/resources/assets/languages/ru-RU.lang @@ -21,4 +21,5 @@ LayerTestGUI.PlacementModeHint = (Блок %s плитки: Ctrl + прокру LayerTestGUI.IsFullscreen = Полный экран: %5s (F11) LayerTestGUI.IsVSync = Верт. синхр.: %5s (F12) -LayerButtonTest.Title = Тест Кнопок \ No newline at end of file +LayerButtonTest.Title = Тест Кнопок +LayerInventory.Title = Игрок \ No newline at end of file