Compare commits
23 Commits
Author | SHA1 | Date | |
---|---|---|---|
38021852d0 | |||
9c85164ed1 | |||
ce573b51ce | |||
a028f6f3c7 | |||
9b67897896 | |||
3641c4130b | |||
be6203719a | |||
9885a1ca42 | |||
c6e6dc6851 | |||
30464febf6 | |||
782b3ef553 | |||
05b1c73fbc | |||
|
bd6442318d | ||
6cd812f7c3 | |||
73ee339dcc | |||
4749be6c60 | |||
a4b731e8a5 | |||
e7d0e8fe40 | |||
040a4f7fd7 | |||
b3ac7b6afe | |||
2fe84dc59e | |||
00ea4a6281 | |||
f186fc602d |
@ -18,22 +18,43 @@
|
|||||||
|
|
||||||
package ru.windcorp.progressia.client;
|
package ru.windcorp.progressia.client;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.EventBus;
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
|
||||||
import ru.windcorp.progressia.client.comms.DefaultClientCommsListener;
|
import ru.windcorp.progressia.client.comms.DefaultClientCommsListener;
|
||||||
import ru.windcorp.progressia.client.comms.ServerCommsChannel;
|
import ru.windcorp.progressia.client.comms.ServerCommsChannel;
|
||||||
|
import ru.windcorp.progressia.client.events.ClientEvent;
|
||||||
|
import ru.windcorp.progressia.client.events.NewLocalEntityEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.GUI;
|
||||||
import ru.windcorp.progressia.client.graphics.world.Camera;
|
import ru.windcorp.progressia.client.graphics.world.Camera;
|
||||||
import ru.windcorp.progressia.client.graphics.world.EntityAnchor;
|
import ru.windcorp.progressia.client.graphics.world.EntityAnchor;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.LayerWorld;
|
||||||
import ru.windcorp.progressia.client.graphics.world.LocalPlayer;
|
import ru.windcorp.progressia.client.graphics.world.LocalPlayer;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.HUDManager;
|
||||||
import ru.windcorp.progressia.client.world.WorldRender;
|
import ru.windcorp.progressia.client.world.WorldRender;
|
||||||
|
import ru.windcorp.progressia.common.util.crash.ReportingEventBus;
|
||||||
import ru.windcorp.progressia.common.world.DefaultWorldData;
|
import ru.windcorp.progressia.common.world.DefaultWorldData;
|
||||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
import ru.windcorp.progressia.test.LayerAbout;
|
||||||
|
import ru.windcorp.progressia.test.LayerDebug;
|
||||||
|
import ru.windcorp.progressia.test.LayerTestUI;
|
||||||
|
|
||||||
public class Client {
|
public class Client {
|
||||||
|
|
||||||
private final WorldRender world;
|
private final WorldRender world;
|
||||||
|
|
||||||
|
private final LayerWorld layerWorld = new LayerWorld(this);
|
||||||
|
private final LayerTestUI layerTestUI = new LayerTestUI();
|
||||||
|
private final LayerAbout layerAbout = new LayerAbout();
|
||||||
|
private final LayerDebug layerDebug = new LayerDebug();
|
||||||
|
|
||||||
private final LocalPlayer localPlayer = new LocalPlayer(this);
|
private final LocalPlayer localPlayer = new LocalPlayer(this);
|
||||||
|
|
||||||
private final Camera camera = new Camera((float) Math.toRadians(70));
|
private final Camera camera = new Camera((float) Math.toRadians(70));
|
||||||
|
|
||||||
|
private final EventBus eventBus = ReportingEventBus.create("ClientEvents");
|
||||||
|
|
||||||
|
private final HUDManager hudManager = new HUDManager(this);
|
||||||
|
|
||||||
private final ServerCommsChannel comms;
|
private final ServerCommsChannel comms;
|
||||||
|
|
||||||
public Client(DefaultWorldData world, ServerCommsChannel comms) {
|
public Client(DefaultWorldData world, ServerCommsChannel comms) {
|
||||||
@ -41,6 +62,22 @@ public class Client {
|
|||||||
this.comms = comms;
|
this.comms = comms;
|
||||||
|
|
||||||
comms.addListener(new DefaultClientCommsListener(this));
|
comms.addListener(new DefaultClientCommsListener(this));
|
||||||
|
subscribe(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void install() {
|
||||||
|
GUI.addBottomLayer(layerWorld);
|
||||||
|
GUI.addTopLayer(layerTestUI);
|
||||||
|
hudManager.install();
|
||||||
|
GUI.addTopLayer(layerAbout);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove() {
|
||||||
|
GUI.removeLayer(layerWorld);
|
||||||
|
GUI.removeLayer(layerTestUI);
|
||||||
|
hudManager.remove();
|
||||||
|
GUI.removeLayer(layerAbout);
|
||||||
|
GUI.removeLayer(layerDebug);
|
||||||
}
|
}
|
||||||
|
|
||||||
public WorldRender getWorld() {
|
public WorldRender getWorld() {
|
||||||
@ -63,17 +100,44 @@ public class Client {
|
|||||||
return comms;
|
return comms;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onLocalPlayerEntityChanged(EntityData entity, EntityData lastKnownEntity) {
|
public HUDManager getHUD() {
|
||||||
if (entity == null) {
|
return hudManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toggleDebugLayer() {
|
||||||
|
if (GUI.getLayers().contains(layerDebug)) {
|
||||||
|
GUI.removeLayer(layerDebug);
|
||||||
|
} else {
|
||||||
|
GUI.addTopLayer(layerDebug);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
private void onLocalPlayerEntityChanged(NewLocalEntityEvent e) {
|
||||||
|
if (e.getNewEntity() == null) {
|
||||||
getCamera().setAnchor(null);
|
getCamera().setAnchor(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
getCamera().setAnchor(
|
getCamera().setAnchor(
|
||||||
new EntityAnchor(
|
new EntityAnchor(
|
||||||
getWorld().getEntityRenderable(entity)
|
getWorld().getEntityRenderable(e.getNewEntity())
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void subscribe(Object object) {
|
||||||
|
eventBus.register(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unsubscribe(Object object) {
|
||||||
|
eventBus.unregister(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postEvent(ClientEvent event) {
|
||||||
|
event.setClient(this);
|
||||||
|
eventBus.post(event);
|
||||||
|
event.setClient(null);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import ru.windcorp.progressia.client.graphics.font.GNUUnifontLoader;
|
|||||||
import ru.windcorp.progressia.client.graphics.font.Typefaces;
|
import ru.windcorp.progressia.client.graphics.font.Typefaces;
|
||||||
import ru.windcorp.progressia.client.graphics.texture.Atlases;
|
import ru.windcorp.progressia.client.graphics.texture.Atlases;
|
||||||
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
|
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.HUDTextures;
|
||||||
import ru.windcorp.progressia.client.localization.Localizer;
|
import ru.windcorp.progressia.client.localization.Localizer;
|
||||||
import ru.windcorp.progressia.common.resource.ResourceManager;
|
import ru.windcorp.progressia.common.resource.ResourceManager;
|
||||||
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||||
@ -47,6 +48,7 @@ public class ClientProxy implements Proxy {
|
|||||||
() -> Typefaces
|
() -> Typefaces
|
||||||
.setDefault(GNUUnifontLoader.load(ResourceManager.getResource("assets/unifont-13.0.03.hex.gz")))
|
.setDefault(GNUUnifontLoader.load(ResourceManager.getResource("assets/unifont-13.0.03.hex.gz")))
|
||||||
);
|
);
|
||||||
|
RenderTaskQueue.waitAndInvoke(HUDTextures::loadItemAmountTypeface);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
throw CrashReports.report(e, "ClientProxy failed");
|
throw CrashReports.report(e, "ClientProxy failed");
|
||||||
}
|
}
|
||||||
|
@ -20,14 +20,10 @@ package ru.windcorp.progressia.client;
|
|||||||
|
|
||||||
import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel;
|
import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel;
|
||||||
import ru.windcorp.progressia.client.graphics.GUI;
|
import ru.windcorp.progressia.client.graphics.GUI;
|
||||||
import ru.windcorp.progressia.client.graphics.Layer;
|
|
||||||
import ru.windcorp.progressia.client.graphics.world.LayerWorld;
|
|
||||||
import ru.windcorp.progressia.common.world.DefaultWorldData;
|
import ru.windcorp.progressia.common.world.DefaultWorldData;
|
||||||
import ru.windcorp.progressia.client.localization.MutableStringLocalized;
|
import ru.windcorp.progressia.client.localization.MutableStringLocalized;
|
||||||
import ru.windcorp.progressia.server.ServerState;
|
import ru.windcorp.progressia.server.ServerState;
|
||||||
import ru.windcorp.progressia.test.LayerAbout;
|
|
||||||
import ru.windcorp.progressia.test.LayerTestText;
|
import ru.windcorp.progressia.test.LayerTestText;
|
||||||
import ru.windcorp.progressia.test.LayerTestUI;
|
|
||||||
import ru.windcorp.progressia.test.TestContent;
|
import ru.windcorp.progressia.test.TestContent;
|
||||||
|
|
||||||
public class ClientState {
|
public class ClientState {
|
||||||
@ -70,24 +66,14 @@ public class ClientState {
|
|||||||
|
|
||||||
if (client != null && client.getLocalPlayer().hasEntity()) {
|
if (client != null && client.getLocalPlayer().hasEntity()) {
|
||||||
GUI.removeLayer(layer);
|
GUI.removeLayer(layer);
|
||||||
|
client.install();
|
||||||
// TODO refactor, this shouldn't be here
|
|
||||||
LayerWorld layerWorld = new LayerWorld(client);
|
|
||||||
LayerTestUI layerUI = new LayerTestUI();
|
|
||||||
LayerAbout layerAbout = new LayerAbout();
|
|
||||||
GUI.addBottomLayer(layerWorld);
|
|
||||||
GUI.addTopLayer(layerUI);
|
|
||||||
GUI.addTopLayer(layerAbout);
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void disconnectFromLocalServer() {
|
public static void disconnectFromLocalServer() {
|
||||||
getInstance().getComms().disconnect();
|
getInstance().getComms().disconnect();
|
||||||
|
getInstance().remove();
|
||||||
for (Layer layer : GUI.getLayers()) {
|
|
||||||
GUI.removeLayer(layer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClientState() {
|
private ClientState() {
|
||||||
|
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.events;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.Client;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for all events issued by a {@link Client}.
|
||||||
|
*/
|
||||||
|
public interface ClientEvent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the client instance that this event happened on.
|
||||||
|
*
|
||||||
|
* @return the client
|
||||||
|
*/
|
||||||
|
Client getClient();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the client instance that the event is posted on. The value provided
|
||||||
|
* to this method must be returned by subsequent calls to
|
||||||
|
* {@link #getClient()}. Do not call this method when handling the event.
|
||||||
|
*
|
||||||
|
* @param client the client dispatching the event or {@code null} to unbind
|
||||||
|
* any previously bound client
|
||||||
|
*/
|
||||||
|
void setClient(Client client);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A default implementation of {@link ClientEvent}. This is not necessarily
|
||||||
|
* extended by client events.
|
||||||
|
*/
|
||||||
|
public static abstract class Default implements ClientEvent {
|
||||||
|
|
||||||
|
private Client client;
|
||||||
|
|
||||||
|
public Default(Client client) {
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Client getClient() {
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setClient(Client client) {
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.events;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.Client;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
|
||||||
|
|
||||||
|
public interface NewLocalEntityEvent extends ClientEvent {
|
||||||
|
|
||||||
|
EntityDataPlayer getNewEntity();
|
||||||
|
EntityDataPlayer getPreviousEntity();
|
||||||
|
|
||||||
|
public class Immutable extends ClientEvent.Default implements NewLocalEntityEvent {
|
||||||
|
|
||||||
|
private final EntityDataPlayer newEntity;
|
||||||
|
private final EntityDataPlayer previousEntity;
|
||||||
|
|
||||||
|
public Immutable(Client client, EntityDataPlayer newEntity, EntityDataPlayer previousEntity) {
|
||||||
|
super(client);
|
||||||
|
this.newEntity = newEntity;
|
||||||
|
this.previousEntity = previousEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityDataPlayer getNewEntity() {
|
||||||
|
return newEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityDataPlayer getPreviousEntity() {
|
||||||
|
return previousEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -56,6 +56,25 @@ public class Colors {
|
|||||||
return color.mul(multiplier, multiplier, multiplier, 1, output);
|
return color.mul(multiplier, multiplier, multiplier, 1, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Vec4 mix(Vec4 zero, Vec4 one, float t, Vec4 output) {
|
||||||
|
if (output == null) {
|
||||||
|
output = new Vec4();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t <= 0) {
|
||||||
|
return output.set(zero);
|
||||||
|
} else if (t >= 1) {
|
||||||
|
return output.set(one);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output.set(
|
||||||
|
zero.x * (1 - t) + one.x * t,
|
||||||
|
zero.y * (1 - t) + one.y * t,
|
||||||
|
zero.z * (1 - t) + one.z * t,
|
||||||
|
zero.w * (1 - t) + one.w * t
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public static Vec4 toVector(int argb, Vec4 output) {
|
public static Vec4 toVector(int argb, Vec4 output) {
|
||||||
output.w = ((argb & 0xFF000000) >>> 24) / (float) 0xFF; // Alpha
|
output.w = ((argb & 0xFF000000) >>> 24) / (float) 0xFF; // Alpha
|
||||||
output.x = ((argb & 0x00FF0000) >>> 16) / (float) 0xFF; // Red
|
output.x = ((argb & 0x00FF0000) >>> 16) / (float) 0xFF; // Red
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.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));
|
||||||
|
|
||||||
|
float newDifference = value - target;
|
||||||
|
if (difference * newDifference < 0) {
|
||||||
|
// Whoops, we've overshot
|
||||||
|
value = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float updateForFrame(float target) {
|
||||||
|
return update(target, GraphicsInterface.getFrameLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -66,6 +66,12 @@ public class GUI {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void updateLayer(Layer layer) {
|
||||||
|
modify(layers -> {
|
||||||
|
// Do nothing
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private static void modify(LayerStackModification mod) {
|
private static void modify(LayerStackModification mod) {
|
||||||
MODIFICATION_QUEUE.add(mod);
|
MODIFICATION_QUEUE.add(mod);
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,8 @@ public class RenderTarget {
|
|||||||
assembleCurrentClipFromFaces();
|
assembleCurrentClipFromFaces();
|
||||||
|
|
||||||
float depth = this.depth--;
|
float depth = this.depth--;
|
||||||
Mat4 transform = new Mat4().translate(0, 0, depth).mul(getTransform());
|
final float kostyl = 1e-2f;
|
||||||
|
Mat4 transform = new Mat4().translate(0, 0, depth).scale(1, 1, kostyl).mul(getTransform());
|
||||||
assembled.add(new Clip(maskStack, transform, renderable));
|
assembled.add(new Clip(maskStack, transform, renderable));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,19 +33,22 @@ public class Font {
|
|||||||
private final float align;
|
private final float align;
|
||||||
private final Vec4 color;
|
private final Vec4 color;
|
||||||
|
|
||||||
public Font(Typeface typeface, int style, float align, Vec4 color) {
|
private final int scale;
|
||||||
|
|
||||||
|
public Font(Typeface typeface, int style, float align, Vec4 color, int scale) {
|
||||||
this.typeface = typeface;
|
this.typeface = typeface;
|
||||||
this.style = style;
|
this.style = style;
|
||||||
this.align = align;
|
this.align = align;
|
||||||
this.color = color;
|
this.color = color;
|
||||||
|
this.scale = scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Font(Typeface typeface, int style, float align, int color) {
|
public Font(Typeface typeface, int style, float align, int color, int scale) {
|
||||||
this(typeface, style, align, Colors.toVector(color));
|
this(typeface, style, align, Colors.toVector(color), scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Font(Typeface typeface) {
|
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() {
|
public Font() {
|
||||||
@ -68,30 +71,62 @@ public class Font {
|
|||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Renderable assemble(
|
public int getScale() {
|
||||||
CharSequence chars,
|
return scale;
|
||||||
float maxWidth
|
|
||||||
) {
|
|
||||||
return typeface.assembleStatic(chars, style, align, maxWidth, color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Renderable assembleDynamic(
|
private Renderable applyScale(Renderable unscaled) {
|
||||||
Supplier<CharSequence> supplier,
|
if (scale == 1) {
|
||||||
float maxWidth
|
return unscaled;
|
||||||
) {
|
}
|
||||||
return typeface.assembleDynamic(supplier, style, align, maxWidth, color);
|
|
||||||
|
return renderer -> {
|
||||||
|
renderer.pushTransform().scale(scale);
|
||||||
|
unscaled.render(renderer);
|
||||||
|
renderer.popTransform();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Renderable assemble(CharSequence chars, float maxWidth) {
|
||||||
|
return applyScale(typeface.assembleStatic(chars, style, align, maxWidth, color));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Renderable assembleDynamic(Supplier<CharSequence> 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<CharSequence> supplier) {
|
||||||
|
return assembleDynamic(supplier, Float.POSITIVE_INFINITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getWidth(CharSequence chars, float maxWidth) {
|
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) {
|
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) {
|
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) {
|
public boolean supports(char c) {
|
||||||
@ -106,7 +141,7 @@ public class Font {
|
|||||||
* @return the new font
|
* @return the new font
|
||||||
*/
|
*/
|
||||||
public Font withStyle(int style) {
|
public Font withStyle(int style) {
|
||||||
return new Font(getTypeface(), style, getAlign(), getColor());
|
return new Font(getTypeface(), style, getAlign(), getColor(), getScale());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Font deriveBold() {
|
public Font deriveBold() {
|
||||||
@ -158,15 +193,19 @@ public class Font {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Font withAlign(float align) {
|
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) {
|
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) {
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,9 @@ public abstract class BasicButton extends Component {
|
|||||||
this.label = label;
|
this.label = label;
|
||||||
|
|
||||||
setLayout(new LayoutAlign(10));
|
setLayout(new LayoutAlign(10));
|
||||||
|
if (label != null) {
|
||||||
addChild(this.label);
|
addChild(this.label);
|
||||||
|
}
|
||||||
|
|
||||||
setFocusable(true);
|
setFocusable(true);
|
||||||
reassembleAt(ARTrigger.HOVER, ARTrigger.FOCUS, ARTrigger.ENABLE);
|
reassembleAt(ARTrigger.HOVER, ARTrigger.FOCUS, ARTrigger.ENABLE);
|
||||||
@ -152,4 +154,8 @@ public abstract class BasicButton extends Component {
|
|||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasLabel() {
|
||||||
|
return label != null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,9 @@ import ru.windcorp.progressia.client.graphics.Colors;
|
|||||||
|
|
||||||
public class Button extends BasicButton {
|
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) {
|
public Button(String name, String label, Font labelFont) {
|
||||||
super(name, label, labelFont);
|
super(name, label, labelFont);
|
||||||
}
|
}
|
||||||
@ -60,17 +63,25 @@ public class Button extends BasicButton {
|
|||||||
} else {
|
} else {
|
||||||
backgroundColor = Colors.WHITE;
|
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
|
// Change label font color
|
||||||
|
|
||||||
|
if (hasLabel()) {
|
||||||
if (isPressed()) {
|
if (isPressed()) {
|
||||||
getLabel().setFont(getLabel().getFont().withColor(Colors.WHITE));
|
getLabel().setFont(getLabel().getFont().withColor(Colors.WHITE));
|
||||||
} else {
|
} else {
|
||||||
getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK));
|
getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void postAssembleSelf(RenderTarget target) {
|
protected void postAssembleSelf(RenderTarget target) {
|
||||||
|
@ -30,7 +30,9 @@ import com.google.common.eventbus.Subscribe;
|
|||||||
|
|
||||||
import glm.vec._2.i.Vec2i;
|
import glm.vec._2.i.Vec2i;
|
||||||
import ru.windcorp.progressia.client.graphics.backend.InputTracker;
|
import ru.windcorp.progressia.client.graphics.backend.InputTracker;
|
||||||
|
import ru.windcorp.progressia.client.graphics.flat.AssembledFlatRenderHelper;
|
||||||
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||||
|
import ru.windcorp.progressia.client.graphics.flat.RenderTarget.Clip;
|
||||||
import ru.windcorp.progressia.client.graphics.gui.event.ChildAddedEvent;
|
import ru.windcorp.progressia.client.graphics.gui.event.ChildAddedEvent;
|
||||||
import ru.windcorp.progressia.client.graphics.gui.event.ChildRemovedEvent;
|
import ru.windcorp.progressia.client.graphics.gui.event.ChildRemovedEvent;
|
||||||
import ru.windcorp.progressia.client.graphics.gui.event.EnableEvent;
|
import ru.windcorp.progressia.client.graphics.gui.event.EnableEvent;
|
||||||
@ -43,6 +45,7 @@ import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
|||||||
import ru.windcorp.progressia.client.graphics.input.KeyMatcher;
|
import ru.windcorp.progressia.client.graphics.input.KeyMatcher;
|
||||||
import ru.windcorp.progressia.client.graphics.input.bus.InputBus;
|
import ru.windcorp.progressia.client.graphics.input.bus.InputBus;
|
||||||
import ru.windcorp.progressia.client.graphics.input.bus.InputListener;
|
import ru.windcorp.progressia.client.graphics.input.bus.InputListener;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||||
import ru.windcorp.progressia.common.util.Named;
|
import ru.windcorp.progressia.common.util.Named;
|
||||||
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||||
import ru.windcorp.progressia.common.util.crash.ReportingEventBus;
|
import ru.windcorp.progressia.common.util.crash.ReportingEventBus;
|
||||||
@ -557,10 +560,8 @@ public class Component extends Named {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void removeInputListener(InputListener<?> listener) {
|
public void removeInputListener(InputListener<?> listener) {
|
||||||
if (inputBus != null) {
|
|
||||||
inputBus.unregister(listener);
|
inputBus.unregister(listener);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean passInputToChildren(InputEvent e) {
|
protected boolean passInputToChildren(InputEvent e) {
|
||||||
return true;
|
return true;
|
||||||
@ -762,6 +763,20 @@ public class Component extends Named {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Renderable assembleToRenderable() {
|
||||||
|
|
||||||
|
RenderTarget target = new RenderTarget();
|
||||||
|
assemble(target);
|
||||||
|
Clip[] clips = target.assemble();
|
||||||
|
|
||||||
|
return renderer -> {
|
||||||
|
for (Clip clip : clips) {
|
||||||
|
clip.render((AssembledFlatRenderHelper) renderer);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
// * Returns a component that displays this component in its center.
|
// * Returns a component that displays this component in its center.
|
||||||
// * @return a {@link Aligner} initialized to center this component
|
// * @return a {@link Aligner} initialized to center this component
|
||||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.gui;
|
||||||
|
|
||||||
|
import java.util.function.BooleanSupplier;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
|
||||||
|
|
||||||
|
public class Components {
|
||||||
|
|
||||||
|
public static Component center(Component c) {
|
||||||
|
return new Group(c.getName() + ".Centerer", new LayoutAlign(), c);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Component hide(Component c, BooleanSupplier shouldHide) {
|
||||||
|
return new Hider(c.getName() + ".Hider", c, shouldHide);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Components() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -33,7 +33,7 @@ public class DynamicLabel extends Component {
|
|||||||
super(name);
|
super(name);
|
||||||
this.font = font;
|
this.font = font;
|
||||||
this.contents = contents;
|
this.contents = contents;
|
||||||
setPreferredSize(width, font.getHeight("", Float.POSITIVE_INFINITY) * 2);
|
setPreferredSize(width, font.getHeight("", Float.POSITIVE_INFINITY));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Font getFont() {
|
public Font getFont() {
|
||||||
@ -46,7 +46,7 @@ public class DynamicLabel extends Component {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void assembleSelf(RenderTarget target) {
|
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.addCustomRenderer(font.assembleDynamic(getContentSupplier(), Float.POSITIVE_INFINITY));
|
||||||
target.popTransform();
|
target.popTransform();
|
||||||
}
|
}
|
||||||
|
@ -25,4 +25,12 @@ public class Group extends Component {
|
|||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Group(String name, Layout layout, Component... children) {
|
||||||
|
this(name, layout);
|
||||||
|
|
||||||
|
for (Component child : children) {
|
||||||
|
addChild(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.gui;
|
||||||
|
|
||||||
|
import java.util.function.BooleanSupplier;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutFill;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||||
|
|
||||||
|
public class Hider extends Component {
|
||||||
|
|
||||||
|
private final BooleanSupplier shouldHide;
|
||||||
|
private final Component contents;
|
||||||
|
|
||||||
|
public Hider(String name, Component contents, BooleanSupplier shouldHide) {
|
||||||
|
super(name);
|
||||||
|
this.contents = contents;
|
||||||
|
this.shouldHide = shouldHide;
|
||||||
|
|
||||||
|
setLayout(new LayoutFill());
|
||||||
|
addChild(contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean passInputToChildren(InputEvent e) {
|
||||||
|
return !shouldHide.getAsBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized Component findFocused() {
|
||||||
|
if (shouldHide.getAsBoolean()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.findFocused();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void assembleChildren(RenderTarget target) {
|
||||||
|
Renderable renderable = contents.assembleToRenderable();
|
||||||
|
target.addCustomRenderer(renderer -> {
|
||||||
|
if (!shouldHide.getAsBoolean()) {
|
||||||
|
renderable.render(renderer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -70,7 +70,7 @@ public class Label extends Component {
|
|||||||
|
|
||||||
public void update() {
|
public void update() {
|
||||||
currentText = contents.get();
|
currentText = contents.get();
|
||||||
currentSize = font.getSize(currentText, maxWidth, null).mul(2);
|
currentSize = font.getSize(currentText, maxWidth, null);
|
||||||
requestReassembly();
|
requestReassembly();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,12 +99,8 @@ public class Label extends Component {
|
|||||||
protected void assembleSelf(RenderTarget target) {
|
protected void assembleSelf(RenderTarget target) {
|
||||||
float startX = getX() + font.getAlign() * (getWidth() - currentSize.x);
|
float startX = getX() + font.getAlign() * (getWidth() - currentSize.x);
|
||||||
|
|
||||||
target.pushTransform(
|
target.pushTransform(new Mat4().identity().translate(startX, getY(), 0));
|
||||||
new Mat4().identity().translate(startX, getY(), 0).scale(2)
|
|
||||||
);
|
|
||||||
|
|
||||||
target.addCustomRenderer(font.assemble(currentText, maxWidth));
|
target.addCustomRenderer(font.assemble(currentText, maxWidth));
|
||||||
|
|
||||||
target.popTransform();
|
target.popTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,6 +126,36 @@ public class Shapes {
|
|||||||
return result;
|
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 {
|
public static class PppBuilder {
|
||||||
|
|
||||||
private final ShapeRenderProgram program;
|
private final ShapeRenderProgram program;
|
||||||
@ -315,4 +345,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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,17 +18,22 @@
|
|||||||
|
|
||||||
package ru.windcorp.progressia.client.graphics.world;
|
package ru.windcorp.progressia.client.graphics.world;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
|
||||||
import ru.windcorp.progressia.client.Client;
|
import ru.windcorp.progressia.client.Client;
|
||||||
|
import ru.windcorp.progressia.client.events.ClientEvent;
|
||||||
|
import ru.windcorp.progressia.client.events.NewLocalEntityEvent;
|
||||||
import ru.windcorp.progressia.client.world.WorldRender;
|
import ru.windcorp.progressia.client.world.WorldRender;
|
||||||
import ru.windcorp.progressia.client.world.entity.EntityRenderable;
|
import ru.windcorp.progressia.client.world.entity.EntityRenderable;
|
||||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
|
||||||
|
|
||||||
public class LocalPlayer {
|
public class LocalPlayer {
|
||||||
|
|
||||||
private final Client client;
|
private final Client client;
|
||||||
|
|
||||||
private long entityId = EntityData.NULL_ENTITY_ID;
|
private long entityId = EntityData.NULL_ENTITY_ID;
|
||||||
private EntityData lastKnownEntity = null;
|
private EntityDataPlayer lastKnownEntity = null;
|
||||||
|
|
||||||
private final Selection selection = new Selection();
|
private final Selection selection = new Selection();
|
||||||
|
|
||||||
@ -59,19 +64,32 @@ public class LocalPlayer {
|
|||||||
return getEntity() != null;
|
return getEntity() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityData getEntity() {
|
public EntityDataPlayer getEntity() {
|
||||||
if (!hasEntityId()) {
|
if (!hasEntityId()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityData entity = getClient().getWorld().getData().getEntity(getEntityId());
|
EntityData entity = getClient().getWorld().getData().getEntity(getEntityId());
|
||||||
|
EntityDataPlayer playerEntity;
|
||||||
|
|
||||||
if (entity != lastKnownEntity) {
|
if (entity == null || entity instanceof EntityDataPlayer) {
|
||||||
getClient().onLocalPlayerEntityChanged(entity, lastKnownEntity);
|
playerEntity = (EntityDataPlayer) entity;
|
||||||
this.lastKnownEntity = 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) {
|
||||||
|
ClientEvent event = new NewLocalEntityEvent.Immutable(getClient(), playerEntity, lastKnownEntity);
|
||||||
|
this.lastKnownEntity = playerEntity;
|
||||||
|
getClient().postEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return playerEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Selection getSelection() {
|
public Selection getSelection() {
|
||||||
|
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import glm.vec._3.Vec3;
|
||||||
|
import glm.vec._4.Vec4;
|
||||||
|
import ru.windcorp.jputil.functions.FloatSupplier;
|
||||||
|
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.gui.Component;
|
||||||
|
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;
|
||||||
|
|
||||||
|
public class Bar extends Component {
|
||||||
|
|
||||||
|
private static final int THICKNESS = 5;
|
||||||
|
|
||||||
|
private final boolean isVertical;
|
||||||
|
|
||||||
|
private final FloatSupplier value;
|
||||||
|
private final FloatSupplier maxValue;
|
||||||
|
|
||||||
|
private final Vec4 color;
|
||||||
|
private final Vec4 backgroundColor;
|
||||||
|
|
||||||
|
private static Renderable unitSquare = null;
|
||||||
|
|
||||||
|
public Bar(String name, boolean isVertical, Vec4 color, FloatSupplier value, FloatSupplier maxValue) {
|
||||||
|
super(name);
|
||||||
|
this.isVertical = isVertical;
|
||||||
|
this.value = value;
|
||||||
|
this.maxValue = maxValue;
|
||||||
|
|
||||||
|
this.color = color;
|
||||||
|
this.backgroundColor = Colors.mix(color, Colors.WHITE, 0.75f, null);
|
||||||
|
|
||||||
|
if (unitSquare == null) {
|
||||||
|
unitSquare = new Shape(
|
||||||
|
Usage.STATIC,
|
||||||
|
FlatRenderProgram.getDefault(),
|
||||||
|
ShapeParts.createRectangle(
|
||||||
|
FlatRenderProgram.getDefault(),
|
||||||
|
null,
|
||||||
|
Colors.WHITE,
|
||||||
|
new Vec3(0, 0, 0),
|
||||||
|
new Vec3(1, 0, 0),
|
||||||
|
new Vec3(0, 1, 0),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
setPreferredSize(THICKNESS, THICKNESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void assembleSelf(RenderTarget target) {
|
||||||
|
target.addCustomRenderer(this::renderSelf);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderSelf(ShapeRenderHelper renderer) {
|
||||||
|
renderer.pushTransform()
|
||||||
|
.translate(getX(), getY(), 0)
|
||||||
|
.scale(getWidth(), getHeight(), 1);
|
||||||
|
|
||||||
|
float length = value.getAsFloat() / maxValue.getAsFloat();
|
||||||
|
if (length < 0) {
|
||||||
|
length = 0;
|
||||||
|
} else if (length > 1) {
|
||||||
|
length = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO why is the order reverse????
|
||||||
|
renderRectangle(renderer, color, length);
|
||||||
|
renderRectangle(renderer, backgroundColor, 1);
|
||||||
|
|
||||||
|
renderer.popTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderRectangle(ShapeRenderHelper renderer, Vec4 color, float length) {
|
||||||
|
renderer.pushColorMultiplier().mul(color);
|
||||||
|
if (length != 1) {
|
||||||
|
renderer.pushTransform().scale(isVertical ? 1 : length, isVertical ? length : 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
unitSquare.render(renderer);
|
||||||
|
|
||||||
|
if (length != 1) {
|
||||||
|
renderer.popTransform();
|
||||||
|
}
|
||||||
|
renderer.popColorMultiplier();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import glm.vec._2.i.Vec2i;
|
||||||
|
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.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.inventory.ItemContainerHand;
|
||||||
|
|
||||||
|
public class CursorHUD extends Component {
|
||||||
|
|
||||||
|
private class CursorBoundSlot {
|
||||||
|
|
||||||
|
private final SlotComponent component;
|
||||||
|
private final Renderable renderable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 0 is not selected, 1 is selected
|
||||||
|
*/
|
||||||
|
private final ExponentAnimation selection = new ExponentAnimation(10, 0);
|
||||||
|
private final double angle;
|
||||||
|
|
||||||
|
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 = CursorHUD.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();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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 CursorHUD(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) {
|
||||||
|
|
||||||
|
target.addCustomRenderer(renderer -> {
|
||||||
|
|
||||||
|
renderer.pushTransform().translate(
|
||||||
|
(float) InputTracker.getCursorX(),
|
||||||
|
(float) InputTracker.getCursorY(),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
for (CursorBoundSlot slot : slots) {
|
||||||
|
slot.render(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.popTransform();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.Client;
|
||||||
|
import ru.windcorp.progressia.client.events.NewLocalEntityEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.GUI;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.client.world.item.inventory.InventoryComponent;
|
||||||
|
import ru.windcorp.progressia.client.world.item.inventory.InventoryRender;
|
||||||
|
import ru.windcorp.progressia.client.world.item.inventory.InventoryRenderRegistry;
|
||||||
|
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.Inventory;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.event.InventoryClosingEvent;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.event.InventoryOpenedEvent;
|
||||||
|
|
||||||
|
public class HUDManager implements HUDWorkspace {
|
||||||
|
|
||||||
|
private final Client client;
|
||||||
|
private final LayerHUD layer;
|
||||||
|
|
||||||
|
public HUDManager(Client client) {
|
||||||
|
this.client = client;
|
||||||
|
this.layer = new LayerHUD(this);
|
||||||
|
client.subscribe(new Object() {
|
||||||
|
@Subscribe
|
||||||
|
public void onLocalEntityChanged(NewLocalEntityEvent e) {
|
||||||
|
if (e.getNewEntity() != null) {
|
||||||
|
e.getNewEntity().subscribe(HUDManager.this);
|
||||||
|
}
|
||||||
|
if (e.getPreviousEntity() != null) {
|
||||||
|
e.getPreviousEntity().unsubscribe(HUDManager.this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void install() {
|
||||||
|
GUI.addTopLayer(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove() {
|
||||||
|
GUI.removeLayer(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void openInventory(InventoryComponent component) {
|
||||||
|
InventoryWindow window = new InventoryWindow("Window", component, this);
|
||||||
|
layer.getWindowManager().addWindow(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeEverything() {
|
||||||
|
System.err.println("closeEverything NYI");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHidden() {
|
||||||
|
return layer.isHidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHidden(boolean hide) {
|
||||||
|
layer.setHidden(hide);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInventoryShown() {
|
||||||
|
return layer.isInventoryShown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInventoryShown(boolean showInventory) {
|
||||||
|
layer.setInventoryShown(showInventory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Client getClient() {
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
private void onInventoryOpened(InventoryOpenedEvent event) {
|
||||||
|
Inventory inventory = event.getInventory();
|
||||||
|
InventoryRender render = InventoryRenderRegistry.getInstance().get(inventory.getId());
|
||||||
|
|
||||||
|
if (render == null) {
|
||||||
|
throw CrashReports.report(null, "InventoryRender not found for ID %s", inventory.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
InventoryComponent component = render.createComponent(inventory, this);
|
||||||
|
openInventory(component);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw CrashReports.report(e, "Could not open inventory %s", inventory.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
private void onInventoryClosing(InventoryClosingEvent event) {
|
||||||
|
Inventory inventory = event.getInventory();
|
||||||
|
|
||||||
|
for (Component component : layer.getWindowManager().getChildren()) {
|
||||||
|
if (component instanceof InventoryWindow) {
|
||||||
|
InventoryWindow window = (InventoryWindow) component;
|
||||||
|
if (window.getContent().getInventory() == inventory) {
|
||||||
|
layer.getWindowManager().closeWindow(window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
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.crash.CrashReports;
|
||||||
|
|
||||||
|
public class HUDTextures {
|
||||||
|
|
||||||
|
private static final AtlasGroup HUD_ATLAS_GROUP = new AtlasGroup("HUD", 1 << 12);
|
||||||
|
|
||||||
|
private static ItemAmountTypeface itemAmountTypeface = null;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ItemAmountTypeface getItemAmountTypeface() {
|
||||||
|
return itemAmountTypeface;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void loadItemAmountTypeface() {
|
||||||
|
try {
|
||||||
|
itemAmountTypeface = new ItemAmountTypeface();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw CrashReports.report(e, "Could not load item amount typeface");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.Client;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.LocalPlayer;
|
||||||
|
import ru.windcorp.progressia.client.world.item.inventory.InventoryComponent;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainerHand;
|
||||||
|
|
||||||
|
public interface HUDWorkspace {
|
||||||
|
|
||||||
|
Client getClient();
|
||||||
|
|
||||||
|
default LocalPlayer getPlayer() {
|
||||||
|
return getClient().getLocalPlayer();
|
||||||
|
}
|
||||||
|
|
||||||
|
default EntityDataPlayer getPlayerEntity() {
|
||||||
|
return getClient().getLocalPlayer().getEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
default ItemContainerHand getHand() {
|
||||||
|
return getClient().getLocalPlayer().getEntity().getSelectedHand();
|
||||||
|
}
|
||||||
|
|
||||||
|
void openInventory(InventoryComponent component);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.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.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;
|
||||||
|
|
||||||
|
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 = manager.getHand() == 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 HUDManager manager;
|
||||||
|
|
||||||
|
public HandsHUD(String name, HUDManager manager) {
|
||||||
|
super(name);
|
||||||
|
this.manager = manager;
|
||||||
|
|
||||||
|
EntityDataPlayer entity = manager.getPlayerEntity();
|
||||||
|
String speciesId = entity.getSpecies().getId();
|
||||||
|
SpeciesRender speciesRender = SpeciesRenderRegistry.getInstance().get(speciesId);
|
||||||
|
|
||||||
|
Map<Side, Component> 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 manager.isInventoryShown();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import glm.vec._2.i.Vec2i;
|
||||||
|
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Button;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Label;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutFill;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.KeyMatcher;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.WheelScrollEvent;
|
||||||
|
import ru.windcorp.progressia.common.Units;
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemDataContainer;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainer;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemSlot;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.Items;
|
||||||
|
|
||||||
|
public class InteractiveSlotComponent extends Button {
|
||||||
|
|
||||||
|
private static final double MIN_PICK_ALL_DELAY = Units.get("0.5 s");
|
||||||
|
|
||||||
|
private double lastMainAction = Double.NEGATIVE_INFINITY;
|
||||||
|
|
||||||
|
private final SlotComponent slotComponent;
|
||||||
|
private final HUDWorkspace workspace;
|
||||||
|
|
||||||
|
public InteractiveSlotComponent(String name, ItemContainer container, int index, HUDWorkspace workspace) {
|
||||||
|
this(name, new SlotComponent(name, container, index), workspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InteractiveSlotComponent(SlotComponent component, HUDWorkspace workspace) {
|
||||||
|
this(component.getName() + ".Interactive", component, workspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InteractiveSlotComponent(String name, SlotComponent component, HUDWorkspace workspace) {
|
||||||
|
super(name, (Label) null);
|
||||||
|
this.slotComponent = component;
|
||||||
|
this.workspace = workspace;
|
||||||
|
|
||||||
|
Vec2i size = slotComponent.getPreferredSize().add(2 * BORDER);
|
||||||
|
setPreferredSize(size);
|
||||||
|
|
||||||
|
addChild(this.slotComponent);
|
||||||
|
setLayout(new LayoutFill(MARGIN));
|
||||||
|
|
||||||
|
addListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addListeners() {
|
||||||
|
addAction(button -> onMainAction());
|
||||||
|
|
||||||
|
addKeyListener(KeyMatcher.RMB, this::onAltAction);
|
||||||
|
|
||||||
|
addInputListener(WheelScrollEvent.class, event -> {
|
||||||
|
if (event.hasVerticalMovement()) {
|
||||||
|
onSingleMoveAction(event.isDown());
|
||||||
|
event.consume();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onMainAction() {
|
||||||
|
ItemSlot handSlot = workspace.getHand().slot();
|
||||||
|
ItemSlot invSlot = getSlot();
|
||||||
|
if (invSlot == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean success = false;
|
||||||
|
|
||||||
|
double now = GraphicsInterface.getTime();
|
||||||
|
if (now - lastMainAction < MIN_PICK_ALL_DELAY) {
|
||||||
|
lastMainAction = Double.NEGATIVE_INFINITY;
|
||||||
|
pickAll(handSlot);
|
||||||
|
success = true;
|
||||||
|
} else {
|
||||||
|
lastMainAction = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
success = Items.pour(handSlot, invSlot) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
success = Items.swap(handSlot, invSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success && handSlot.isEmpty()) {
|
||||||
|
success = Items.pour(invSlot, handSlot) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
requestReassembly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pickAll(ItemSlot handSlot) {
|
||||||
|
int maxIndex = getSlot().getContainer().getMaxIndex();
|
||||||
|
for (int index = 0; index < maxIndex; ++index) {
|
||||||
|
Items.pour(new ItemSlot(getSlot().getContainer(), index), handSlot);
|
||||||
|
if (handSlot.isEmpty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onAltAction(KeyEvent e) {
|
||||||
|
ItemSlot handSlot = workspace.getHand().slot();
|
||||||
|
ItemSlot invSlot = getSlot();
|
||||||
|
if (invSlot == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean success = false;
|
||||||
|
|
||||||
|
if (handSlot.isEmpty()) {
|
||||||
|
success = tryToOpen(invSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success && handSlot.isEmpty()) {
|
||||||
|
success = Items.pour(invSlot, handSlot, invSlot.getCount() / 2) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
success = Items.pour(handSlot, invSlot, 1) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
success = Items.swap(handSlot, invSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
requestReassembly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean tryToOpen(ItemSlot invSlot) {
|
||||||
|
if (invSlot.getCount() != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!(invSlot.getItem() instanceof ItemDataContainer)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemDataContainer item = (ItemDataContainer) invSlot.getItem();
|
||||||
|
return item.open(workspace.getPlayerEntity()) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onSingleMoveAction(boolean fromHand) {
|
||||||
|
ItemSlot handSlot = workspace.getHand().slot();
|
||||||
|
ItemSlot invSlot = getSlot();
|
||||||
|
|
||||||
|
ItemSlot from = fromHand ? handSlot : invSlot;
|
||||||
|
ItemSlot into = fromHand ? invSlot : handSlot;
|
||||||
|
|
||||||
|
if (Items.pour(from, into, 1) != 0) {
|
||||||
|
requestReassembly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemSlot getSlot() {
|
||||||
|
return slotComponent.getSlot();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
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.LayoutVertical;
|
||||||
|
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.EquipmentSlot;
|
||||||
|
|
||||||
|
public class InventoryHUD extends Component {
|
||||||
|
|
||||||
|
public enum Side {
|
||||||
|
LEFT("Left", LayoutBorderHorizontal.LEFT),
|
||||||
|
RIGHT("Right", LayoutBorderHorizontal.RIGHT);
|
||||||
|
|
||||||
|
private final String ccName;
|
||||||
|
private final Object lbhHint;
|
||||||
|
|
||||||
|
private Side(String ccName, Object lbhHint) {
|
||||||
|
this.ccName = ccName;
|
||||||
|
this.lbhHint = lbhHint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public InventoryHUD(String name, HUDWorkspace workspace) {
|
||||||
|
super(name);
|
||||||
|
setLayout(new LayoutBorderHorizontal());
|
||||||
|
|
||||||
|
EntityDataPlayer entity = workspace.getPlayerEntity();
|
||||||
|
String speciesId = entity.getSpecies().getId();
|
||||||
|
SpeciesRender speciesRender = SpeciesRenderRegistry.getInstance().get(speciesId);
|
||||||
|
|
||||||
|
Map<Side, Component> containers = Maps.toMap(
|
||||||
|
Arrays.asList(Side.values()),
|
||||||
|
side -> new Group(name + "." + side.ccName, new LayoutVertical(15))
|
||||||
|
);
|
||||||
|
|
||||||
|
for (int i = 0; i < entity.getEquipmentCount(); ++i) {
|
||||||
|
|
||||||
|
EquipmentSlot slot = entity.getSpecies().getEquipmentSlots().get(i);
|
||||||
|
|
||||||
|
SlotComponent display = new SlotComponent(name + "." + slot.getName(), entity.getEquipmentSlot(i), 0)
|
||||||
|
.setBackground(speciesRender.getEquipmentSlotBackground(slot))
|
||||||
|
.setScale(2);
|
||||||
|
|
||||||
|
InteractiveSlotComponent interactiveDisplay = new InteractiveSlotComponent(
|
||||||
|
display,
|
||||||
|
workspace
|
||||||
|
);
|
||||||
|
|
||||||
|
containers.get(speciesRender.getEquipmentSlotSide(slot)).addChild(interactiveDisplay);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
containers.forEach((side, comp) -> {
|
||||||
|
addChild(
|
||||||
|
new Group(name + "." + side.ccName + ".Aligner", new LayoutAlign(0, 1, 0), comp)
|
||||||
|
.setLayoutHint(side.lbhHint)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
|
||||||
|
import glm.vec._2.Vec2;
|
||||||
|
import glm.vec._4.Vec4;
|
||||||
|
import ru.windcorp.progressia.client.graphics.Colors;
|
||||||
|
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||||
|
import ru.windcorp.progressia.client.graphics.font.Font;
|
||||||
|
import ru.windcorp.progressia.client.graphics.font.Typeface;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Button;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.DragManager;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Group;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Label;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Panel;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.event.DragEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutBorderHorizontal;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutFill;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical;
|
||||||
|
import ru.windcorp.progressia.client.localization.MutableString;
|
||||||
|
import ru.windcorp.progressia.client.localization.MutableStringConcat;
|
||||||
|
import ru.windcorp.progressia.client.localization.MutableStringLocalized;
|
||||||
|
import ru.windcorp.progressia.client.world.item.inventory.InventoryComponent;
|
||||||
|
|
||||||
|
public class InventoryWindow extends Panel {
|
||||||
|
|
||||||
|
private static final String CLOSE_CHAR = "\u2715";
|
||||||
|
private static final String HANDLE_CHAR = "\u2800";
|
||||||
|
private static final Vec4 CLOSE_BUTTON_IDLE = Colors.toVector(0xFFBC1515);
|
||||||
|
private static final Vec4 CLOSE_BUTTON_HOVER = Colors.toVector(0xFFFA6464);
|
||||||
|
private static final Vec4 CLOSE_BUTTON_PRESSED = Colors.BLACK;
|
||||||
|
|
||||||
|
private final InventoryComponent content;
|
||||||
|
private final HUDWorkspace workspace;
|
||||||
|
|
||||||
|
private final Vec2 relativePosition = new Vec2(Float.NaN);
|
||||||
|
|
||||||
|
public InventoryWindow(String name, InventoryComponent component, HUDWorkspace workspace) {
|
||||||
|
super(name, new LayoutVertical(15, 15));
|
||||||
|
this.content = component;
|
||||||
|
this.workspace = workspace;
|
||||||
|
|
||||||
|
Group titleBar = new Group(getName() + ".TitleBar", new LayoutBorderHorizontal());
|
||||||
|
titleBar.addChild(createLabel(component).setLayoutHint(LayoutBorderHorizontal.CENTER));
|
||||||
|
titleBar.addChild(createCloseButton(component).setLayoutHint(LayoutBorderHorizontal.RIGHT));
|
||||||
|
|
||||||
|
new DragManager().install(titleBar);
|
||||||
|
titleBar.addListener(new Object() {
|
||||||
|
@Subscribe
|
||||||
|
public void onWindowDragged(DragEvent e) {
|
||||||
|
Vec2 change = new Vec2((float) e.getCurrentChangeX(), (float) e.getCurrentChangeY());
|
||||||
|
change.div(getParent().getWidth(), getParent().getHeight());
|
||||||
|
relativePosition.add(change);
|
||||||
|
requestReassembly();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
addChild(titleBar);
|
||||||
|
|
||||||
|
addChild(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Label createLabel(InventoryComponent component) {
|
||||||
|
String translationKey = "Inventory." + component.getInventory().getId() + ".Title";
|
||||||
|
MutableString titleText = new MutableStringConcat(
|
||||||
|
HANDLE_CHAR + " ",
|
||||||
|
new MutableStringLocalized(translationKey)
|
||||||
|
);
|
||||||
|
Font titleFont = new Font().deriveBold().withColor(Colors.BLACK).withAlign(Typeface.ALIGN_LEFT);
|
||||||
|
|
||||||
|
return new Label(getName() + ".Title", titleFont, titleText);
|
||||||
|
}
|
||||||
|
|
||||||
|
private WindowedHUD getManager() {
|
||||||
|
Component parent = getParent();
|
||||||
|
if (parent instanceof WindowedHUD) {
|
||||||
|
return (WindowedHUD) parent;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the relativePosition
|
||||||
|
*/
|
||||||
|
public Vec2 getRelativePosition() {
|
||||||
|
return relativePosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Component createCloseButton(InventoryComponent component) {
|
||||||
|
|
||||||
|
Button button = new Button(getName() + ".CloseButton", CLOSE_CHAR) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void assembleSelf(RenderTarget target) {
|
||||||
|
|
||||||
|
Vec4 color = CLOSE_BUTTON_IDLE;
|
||||||
|
if (isPressed()) {
|
||||||
|
color = CLOSE_BUTTON_PRESSED;
|
||||||
|
} else if (isHovered()) {
|
||||||
|
color = CLOSE_BUTTON_HOVER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasLabel()) {
|
||||||
|
getLabel().setFont(getLabel().getFont().withColor(color));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
button.addAction(b -> {
|
||||||
|
|
||||||
|
content.getInventory().close(workspace.getPlayerEntity());
|
||||||
|
|
||||||
|
WindowedHUD manager = getManager();
|
||||||
|
if (manager == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.closeWindow(this);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
button.setLayout(new LayoutFill());
|
||||||
|
|
||||||
|
int height = button.getLabel().getFont().getHeight(button.getLabel().getCurrentText());
|
||||||
|
button.setPreferredSize(height, height);
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InventoryComponent getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.flat.FlatRenderProgram;
|
||||||
|
import ru.windcorp.progressia.client.graphics.font.SpriteTypeface;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram;
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.ComplexTexture;
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.TextureLoader;
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.TexturePrimitive;
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.TextureSettings;
|
||||||
|
import ru.windcorp.progressia.common.resource.ResourceManager;
|
||||||
|
|
||||||
|
public class ItemAmountTypeface extends SpriteTypeface {
|
||||||
|
|
||||||
|
public static final int HEIGHT = 5;
|
||||||
|
public static final int WIDTH = 3;
|
||||||
|
|
||||||
|
private final Texture[] textures = new Texture[10];
|
||||||
|
|
||||||
|
public ItemAmountTypeface() throws IOException {
|
||||||
|
super("ItemAmount", HEIGHT, 1);
|
||||||
|
|
||||||
|
ComplexTexture atlas = new ComplexTexture(new TexturePrimitive(
|
||||||
|
TextureLoader.loadPixels(
|
||||||
|
ResourceManager.getTextureResource("gui/ItemAmountTypeface"),
|
||||||
|
new TextureSettings(false)
|
||||||
|
).getData()
|
||||||
|
), 30, 5);
|
||||||
|
|
||||||
|
for (int i = 0; i <= 9; ++i) {
|
||||||
|
textures[i] = atlas.get(i * WIDTH, 0, WIDTH, HEIGHT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Texture getTexture(char c) {
|
||||||
|
if (!supports(c))
|
||||||
|
return textures[0];
|
||||||
|
return textures[c - '0'];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ShapeRenderProgram getProgram() {
|
||||||
|
return FlatRenderProgram.getDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(char c) {
|
||||||
|
return c >= '0' && c <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.events.NewLocalEntityEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.GUI;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Components;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.GUILayer;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Group;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutFill;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.KeyMatcher;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.bus.InputBus;
|
||||||
|
import ru.windcorp.progressia.test.controls.TestPlayerControls;
|
||||||
|
|
||||||
|
public class LayerHUD extends GUILayer {
|
||||||
|
|
||||||
|
private final HUDManager manager;
|
||||||
|
private WindowedHUD windowManager = null;
|
||||||
|
|
||||||
|
private boolean showInventory = false;
|
||||||
|
private boolean isHidden = false;
|
||||||
|
|
||||||
|
public LayerHUD(HUDManager manager) {
|
||||||
|
super("LayerHUD", new LayoutFill(15));
|
||||||
|
this.manager = manager;
|
||||||
|
|
||||||
|
setCursorPolicy(CursorPolicy.INDIFFERENT);
|
||||||
|
|
||||||
|
manager.getClient().subscribe(this);
|
||||||
|
|
||||||
|
getRoot().addKeyListener(new KeyMatcher("Escape"), e -> {
|
||||||
|
setInventoryShown(!showInventory);
|
||||||
|
e.consume();
|
||||||
|
}, InputBus.Option.IGNORE_FOCUS);
|
||||||
|
|
||||||
|
getRoot().addKeyListener(new KeyMatcher("E"), e -> {
|
||||||
|
setInventoryShown(!showInventory);
|
||||||
|
e.consume();
|
||||||
|
}, InputBus.Option.IGNORE_FOCUS);
|
||||||
|
|
||||||
|
getRoot().addKeyListener(new KeyMatcher("Left Control"), e -> {
|
||||||
|
TestPlayerControls.getInstance().getInventoryControls().switchHandsWithCtrl(e);
|
||||||
|
e.consume();
|
||||||
|
}, InputBus.Option.IGNORE_ACTION, InputBus.Option.IGNORE_FOCUS);
|
||||||
|
|
||||||
|
getRoot().addKeyListener(new KeyMatcher("Right Control"), e -> {
|
||||||
|
TestPlayerControls.getInstance().getInventoryControls().switchHandsWithCtrl(e);
|
||||||
|
e.consume();
|
||||||
|
}, InputBus.Option.IGNORE_ACTION, InputBus.Option.IGNORE_FOCUS);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
private void onEntityChanged(NewLocalEntityEvent e) {
|
||||||
|
while (!getRoot().getChildren().isEmpty()) {
|
||||||
|
getRoot().removeChild(getRoot().getChild(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.getNewEntity() == null) {
|
||||||
|
getRoot().requestReassembly();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
getRoot().addChild(new PermanentHUD(getName() + ".Permanent", manager));
|
||||||
|
|
||||||
|
Component inventoryGroup = new Group(getName() + ".InventoryGroup", new LayoutFill());
|
||||||
|
|
||||||
|
inventoryGroup.addChild(new InventoryHUD(getName() + ".Equipment", manager));
|
||||||
|
|
||||||
|
windowManager = new WindowedHUD(getName() + ".Windows");
|
||||||
|
inventoryGroup.addChild(windowManager);
|
||||||
|
|
||||||
|
inventoryGroup.addChild(new CursorHUD(getName() + ".Cursor", manager.getPlayerEntity()));
|
||||||
|
|
||||||
|
getRoot().addChild(Components.hide(inventoryGroup, () -> !showInventory));
|
||||||
|
|
||||||
|
getRoot().requestReassembly();
|
||||||
|
}
|
||||||
|
|
||||||
|
public WindowedHUD getWindowManager() {
|
||||||
|
return windowManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInventoryShown() {
|
||||||
|
return showInventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInventoryShown(boolean showInventory) {
|
||||||
|
this.showInventory = showInventory;
|
||||||
|
updateCursorPolicy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHidden() {
|
||||||
|
return isHidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHidden(boolean isHidden) {
|
||||||
|
this.isHidden = isHidden;
|
||||||
|
updateCursorPolicy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateCursorPolicy() {
|
||||||
|
if (showInventory && !isHidden) {
|
||||||
|
setCursorPolicy(CursorPolicy.REQUIRE);
|
||||||
|
} else {
|
||||||
|
setCursorPolicy(CursorPolicy.INDIFFERENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
GUI.updateLayer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleInput(InputEvent event) {
|
||||||
|
if (isHidden) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.handleInput(event);
|
||||||
|
|
||||||
|
if (getCursorPolicy() == CursorPolicy.REQUIRE) {
|
||||||
|
event.consume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRender() {
|
||||||
|
if (isHidden) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.doRender();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutBorderVertical;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
|
||||||
|
|
||||||
|
public class PermanentHUD extends Component {
|
||||||
|
|
||||||
|
public PermanentHUD(String name, HUDManager manager) {
|
||||||
|
super(name);
|
||||||
|
setLayout(new LayoutBorderVertical());
|
||||||
|
|
||||||
|
EntityDataPlayer entity = manager.getPlayerEntity();
|
||||||
|
if (entity == null) {
|
||||||
|
throw new IllegalStateException("Player " + manager.getPlayer() + " does not have an associated entity");
|
||||||
|
}
|
||||||
|
|
||||||
|
addChild(new HandsHUD(name + ".Hands", manager).setLayoutHint(LayoutBorderVertical.UP));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,217 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import java.util.function.BooleanSupplier;
|
||||||
|
import glm.mat._4.Mat4;
|
||||||
|
import ru.windcorp.progressia.client.graphics.Colors;
|
||||||
|
import ru.windcorp.progressia.client.graphics.backend.InputTracker;
|
||||||
|
import ru.windcorp.progressia.client.graphics.flat.FlatRenderProgram;
|
||||||
|
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||||
|
import ru.windcorp.progressia.client.graphics.font.Font;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.DynamicLabel;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.Shapes.PgmBuilder;
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||||
|
import ru.windcorp.progressia.client.world.item.ItemRenderRegistry;
|
||||||
|
import ru.windcorp.progressia.client.world.item.ItemRenderable;
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemData;
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemDataContainer;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainer;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemSlot;
|
||||||
|
|
||||||
|
public class SlotComponent extends Component {
|
||||||
|
|
||||||
|
static final float TEXTURE_SIZE = 24;
|
||||||
|
|
||||||
|
private static boolean drawVirtualSlots;
|
||||||
|
static {
|
||||||
|
String key = SlotComponent.class.getName() + ".drawVirtualSlots";
|
||||||
|
drawVirtualSlots = Boolean.parseBoolean(System.getProperty(key, "true"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Renderable containerOpenDecoration = null;
|
||||||
|
private static Renderable containerOpenableDecoration = null;
|
||||||
|
|
||||||
|
private final ItemSlot slot;
|
||||||
|
|
||||||
|
private float scale = 2;
|
||||||
|
|
||||||
|
private ItemRenderable itemRenderer = null;
|
||||||
|
|
||||||
|
private int amountDisplayInt = 0;
|
||||||
|
private String amountDisplayString = "";
|
||||||
|
|
||||||
|
private Renderable background = null;
|
||||||
|
private BooleanSupplier backgroundCondition = null;
|
||||||
|
|
||||||
|
public SlotComponent(String name, ItemContainer container, int index) {
|
||||||
|
super(name);
|
||||||
|
this.slot = new ItemSlot(container, index);
|
||||||
|
|
||||||
|
setScale(2);
|
||||||
|
|
||||||
|
Font sizeFont = new Font(HUDTextures.getItemAmountTypeface()).deriveOutlined().withScale(2);
|
||||||
|
addChild(new DynamicLabel(getName() + ".Size", sizeFont, () -> amountDisplayString, getPreferredSize().x));
|
||||||
|
|
||||||
|
setLayout(new LayoutAlign(0, 0, 0));
|
||||||
|
|
||||||
|
if (containerOpenDecoration == null) {
|
||||||
|
containerOpenDecoration = new PgmBuilder(
|
||||||
|
FlatRenderProgram.getDefault(),
|
||||||
|
HUDTextures.getHUDTexture("DecorationContainerOpen")
|
||||||
|
).setSize(TEXTURE_SIZE + 2).setOrigin(-1, -1, 0).create();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (containerOpenableDecoration == null) {
|
||||||
|
containerOpenableDecoration = new PgmBuilder(
|
||||||
|
FlatRenderProgram.getDefault(),
|
||||||
|
HUDTextures.getHUDTexture("DecorationContainerOpenable")
|
||||||
|
).setSize(TEXTURE_SIZE + 2).setOrigin(-1, -1, 0).create();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the container
|
||||||
|
*/
|
||||||
|
public ItemContainer getSlotContainer() {
|
||||||
|
return slot.getContainer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the index
|
||||||
|
*/
|
||||||
|
public int getSlotIndex() {
|
||||||
|
return slot.getIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemSlot getSlot() {
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SlotComponent setScale(float scale) {
|
||||||
|
this.scale = scale;
|
||||||
|
|
||||||
|
int side = (int) (TEXTURE_SIZE * scale);
|
||||||
|
setPreferredSize(side, side);
|
||||||
|
invalidate();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SlotComponent setBackground(Texture texture, BooleanSupplier when) {
|
||||||
|
background = new PgmBuilder(FlatRenderProgram.getDefault(), texture).setSize(TEXTURE_SIZE).create();
|
||||||
|
setBackgroundDisplayCondition(when);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SlotComponent setBackground(Texture texture) {
|
||||||
|
return setBackground(texture, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SlotComponent setBackgroundDisplayCondition(BooleanSupplier backgroundCondition) {
|
||||||
|
this.backgroundCondition = backgroundCondition;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void assembleSelf(RenderTarget target) {
|
||||||
|
super.assembleSelf(target);
|
||||||
|
assembleItem(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateItemRenderer() {
|
||||||
|
ItemData contents;
|
||||||
|
contents = slot.getItem();
|
||||||
|
|
||||||
|
if (contents == null) {
|
||||||
|
itemRenderer = null;
|
||||||
|
amountDisplayInt = 0;
|
||||||
|
amountDisplayString = "";
|
||||||
|
} else {
|
||||||
|
if (itemRenderer == null || itemRenderer.getData() != contents) {
|
||||||
|
itemRenderer = ItemRenderRegistry.getInstance().get(contents.getId()).createRenderable(contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
int newAmount = slot.getCount();
|
||||||
|
if (newAmount != amountDisplayInt) {
|
||||||
|
amountDisplayInt = newAmount;
|
||||||
|
amountDisplayString = newAmount == 1 ? "" : Integer.toString(newAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assembleItem(RenderTarget target) {
|
||||||
|
target.pushTransform(new Mat4().translate(getX(), getY(), 0).scale(scale, scale, 1));
|
||||||
|
target.addCustomRenderer(renderer -> {
|
||||||
|
|
||||||
|
updateItemRenderer();
|
||||||
|
|
||||||
|
if (drawVirtualSlots && getSlot() == null) {
|
||||||
|
renderer.pushColorMultiplier().set(Colors.DEBUG_GREEN);
|
||||||
|
containerOpenDecoration.render(renderer);
|
||||||
|
renderer.popColorMultiplier();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemRenderer != null) {
|
||||||
|
itemRenderer.render(renderer);
|
||||||
|
renderDecorations(renderer);
|
||||||
|
} else if (background != null) {
|
||||||
|
if (backgroundCondition == null || backgroundCondition.getAsBoolean()) {
|
||||||
|
background.render(renderer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
target.popTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderDecorations(ShapeRenderHelper renderer) {
|
||||||
|
ItemData contents = getSlot().getItem();
|
||||||
|
|
||||||
|
if (contents instanceof ItemDataContainer) {
|
||||||
|
ItemDataContainer asContainer = (ItemDataContainer) contents;
|
||||||
|
|
||||||
|
if (asContainer.isOpen()) {
|
||||||
|
renderer.pushColorMultiplier().mul(Colors.BLUE);
|
||||||
|
containerOpenDecoration.render(renderer);
|
||||||
|
renderer.popColorMultiplier();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
double dx = InputTracker.getCursorX() - (getX() + getWidth() / 2);
|
||||||
|
double dy = InputTracker.getCursorY() - (getY() + getHeight() / 2);
|
||||||
|
double distanceToCursorSquared = dx*dx + dy*dy;
|
||||||
|
final double maxDistanceSquared = (scale * TEXTURE_SIZE * 4) * (scale * TEXTURE_SIZE * 4);
|
||||||
|
|
||||||
|
float opacity = (float) (1 - distanceToCursorSquared / maxDistanceSquared);
|
||||||
|
|
||||||
|
if (opacity > 0) {
|
||||||
|
renderer.pushColorMultiplier().mul(Colors.BLUE.x, Colors.BLUE.y, Colors.BLUE.z, opacity);
|
||||||
|
containerOpenableDecoration.render(renderer);
|
||||||
|
renderer.popColorMultiplier();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
|
||||||
|
public class WindowedHUD extends Component {
|
||||||
|
|
||||||
|
public WindowedHUD(String name) {
|
||||||
|
super(name);
|
||||||
|
setLayout(new WindowedLayout());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addWindow(InventoryWindow window) {
|
||||||
|
addChild(window);
|
||||||
|
window.setSize(window.getPreferredSize());
|
||||||
|
|
||||||
|
centerWindow(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeWindow(InventoryWindow window) {
|
||||||
|
removeChild(window);
|
||||||
|
requestReassembly();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void centerWindow(InventoryWindow window) {
|
||||||
|
window.setPosition(
|
||||||
|
(getWidth() - window.getWidth()) / 2,
|
||||||
|
(getHeight() - window.getHeight()) / 2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import glm.Glm;
|
||||||
|
import glm.vec._2.Vec2;
|
||||||
|
import glm.vec._2.i.Vec2i;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Layout;
|
||||||
|
|
||||||
|
public class WindowedLayout implements Layout {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void layout(Component c) {
|
||||||
|
for (Component component : c.getChildren()) {
|
||||||
|
InventoryWindow window = (InventoryWindow) component;
|
||||||
|
|
||||||
|
Vec2i size = new Vec2i(c.getWidth(), c.getHeight());
|
||||||
|
Glm.min(window.getPreferredSize(), size, size);
|
||||||
|
window.setSize(size);
|
||||||
|
|
||||||
|
Vec2 relPos = window.getRelativePosition();
|
||||||
|
|
||||||
|
if (Float.isNaN(relPos.x) || Float.isNaN(relPos.y)) {
|
||||||
|
relPos.x = 0.5f;
|
||||||
|
relPos.y = 2 / 3.0f;
|
||||||
|
} else {
|
||||||
|
float minPosX = 0;
|
||||||
|
float minPosY = window.getHeight() / (float) c.getHeight();
|
||||||
|
float maxPosX = 1;
|
||||||
|
float maxPosY = 1;
|
||||||
|
|
||||||
|
relPos.x = Glm.clamp(relPos.x, minPosX, maxPosX);
|
||||||
|
relPos.y = Glm.clamp(relPos.y, minPosY, maxPosY);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.setPosition(
|
||||||
|
(int) (relPos.x * c.getWidth() - window.getWidth() / 2.0f),
|
||||||
|
(int) (relPos.y * c.getHeight() - window.getHeight())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vec2i calculatePreferredSize(Component c) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -19,45 +19,18 @@
|
|||||||
package ru.windcorp.progressia.client.world.entity;
|
package ru.windcorp.progressia.client.world.entity;
|
||||||
|
|
||||||
import glm.vec._3.Vec3;
|
import glm.vec._3.Vec3;
|
||||||
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
import ru.windcorp.progressia.client.world.UpdatingRenderable;
|
||||||
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
|
||||||
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
|
|
||||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||||
import ru.windcorp.progressia.common.world.generic.EntityGeneric;
|
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 final EntityData data;
|
||||||
|
|
||||||
private long stateComputedForFrame = -1;
|
|
||||||
|
|
||||||
public EntityRenderable(EntityData data) {
|
public EntityRenderable(EntityData data) {
|
||||||
this.data = 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() {
|
public EntityData getData() {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.world.entity;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.InventoryHUD;
|
||||||
|
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 abstract InventoryHUD.Side getEquipmentSlotSide(EquipmentSlot equipmentSlot);
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.world.entity;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
|
||||||
|
|
||||||
|
public class SpeciesRenderRegistry extends NamespacedInstanceRegistry<SpeciesRender> {
|
||||||
|
|
||||||
|
private static final SpeciesRenderRegistry INSTANCE = new SpeciesRenderRegistry();
|
||||||
|
|
||||||
|
public static SpeciesRenderRegistry getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpeciesRender get(EntityDataPlayer player) {
|
||||||
|
return get(player.getSpecies().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<ItemRender> {
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.world.item.inventory;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.InteractiveSlotComponent;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainer;
|
||||||
|
|
||||||
|
public abstract class ContainerComponent extends Component {
|
||||||
|
|
||||||
|
public ContainerComponent(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract ItemContainer getContainer();
|
||||||
|
|
||||||
|
public abstract Collection<InteractiveSlotComponent> getSlots();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.world.item.inventory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
|
||||||
|
import glm.vec._2.i.Vec2i;
|
||||||
|
import ru.windcorp.progressia.client.graphics.Colors;
|
||||||
|
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.gui.layout.LayoutGrid;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.Bar;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.HUDWorkspace;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.InteractiveSlotComponent;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainer;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.event.ItemSlotChangedEvent;
|
||||||
|
|
||||||
|
public class ContainerComponentSimple extends ContainerComponent {
|
||||||
|
|
||||||
|
private final Group slots = new Group("Inventory.Slots", new LayoutGrid(0, 15));
|
||||||
|
private final List<InteractiveSlotComponent> slotCollection = new ArrayList<>();
|
||||||
|
|
||||||
|
private final ItemContainer container;
|
||||||
|
private final HUDWorkspace workspace;
|
||||||
|
|
||||||
|
private int tmp__getSlotsPerRow() {
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContainerComponentSimple(ItemContainer container, HUDWorkspace workspace) {
|
||||||
|
super("Inventory");
|
||||||
|
this.container = container;
|
||||||
|
this.workspace = workspace;
|
||||||
|
|
||||||
|
if (container.getInventory() != null) {
|
||||||
|
container.getInventory().subscribe(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
setLayout(new LayoutBorderHorizontal(15));
|
||||||
|
|
||||||
|
Bar massBar = new Bar(
|
||||||
|
"MassBar",
|
||||||
|
true,
|
||||||
|
Colors.toVector(0xFF44AAAA),
|
||||||
|
container::getMass,
|
||||||
|
container::getMassLimit
|
||||||
|
);
|
||||||
|
Bar volumeBar = new Bar(
|
||||||
|
"VolumeBar",
|
||||||
|
false,
|
||||||
|
Colors.toVector(0xFFAA4444),
|
||||||
|
container::getVolume,
|
||||||
|
container::getVolumeLimit
|
||||||
|
);
|
||||||
|
|
||||||
|
Component slotsAndVolumeBar = new Group(
|
||||||
|
"SlotsAndVolumeBar",
|
||||||
|
new LayoutBorderVertical(15),
|
||||||
|
slots.setLayoutHint(LayoutBorderVertical.CENTER),
|
||||||
|
volumeBar.setLayoutHint(LayoutBorderVertical.UP)
|
||||||
|
);
|
||||||
|
|
||||||
|
addChild(slotsAndVolumeBar.setLayoutHint(LayoutBorderHorizontal.CENTER));
|
||||||
|
addChild(massBar.setLayoutHint(LayoutBorderHorizontal.LEFT));
|
||||||
|
|
||||||
|
onSlotChanged(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addSlot(int index) {
|
||||||
|
final int maxX = tmp__getSlotsPerRow();
|
||||||
|
|
||||||
|
InteractiveSlotComponent component = new InteractiveSlotComponent("Inventory.Slot." + index, container, index, workspace);
|
||||||
|
|
||||||
|
Vec2i pos = new Vec2i(index % maxX, index / maxX);
|
||||||
|
slots.addChild(component.setLayoutHint(pos));
|
||||||
|
slotCollection.add(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeSlot(int index) {
|
||||||
|
slots.removeChild(slotCollection.remove(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemContainer getContainer() {
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<InteractiveSlotComponent> getSlots() {
|
||||||
|
return slotCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
private void onSlotChanged(ItemSlotChangedEvent e) {
|
||||||
|
if (e != null && e.getContainer() != container) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wantSlots = container.getLastFilledSlot();
|
||||||
|
int slotsPerRow = tmp__getSlotsPerRow();
|
||||||
|
|
||||||
|
wantSlots = (wantSlots / slotsPerRow + 2) * slotsPerRow;
|
||||||
|
if (wantSlots < slotsPerRow) {
|
||||||
|
wantSlots = slotsPerRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (wantSlots > slotCollection.size()) {
|
||||||
|
addSlot(slotCollection.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
while (wantSlots < slotCollection.size()) {
|
||||||
|
removeSlot(slotCollection.size() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.world.item.inventory;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.Inventory;
|
||||||
|
|
||||||
|
public abstract class InventoryComponent extends Component {
|
||||||
|
|
||||||
|
public InventoryComponent(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Inventory getInventory();
|
||||||
|
|
||||||
|
public abstract Collection<? extends ContainerComponent> getContainers();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.world.item.inventory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutFill;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.HUDWorkspace;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.Inventory;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainer;
|
||||||
|
|
||||||
|
public class InventoryComponentSimple extends InventoryComponent {
|
||||||
|
|
||||||
|
private final Inventory inventory;
|
||||||
|
private final Collection<ContainerComponentSimple> containers = new ArrayList<>();
|
||||||
|
|
||||||
|
public InventoryComponentSimple(String name, Inventory inventory, HUDWorkspace workspace) {
|
||||||
|
super(name);
|
||||||
|
setLayout(new LayoutFill());
|
||||||
|
this.inventory = inventory;
|
||||||
|
|
||||||
|
for (ItemContainer container : inventory.getContainers()) {
|
||||||
|
ContainerComponentSimple component = new ContainerComponentSimple(container, workspace);
|
||||||
|
containers.add(component);
|
||||||
|
addChild(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Inventory getInventory() {
|
||||||
|
return inventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<? extends ContainerComponent> getContainers() {
|
||||||
|
return containers;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.world.item.inventory;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.HUDWorkspace;
|
||||||
|
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.Inventory;
|
||||||
|
|
||||||
|
public abstract class InventoryRender extends Namespaced {
|
||||||
|
|
||||||
|
public InventoryRender(String id) {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract InventoryComponent createComponent(Inventory inventory, HUDWorkspace workspace);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.world.item.inventory;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry;
|
||||||
|
|
||||||
|
public class InventoryRenderRegistry extends NamespacedInstanceRegistry<InventoryRender> {
|
||||||
|
|
||||||
|
private static final InventoryRenderRegistry INSTANCE = new InventoryRenderRegistry();
|
||||||
|
|
||||||
|
public static InventoryRenderRegistry getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -65,6 +65,8 @@ public class Units {
|
|||||||
|
|
||||||
// Volume
|
// Volume
|
||||||
public static final float CUBIC_CENTIMETERS = CENTIMETERS * CENTIMETERS * CENTIMETERS;
|
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_METERS = METERS * METERS * METERS;
|
||||||
public static final float CUBIC_MILLIMETERS = MILLIMETERS * MILLIMETERS * MILLIMETERS;
|
public static final float CUBIC_MILLIMETERS = MILLIMETERS * MILLIMETERS * MILLIMETERS;
|
||||||
public static final float CUBIC_KILOMETERS = KILOMETERS * KILOMETERS * KILOMETERS;
|
public static final float CUBIC_KILOMETERS = KILOMETERS * KILOMETERS * KILOMETERS;
|
||||||
|
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ru.windcorp.progressia.common.state;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutput;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class BooleanStateField extends StateField {
|
||||||
|
|
||||||
|
public BooleanStateField(
|
||||||
|
String id,
|
||||||
|
boolean isLocal,
|
||||||
|
int index
|
||||||
|
) {
|
||||||
|
super(id, isLocal, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean get(StatefulObject object) {
|
||||||
|
return object.getStorage().getBoolean(getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNow(StatefulObject object, boolean value) {
|
||||||
|
object.getStorage().setBoolean(getIndex(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(StateChanger changer, boolean value) {
|
||||||
|
changer.setBoolean(this, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(
|
||||||
|
StatefulObject object,
|
||||||
|
DataInput input,
|
||||||
|
IOContext context
|
||||||
|
)
|
||||||
|
throws IOException {
|
||||||
|
object.getStorage().setBoolean(getIndex(), input.readBoolean());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(
|
||||||
|
StatefulObject object,
|
||||||
|
DataOutput output,
|
||||||
|
IOContext context
|
||||||
|
)
|
||||||
|
throws IOException {
|
||||||
|
output.writeBoolean(object.getStorage().getBoolean(getIndex()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copy(StatefulObject from, StatefulObject to) {
|
||||||
|
setNow(to, get(from));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int computeHashCode(StatefulObject object) {
|
||||||
|
return Boolean.hashCode(get(object));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areEqual(StatefulObject a, StatefulObject b) {
|
||||||
|
return get(a) == get(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefault(StateStorage storage) {
|
||||||
|
storage.setBoolean(getIndex(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -22,10 +22,13 @@ import gnu.trove.map.TIntIntMap;
|
|||||||
import gnu.trove.map.TIntObjectMap;
|
import gnu.trove.map.TIntObjectMap;
|
||||||
import gnu.trove.map.hash.TIntIntHashMap;
|
import gnu.trove.map.hash.TIntIntHashMap;
|
||||||
import gnu.trove.map.hash.TIntObjectHashMap;
|
import gnu.trove.map.hash.TIntObjectHashMap;
|
||||||
|
import gnu.trove.set.TIntSet;
|
||||||
|
import gnu.trove.set.hash.TIntHashSet;
|
||||||
|
|
||||||
public class HashMapStateStorage extends StateStorage {
|
public class HashMapStateStorage extends StateStorage {
|
||||||
|
|
||||||
private final TIntIntMap ints = new TIntIntHashMap();
|
private final TIntIntMap ints = new TIntIntHashMap();
|
||||||
|
private final TIntSet booleans = new TIntHashSet();
|
||||||
private final TIntObjectMap<Object> objects = new TIntObjectHashMap<>();
|
private final TIntObjectMap<Object> objects = new TIntObjectHashMap<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -38,6 +41,20 @@ public class HashMapStateStorage extends StateStorage {
|
|||||||
ints.put(index, value);
|
ints.put(index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getBoolean(int index) {
|
||||||
|
return booleans.contains(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBoolean(int index, boolean value) {
|
||||||
|
if (value) {
|
||||||
|
booleans.add(index);
|
||||||
|
} else {
|
||||||
|
booleans.remove(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getObject(int index) {
|
public Object getObject(int index) {
|
||||||
return objects.get(index);
|
return objects.get(index);
|
||||||
|
@ -85,6 +85,21 @@ public class InspectingStatefulObjectLayout
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class Boolean implements StateFieldBuilder.Boolean {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BooleanStateField build() {
|
||||||
|
return registerField(
|
||||||
|
new BooleanStateField(
|
||||||
|
id,
|
||||||
|
isLocal,
|
||||||
|
fieldIndexCounters.getBooleansThenIncrement()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private class Obj<T> implements StateFieldBuilder.Obj<T> {
|
private class Obj<T> implements StateFieldBuilder.Obj<T> {
|
||||||
|
|
||||||
private final ObjectCodec<T> codec;
|
private final ObjectCodec<T> codec;
|
||||||
@ -123,6 +138,11 @@ public class InspectingStatefulObjectLayout
|
|||||||
return new Int();
|
return new Int();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean ofBoolean() {
|
||||||
|
return new Boolean();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> Obj<T> of(ObjectCodec<T> codec, Supplier<T> defaultValue) {
|
public <T> Obj<T> of(ObjectCodec<T> codec, Supplier<T> defaultValue) {
|
||||||
return new Obj<T>(codec, defaultValue);
|
return new Obj<T>(codec, defaultValue);
|
||||||
|
@ -21,11 +21,13 @@ package ru.windcorp.progressia.common.state;
|
|||||||
public class OptimizedStateStorage extends StateStorage {
|
public class OptimizedStateStorage extends StateStorage {
|
||||||
|
|
||||||
private final int[] ints;
|
private final int[] ints;
|
||||||
|
private final boolean[] booleans;
|
||||||
private final Object[] objects;
|
private final Object[] objects;
|
||||||
|
|
||||||
public OptimizedStateStorage(PrimitiveCounters sizes) {
|
public OptimizedStateStorage(PrimitiveCounters sizes) {
|
||||||
this.ints = new int[sizes.getInts()];
|
this.ints = sizes.getInts() == 0 ? null : new int[sizes.getInts()];
|
||||||
this.objects = new Object[sizes.getObjects()];
|
this.booleans = sizes.getBooleans() == 0 ? null : new boolean[sizes.getBooleans()];
|
||||||
|
this.objects = sizes.getObjects() == 0 ? null : new Object[sizes.getObjects()];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -38,6 +40,16 @@ public class OptimizedStateStorage extends StateStorage {
|
|||||||
ints[index] = value;
|
ints[index] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getBoolean(int index) {
|
||||||
|
return booleans[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBoolean(int index, boolean value) {
|
||||||
|
booleans[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getObject(int index) {
|
public Object getObject(int index) {
|
||||||
return objects[index];
|
return objects[index];
|
||||||
|
@ -75,6 +75,16 @@ public class OptimizedStatefulObjectLayout
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean ofBoolean() {
|
||||||
|
return new Boolean() {
|
||||||
|
@Override
|
||||||
|
public BooleanStateField build() {
|
||||||
|
return (BooleanStateField) result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> Obj<T> of(ObjectCodec<T> codec, Supplier<T> defaultValue) {
|
public <T> Obj<T> of(ObjectCodec<T> codec, Supplier<T> defaultValue) {
|
||||||
return new Obj<T>() {
|
return new Obj<T>() {
|
||||||
|
@ -21,6 +21,7 @@ package ru.windcorp.progressia.common.state;
|
|||||||
class PrimitiveCounters {
|
class PrimitiveCounters {
|
||||||
|
|
||||||
private int ints = 0;
|
private int ints = 0;
|
||||||
|
private int booleans = 0;
|
||||||
private int objects = 0;
|
private int objects = 0;
|
||||||
|
|
||||||
public PrimitiveCounters() {
|
public PrimitiveCounters() {
|
||||||
@ -28,6 +29,7 @@ class PrimitiveCounters {
|
|||||||
|
|
||||||
public PrimitiveCounters(PrimitiveCounters copyFrom) {
|
public PrimitiveCounters(PrimitiveCounters copyFrom) {
|
||||||
this.ints = copyFrom.ints;
|
this.ints = copyFrom.ints;
|
||||||
|
this.booleans = copyFrom.booleans;
|
||||||
this.objects = copyFrom.objects;
|
this.objects = copyFrom.objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,6 +41,14 @@ class PrimitiveCounters {
|
|||||||
return this.ints++;
|
return this.ints++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getBooleans() {
|
||||||
|
return booleans;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBooleansThenIncrement() {
|
||||||
|
return this.booleans++;
|
||||||
|
}
|
||||||
|
|
||||||
public int getObjects() {
|
public int getObjects() {
|
||||||
return objects;
|
return objects;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ package ru.windcorp.progressia.common.state;
|
|||||||
public interface StateChanger {
|
public interface StateChanger {
|
||||||
|
|
||||||
void setInt(IntStateField field, int value);
|
void setInt(IntStateField field, int value);
|
||||||
|
void setBoolean(BooleanStateField field, boolean value);
|
||||||
<T> void setObject(ObjectStateField<T> field, T value);
|
<T> void setObject(ObjectStateField<T> field, T value);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,12 +29,18 @@ public interface StateFieldBuilder {
|
|||||||
IntStateField build();
|
IntStateField build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static interface Boolean {
|
||||||
|
BooleanStateField build();
|
||||||
|
}
|
||||||
|
|
||||||
public static interface Obj<T> {
|
public static interface Obj<T> {
|
||||||
ObjectStateField<T> build();
|
ObjectStateField<T> build();
|
||||||
}
|
}
|
||||||
|
|
||||||
Int ofInt();
|
Int ofInt();
|
||||||
|
|
||||||
|
Boolean ofBoolean();
|
||||||
|
|
||||||
<T> Obj<T> of(ObjectCodec<T> codec, Supplier<T> defaultValue);
|
<T> Obj<T> of(ObjectCodec<T> codec, Supplier<T> defaultValue);
|
||||||
|
|
||||||
default <T> Obj<T> of(Class<T> clazz, Supplier<T> defaultValue) {
|
default <T> Obj<T> of(Class<T> clazz, Supplier<T> defaultValue) {
|
||||||
|
@ -24,6 +24,10 @@ public abstract class StateStorage {
|
|||||||
|
|
||||||
public abstract void setInt(int index, int value);
|
public abstract void setInt(int index, int value);
|
||||||
|
|
||||||
|
public abstract boolean getBoolean(int index);
|
||||||
|
|
||||||
|
public abstract void setBoolean(int index, boolean value);
|
||||||
|
|
||||||
public abstract Object getObject(int index);
|
public abstract Object getObject(int index);
|
||||||
|
|
||||||
public abstract void setObject(int index, Object object);
|
public abstract void setObject(int index, Object object);
|
||||||
|
@ -43,6 +43,16 @@ public class StatefulObjectRegistry<T extends StatefulObject> {
|
|||||||
T build();
|
T build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public static interface IdFactory<T> {
|
||||||
|
/**
|
||||||
|
* Initializes a new, independent instance of the stateful object.
|
||||||
|
*
|
||||||
|
* @return the created object
|
||||||
|
*/
|
||||||
|
T build(String id);
|
||||||
|
}
|
||||||
|
|
||||||
protected static class Type<T> extends Namespaced {
|
protected static class Type<T> extends Namespaced {
|
||||||
|
|
||||||
private final Factory<T> factory;
|
private final Factory<T> factory;
|
||||||
@ -111,4 +121,8 @@ public class StatefulObjectRegistry<T extends StatefulObject> {
|
|||||||
registry.register(new Type<>(id, factory));
|
registry.register(new Type<>(id, factory));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void register(String id, IdFactory<T> factory) {
|
||||||
|
register(id, () -> factory.build(id));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.entity;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.EventBus;
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.state.IntStateField;
|
||||||
|
import ru.windcorp.progressia.common.state.ObjectStateField;
|
||||||
|
import ru.windcorp.progressia.common.util.crash.ReportingEventBus;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.InventoryUser;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainerEquipment;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainerHand;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.event.InventoryClosingEvent;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.event.InventoryOpenedEvent;
|
||||||
|
|
||||||
|
public class EntityDataPlayer extends EntityData implements InventoryUser {
|
||||||
|
|
||||||
|
private final ObjectStateField<SpeciesDatalet> speciesDatalet = field("Core:SpeciesDatalet").setShared()
|
||||||
|
.of(SpeciesDataRegistry.getInstance().getCodec()).build();
|
||||||
|
|
||||||
|
private final IntStateField selectedHand = field("Core:SelectedHand").setShared().ofInt().build();
|
||||||
|
|
||||||
|
private final EventBus eventBus = ReportingEventBus.create("EntityDataPlayer");
|
||||||
|
|
||||||
|
public EntityDataPlayer(String id, SpeciesData species) {
|
||||||
|
super(id);
|
||||||
|
|
||||||
|
setSpecies(species);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setSpecies(SpeciesData species) {
|
||||||
|
speciesDatalet.setNow(this, species.createDatalet());
|
||||||
|
setCollisionModel(species.getCollisionModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ItemContainerEquipment getEquipmentSlot(int index) {
|
||||||
|
return speciesDatalet.get(this).getEquipment()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
private void onInventoryOpened(InventoryOpenedEvent event) {
|
||||||
|
eventBus.post(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
private void onInventoryClosed(InventoryClosingEvent event) {
|
||||||
|
eventBus.post(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void subscribe(Object listener) {
|
||||||
|
eventBus.register(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unsubscribe(Object listener) {
|
||||||
|
eventBus.unregister(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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<SpeciesDatalet> {
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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<ItemData> filter;
|
||||||
|
|
||||||
|
public EquipmentSlot(String name, Predicate<ItemData> filter) {
|
||||||
|
super(name);
|
||||||
|
this.filter = filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Predicate<ItemData> getFilter() {
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Hand> hands;
|
||||||
|
private List<EquipmentSlot> 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<Hand> getHands() {
|
||||||
|
return hands;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<EquipmentSlot> getEquipmentSlots() {
|
||||||
|
return equipmentSlots;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract CollisionModel getCollisionModel();
|
||||||
|
|
||||||
|
public SpeciesDatalet createDatalet() {
|
||||||
|
return new SpeciesDatalet(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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<SpeciesData> {
|
||||||
|
|
||||||
|
private static final SpeciesDataRegistry INSTANCE = new SpeciesDataRegistry();
|
||||||
|
|
||||||
|
private final ObjectCodec<SpeciesDatalet> codec = new SpeciesCodec();
|
||||||
|
|
||||||
|
public static SpeciesDataRegistry getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjectCodec<SpeciesDatalet> getCodec() {
|
||||||
|
return codec;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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.inventory.ItemContainerEquipment;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.generic;
|
||||||
|
|
||||||
|
public interface ItemGeneric {
|
||||||
|
|
||||||
|
String getId();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.state.StatefulObject;
|
||||||
|
import ru.windcorp.progressia.common.world.generic.ItemGeneric;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An item identified by its ID and properties, able to reside in a slot.
|
||||||
|
*/
|
||||||
|
public abstract class ItemData extends StatefulObject implements ItemGeneric {
|
||||||
|
|
||||||
|
public ItemData(String id) {
|
||||||
|
super(ItemDataRegistry.getInstance(), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes and returns the mass of a single unit (single item) of this
|
||||||
|
* item.
|
||||||
|
*
|
||||||
|
* @return the mass of this item
|
||||||
|
*/
|
||||||
|
public abstract float getMass();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes and returns the volume of a single unit (single item) of this
|
||||||
|
* item stack.
|
||||||
|
*
|
||||||
|
* @return the volume of this item
|
||||||
|
*/
|
||||||
|
public abstract float getVolume();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterators;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.state.ObjectStateField;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.InventoryOwner;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.InventorySimple;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.InventoryUser;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainer;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainerMixedSimple;
|
||||||
|
|
||||||
|
public class ItemDataContainer extends ItemData implements InventoryOwner, ItemDataWithContainers {
|
||||||
|
|
||||||
|
private final ObjectStateField<InventorySimple> inventory = field("Core:Contents").setShared().def(this::createInventory)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
private final float ownMass;
|
||||||
|
private final float containerMassLimit;
|
||||||
|
|
||||||
|
private final float ownVolume;
|
||||||
|
private final float containerVolumeLimit;
|
||||||
|
private final boolean containerContributesVolume;
|
||||||
|
|
||||||
|
public ItemDataContainer(
|
||||||
|
String id,
|
||||||
|
float ownMass,
|
||||||
|
float containerMassLimit,
|
||||||
|
float ownVolume,
|
||||||
|
float containerVolumeLimit,
|
||||||
|
boolean containerContributesVolume
|
||||||
|
) {
|
||||||
|
super(id);
|
||||||
|
this.ownMass = ownMass;
|
||||||
|
this.containerMassLimit = containerMassLimit;
|
||||||
|
this.ownVolume = ownVolume;
|
||||||
|
this.containerVolumeLimit = containerVolumeLimit;
|
||||||
|
this.containerContributesVolume = containerContributesVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected InventorySimple createInventory() {
|
||||||
|
return new InventorySimple(
|
||||||
|
getId(),
|
||||||
|
this,
|
||||||
|
new ItemContainerMixedSimple(getId(), containerMassLimit, containerVolumeLimit)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InventorySimple getInventory() {
|
||||||
|
return inventory.get(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<? extends ItemContainer> getAllContainers() {
|
||||||
|
return Iterators.forArray(getInventory().getContainers());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOpen() {
|
||||||
|
return !getInventory().getUsers().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canOpen(InventoryUser user) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized InventorySimple open(InventoryUser user) {
|
||||||
|
if (isOpen()) {
|
||||||
|
return null;
|
||||||
|
} else if (!canOpen(user)) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
getInventory().open(user);
|
||||||
|
return getInventory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void close() {
|
||||||
|
getInventory().closeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getMass() {
|
||||||
|
return ownMass + getInventory().getMass();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getVolume() {
|
||||||
|
if (containerContributesVolume) {
|
||||||
|
return ownVolume + getInventory().getVolume();
|
||||||
|
} else {
|
||||||
|
return ownVolume;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.state.StatefulObjectRegistry;
|
||||||
|
|
||||||
|
public class ItemDataRegistry extends StatefulObjectRegistry<ItemData> {
|
||||||
|
|
||||||
|
private static final ItemDataRegistry INSTANCE = new ItemDataRegistry();
|
||||||
|
|
||||||
|
public static ItemDataRegistry getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item;
|
||||||
|
|
||||||
|
public class ItemDataSimple extends ItemData {
|
||||||
|
|
||||||
|
private final float mass;
|
||||||
|
private final float volume;
|
||||||
|
|
||||||
|
public ItemDataSimple(String id, float mass, float volume) {
|
||||||
|
super(id);
|
||||||
|
this.mass = mass;
|
||||||
|
this.volume = volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getMass() {
|
||||||
|
return mass;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getVolume() {
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainer;
|
||||||
|
|
||||||
|
public interface ItemDataWithContainers {
|
||||||
|
|
||||||
|
Iterator<? extends ItemContainer> getAllContainers();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainer;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemSlot;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A generalization of mass and volume. Not to be extended by mods.
|
||||||
|
*/
|
||||||
|
public enum LinearItemProperty {
|
||||||
|
|
||||||
|
MASS,
|
||||||
|
VOLUME;
|
||||||
|
|
||||||
|
public float get(ItemData item) {
|
||||||
|
switch (this) {
|
||||||
|
case MASS:
|
||||||
|
return item.getMass();
|
||||||
|
case VOLUME:
|
||||||
|
return item.getVolume();
|
||||||
|
default:
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float get(ItemSlot slot) {
|
||||||
|
switch (this) {
|
||||||
|
case MASS:
|
||||||
|
return slot.getMass();
|
||||||
|
case VOLUME:
|
||||||
|
return slot.getVolume();
|
||||||
|
default:
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float get(ItemContainer container) {
|
||||||
|
switch (this) {
|
||||||
|
case MASS:
|
||||||
|
return container.getMass();
|
||||||
|
case VOLUME:
|
||||||
|
return container.getVolume();
|
||||||
|
default:
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getLimit(ItemContainer container) {
|
||||||
|
switch (this) {
|
||||||
|
case MASS:
|
||||||
|
return container.getMassLimit();
|
||||||
|
case VOLUME:
|
||||||
|
return container.getVolumeLimit();
|
||||||
|
default:
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item.inventory;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutput;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.EventBus;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.state.Encodable;
|
||||||
|
import ru.windcorp.progressia.common.state.IOContext;
|
||||||
|
import ru.windcorp.progressia.common.util.crash.ReportingEventBus;
|
||||||
|
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.event.InventoryClosingEvent;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.event.InventoryOpenedEvent;
|
||||||
|
|
||||||
|
public class Inventory extends Namespaced implements Encodable {
|
||||||
|
|
||||||
|
private final InventoryOwner owner;
|
||||||
|
private final ItemContainer[] containers;
|
||||||
|
private final List<InventoryUser> users = new ArrayList<>();
|
||||||
|
|
||||||
|
private EventBus eventBus = null;
|
||||||
|
|
||||||
|
public Inventory(String id, InventoryOwner owner, ItemContainer... containers) {
|
||||||
|
super(id);
|
||||||
|
this.owner = owner;
|
||||||
|
this.containers = containers;
|
||||||
|
for (ItemContainer container : containers) {
|
||||||
|
container.setInventory(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public InventoryOwner getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void open(InventoryUser user) {
|
||||||
|
users.add(user);
|
||||||
|
subscribe(user);
|
||||||
|
eventBus.post(new InventoryOpenedEvent(this, user));
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void close(InventoryUser user) {
|
||||||
|
if (eventBus != null) {
|
||||||
|
eventBus.post(new InventoryClosingEvent(this, user));
|
||||||
|
}
|
||||||
|
|
||||||
|
users.remove(user);
|
||||||
|
unsubscribe(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void subscribe(Object listener) {
|
||||||
|
if (eventBus == null) {
|
||||||
|
eventBus = ReportingEventBus.create("Inventory " + getId());
|
||||||
|
}
|
||||||
|
eventBus.register(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void unsubscribe(Object listener) {
|
||||||
|
if (eventBus == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
eventBus.unregister(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the eventBus
|
||||||
|
*/
|
||||||
|
public EventBus getEventBus() {
|
||||||
|
return eventBus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized boolean isUser(InventoryUser user) {
|
||||||
|
return users.contains(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void forEachUser(Consumer<? super InventoryUser> action) {
|
||||||
|
users.forEach(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<InventoryUser> getUsers() {
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void closeAll() {
|
||||||
|
while (!users.isEmpty()) {
|
||||||
|
close(users.get(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemContainer[] getContainers() {
|
||||||
|
return containers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized float getMass() {
|
||||||
|
float sum = 0;
|
||||||
|
for (ItemContainer container : containers) {
|
||||||
|
sum += container.getMass();
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized float getVolume() {
|
||||||
|
float sum = 0;
|
||||||
|
for (ItemContainer container : containers) {
|
||||||
|
sum += container.getVolume();
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void read(DataInput input, IOContext context) throws IOException {
|
||||||
|
for (ItemContainer container : containers) {
|
||||||
|
container.read(input, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void write(DataOutput output, IOContext context) throws IOException {
|
||||||
|
for (ItemContainer container : containers) {
|
||||||
|
container.write(output, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void copy(Encodable destination) {
|
||||||
|
Inventory inventory = (Inventory) destination;
|
||||||
|
assert inventory.containers.length == containers.length;
|
||||||
|
for (int i = 0; i < containers.length; ++i) {
|
||||||
|
containers[i].copy(inventory.containers[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item.inventory;
|
||||||
|
|
||||||
|
public interface InventoryOwner {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item.inventory;
|
||||||
|
|
||||||
|
public class InventorySimple extends Inventory {
|
||||||
|
|
||||||
|
public InventorySimple(String id, InventoryOwner owner, ItemContainer container) {
|
||||||
|
super(id, owner, container);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemContainer getContainer() {
|
||||||
|
return getContainers()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item.inventory;
|
||||||
|
|
||||||
|
public interface InventoryUser {
|
||||||
|
|
||||||
|
default void open(Inventory inventory) {
|
||||||
|
inventory.open(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
default void close(Inventory inventory) {
|
||||||
|
inventory.close(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean isUsing(Inventory inventory) {
|
||||||
|
return inventory.isUser(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,525 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item.inventory;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import gnu.trove.iterator.TIntIterator;
|
||||||
|
import gnu.trove.set.TIntSet;
|
||||||
|
import gnu.trove.set.hash.TIntHashSet;
|
||||||
|
import ru.windcorp.progressia.common.state.Encodable;
|
||||||
|
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemData;
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemDataWithContainers;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.event.ItemSlotChangedEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base class of item containers. An item container is a set of slots with
|
||||||
|
* defined limits on mass and volume. Containers are typically grouped into an
|
||||||
|
* {@link Inventory} by in-game function.
|
||||||
|
* <p>
|
||||||
|
* A container contains some number of slots indexed from 0. Users may inspect
|
||||||
|
* the contents of any slot. Slots may contain an {@link ItemData} and an item
|
||||||
|
* count. Item count is zero iff the {@link ItemData} is {@code null}, in which
|
||||||
|
* case the slot is considered empty.
|
||||||
|
* <p>
|
||||||
|
* Item containers also implement mass and volume calculation. Both properties
|
||||||
|
* are determined by the corresponding {@link ItemData} methods, and combine
|
||||||
|
* linearly:
|
||||||
|
* {@code mass(2 * stick + 5 * apple) = 2 * mass(stick) + 5 * mass(apple)},
|
||||||
|
* empty slots do not contribute any mass of volume. Users may query these
|
||||||
|
* computed values. In addition, a limit may be imposed on both properties.
|
||||||
|
* Containers will refuse operations which would lead to the violation of these
|
||||||
|
* limits. However, containers cannot detect excess mass or volume resulting
|
||||||
|
* from
|
||||||
|
* a implementation-triggered change of limits.
|
||||||
|
* <p>
|
||||||
|
* As a safeguard against memory leaks, all containers must be provided with a
|
||||||
|
* maximum possible size. Item containers will refuse operations on slots with
|
||||||
|
* indices exceeding or equal to the maximum possible size.
|
||||||
|
* <p>
|
||||||
|
* Implementors will typically find the following subclasses useful:
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link ItemContainerMixed} for containers allowing an arbitrary amount of
|
||||||
|
* slots
|
||||||
|
* <ul>
|
||||||
|
* <li>see {@link ItemContainerMixedSimple} for a complete implementation</li>
|
||||||
|
* </ul>
|
||||||
|
* </li>
|
||||||
|
* <li>{@link ItemContainerSingle} for containers providing only one slot</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public abstract class ItemContainer extends Namespaced implements Encodable {
|
||||||
|
|
||||||
|
private Inventory inventory;
|
||||||
|
private final int maxPossibleSize;
|
||||||
|
|
||||||
|
private final TIntSet subContainersCache = new TIntHashSet();
|
||||||
|
|
||||||
|
public ItemContainer(String id, int maxPossibleSize) {
|
||||||
|
super(id);
|
||||||
|
this.maxPossibleSize = maxPossibleSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the inventory
|
||||||
|
*/
|
||||||
|
public Inventory getInventory() {
|
||||||
|
return inventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param inventory the inventory to set
|
||||||
|
*/
|
||||||
|
void setInventory(Inventory inventory) {
|
||||||
|
this.inventory = inventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the item in the slot at the specified index.
|
||||||
|
*
|
||||||
|
* @param index the index of the slot to query
|
||||||
|
* @return the item or {@code null} if the slot is empty.
|
||||||
|
*/
|
||||||
|
public abstract ItemData getItem(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the item count in the slot at the specified index.
|
||||||
|
*
|
||||||
|
* @param index the index of the slot to query
|
||||||
|
* @return the item count or {@code 0} if the slot is empty
|
||||||
|
*/
|
||||||
|
public abstract int getCount(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a slot index strictly greater than all indices containing
|
||||||
|
* items. Use this index as upper bound when iterating the container's
|
||||||
|
* items. The slot at this index is empty.
|
||||||
|
*
|
||||||
|
* @return a strict upper bound on the indices of filled slots
|
||||||
|
*/
|
||||||
|
public abstract int getMaxIndex();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes and returns the slot index of the last non-empty slot in this
|
||||||
|
* container. This operation is potentially slower than
|
||||||
|
* {@link #getMaxIndex()}, which is less precise.
|
||||||
|
*
|
||||||
|
* @return the index of the last filled slot, or -1 if no such slot exists
|
||||||
|
*/
|
||||||
|
public int getLastFilledSlot() {
|
||||||
|
int index = getMaxIndex();
|
||||||
|
while (isEmpty(index) && index >= 0) {
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether items of the specified kind could be inserted into
|
||||||
|
* this container assuming a slot is available and mass and volume
|
||||||
|
* requirements of the container are satisfied.
|
||||||
|
* <p>
|
||||||
|
* This method should only be a function of the configuration of the
|
||||||
|
* container and of the item; it must not depend on the contents of the
|
||||||
|
* container.
|
||||||
|
*
|
||||||
|
* @param item the item to check, not null
|
||||||
|
* @return {@code true} iff the item is allowed in this container
|
||||||
|
*/
|
||||||
|
protected boolean canAdd(ItemData item) {
|
||||||
|
if (item == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (containsRecursively(item, this)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean containsRecursively(ItemData haystack, ItemContainer needle) {
|
||||||
|
if (!(haystack instanceof ItemDataWithContainers)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemDataWithContainers haystackWithTastyHay = (ItemDataWithContainers) haystack;
|
||||||
|
|
||||||
|
Iterator<? extends ItemContainer> iterator = haystackWithTastyHay.getAllContainers();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
ItemContainer container = iterator.next();
|
||||||
|
|
||||||
|
if (container == needle) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TIntIterator indexIterator = container.subContainersCache.iterator();
|
||||||
|
|
||||||
|
while (indexIterator.hasNext()) {
|
||||||
|
|
||||||
|
int subHaystackIndex = indexIterator.next();
|
||||||
|
ItemData subHaystackOrMaybeNot = container.getItem(subHaystackIndex);
|
||||||
|
if (containsRecursively(subHaystackOrMaybeNot, needle)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether inventory users are allowed to manually remove items
|
||||||
|
* from this container.
|
||||||
|
* <p>
|
||||||
|
* This method should only be a function of the configuration of the
|
||||||
|
* container; it must not depend on the contents of the container.
|
||||||
|
*
|
||||||
|
* @return {@code true} iff items could be removed from this container
|
||||||
|
*/
|
||||||
|
protected boolean isRemovingAllowed() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the items can be added at the specified index. The
|
||||||
|
* slot must already contain items equal to {@code item} parameter or be
|
||||||
|
* empty. Neither total mass nor volume of the added items may exceed the
|
||||||
|
* available mass and volume of the container. Additional restrictions may
|
||||||
|
* apply.
|
||||||
|
* <p>
|
||||||
|
* When index is valid, {@code item == null} and {@code count == 0}, this
|
||||||
|
* method returns {@code true}. Otherwise, when {@code count <= 0}, this
|
||||||
|
* method returns {@code false}.
|
||||||
|
*
|
||||||
|
* @param index the index of the slot to query
|
||||||
|
* @param item the item type
|
||||||
|
* @param count the amount of items to add
|
||||||
|
* @return {@code true} iff the operation is possible
|
||||||
|
*/
|
||||||
|
public boolean canAdd(int index, ItemData item, int count) {
|
||||||
|
if (index < 0 || index >= maxPossibleSize) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item == null && count == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemData currentItem = getItem(index);
|
||||||
|
if (currentItem == null) {
|
||||||
|
// Pass
|
||||||
|
} else if (currentItem.equals(item)) {
|
||||||
|
// Pass
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!canAdd(item)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float addedMass = item.getMass() * count;
|
||||||
|
if (getMass() + addedMass > getMassLimit()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float addedVolume = item.getVolume() * count;
|
||||||
|
if (getVolume() + addedVolume > getVolumeLimit()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the items can be removed from the specified index. The
|
||||||
|
* slot must already contain items equal to {@code item} parameter. The item
|
||||||
|
* count must be no lower than {@code count} parameter. Additional
|
||||||
|
* restrictions may apply.
|
||||||
|
* <p>
|
||||||
|
* When index is valid, {@code item == null} and {@code count == 0}, this
|
||||||
|
* method returns {@code true}. Otherwise, when {@code count <= 0}, this
|
||||||
|
* method returns {@code false}.
|
||||||
|
*
|
||||||
|
* @param index the index of the slot to query
|
||||||
|
* @param item the item type
|
||||||
|
* @param count the amount of items to remove
|
||||||
|
* @return {@code true} iff the operation is possible
|
||||||
|
*/
|
||||||
|
public boolean canRemove(int index, ItemData item, int count) {
|
||||||
|
if (index < 0 || index >= maxPossibleSize) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item == null && count == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isRemovingAllowed()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemData currentItem = getItem(index);
|
||||||
|
if (currentItem == null) {
|
||||||
|
return false;
|
||||||
|
} else if (currentItem.equals(item)) {
|
||||||
|
// Pass
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getCount(index) < count) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to add the provided items to the specified slot in the
|
||||||
|
* container. This method modifies the data structure directly; use an
|
||||||
|
* appropriate {@link Items} method to add items in a safe and convenient
|
||||||
|
* way.
|
||||||
|
* <p>
|
||||||
|
* A {@link #canAdd(int, ItemData, int)} check is performed. If the check
|
||||||
|
* fails, the method does not alter the contents of the container and
|
||||||
|
* returns {@code false}. If the check succeeds, the item type and item
|
||||||
|
* count of the referenced slot are altered appropriately and {@code true}
|
||||||
|
* is returned.
|
||||||
|
* <p>
|
||||||
|
* When {@code item == null} or {@code count <= 0}, this method returns
|
||||||
|
* {@code false}.
|
||||||
|
*
|
||||||
|
* @param index the index of the slot to alter
|
||||||
|
* @param item the item type
|
||||||
|
* @param count the amount of items to add
|
||||||
|
* @return {@code true} iff the container was changed as the result of this
|
||||||
|
* operation
|
||||||
|
*/
|
||||||
|
protected abstract boolean add(int index, ItemData item, int count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to remove the provided items from the specified slot in the
|
||||||
|
* container. This method modifies the data structure directly; use an
|
||||||
|
* appropriate {@link Items} method to remove items in a safe and convenient
|
||||||
|
* way.
|
||||||
|
* <p>
|
||||||
|
* A {@link #canRemove(int, ItemData, int)} check is performed. If the check
|
||||||
|
* fails, the method does not alter the contents of the container and
|
||||||
|
* returns {@code false}. If the check succeeds, the item type and item
|
||||||
|
* count of the referenced slot are altered appropriately and {@code true}
|
||||||
|
* is returned.
|
||||||
|
* <p>
|
||||||
|
* When {@code item == null} or {@code count <= 0}, this method returns
|
||||||
|
* {@code false}.
|
||||||
|
*
|
||||||
|
* @param index the index of the slot to alter
|
||||||
|
* @param item the item type
|
||||||
|
* @param count the amount of items to remove
|
||||||
|
* @return {@code true} iff the container was changed as the result of this
|
||||||
|
* operation
|
||||||
|
*/
|
||||||
|
protected abstract boolean remove(int index, ItemData item, int count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
|
||||||
|
public synchronized float getMass() {
|
||||||
|
float sum = 0;
|
||||||
|
for (int i = 0; i < getMaxIndex(); ++i) {
|
||||||
|
ItemData data = getItem(i);
|
||||||
|
|
||||||
|
if (data == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sum += data.getMass() * getCount(i);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized float getVolume() {
|
||||||
|
float sum = 0;
|
||||||
|
for (int i = 0; i < getMaxIndex(); ++i) {
|
||||||
|
ItemData data = getItem(i);
|
||||||
|
|
||||||
|
if (data == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sum += data.getVolume() * getCount(i);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void fireSlotChangeEvent(int index) {
|
||||||
|
if (getItem(index) instanceof ItemDataWithContainers) {
|
||||||
|
subContainersCache.add(index);
|
||||||
|
} else {
|
||||||
|
subContainersCache.remove(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
Inventory inventory = this.inventory;
|
||||||
|
if (inventory == null || inventory.getEventBus() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inventory.getEventBus().post(new ItemSlotChangedEvent(this, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks class invariants and throws an {@link IllegalStateException} in
|
||||||
|
* case of discrepancies.
|
||||||
|
*/
|
||||||
|
protected synchronized void checkState() {
|
||||||
|
int maxIndex = getMaxIndex();
|
||||||
|
for (int index = 0; index < maxIndex; ++index) {
|
||||||
|
|
||||||
|
ItemData item = getItem(index);
|
||||||
|
int count = getCount(index);
|
||||||
|
|
||||||
|
if ((item == null) != (count == 0)) {
|
||||||
|
if (item == null) {
|
||||||
|
throw new IllegalStateException("Item is null but count (" + count + ") != 0 in slot " + index);
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Item is " + item + " but count is zero in slot " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count < 0) {
|
||||||
|
throw new IllegalStateException("count is negative: " + count + " in slot " + index);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isContainer = item instanceof ItemDataWithContainers;
|
||||||
|
if (isContainer != subContainersCache.contains(index)) {
|
||||||
|
if (!isContainer) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"subContainersCache is invalid: item in slot " + index + " (" + item
|
||||||
|
+ ") is cached as a container"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"subContainersCache is invalid: item in slot " + index + " (" + item
|
||||||
|
+ ") is not cached as a container"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isContainer) {
|
||||||
|
if (containsRecursively(item, this)) {
|
||||||
|
throw new IllegalStateException("Recursion detected in slot " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using negation in following checks to trigger errors if any value is
|
||||||
|
// NaN
|
||||||
|
// (since all comparisons return false if any operand is NaN)
|
||||||
|
|
||||||
|
float mass = getMass();
|
||||||
|
if (!(mass >= 0)) {
|
||||||
|
throw new IllegalStateException("Mass is negative: " + mass);
|
||||||
|
}
|
||||||
|
|
||||||
|
float massLimit = getMassLimit();
|
||||||
|
if (!(mass <= massLimit)) {
|
||||||
|
throw new IllegalStateException("Mass is greater than mass limit: " + mass + " > " + massLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
float volume = getVolume();
|
||||||
|
if (!(volume >= 0)) {
|
||||||
|
throw new IllegalStateException("Volume is negative: " + volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
float volumeLimit = getVolumeLimit();
|
||||||
|
if (!(volume <= volumeLimit)) {
|
||||||
|
throw new IllegalStateException("Volume is greater than volume limit: " + volume + " > " + volumeLimit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface SlotConsumer {
|
||||||
|
void accept(ItemData item, int count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes the provided action for each slot in this container. The action
|
||||||
|
* is run for empty slots, in which case call is invoked with parameters
|
||||||
|
* {@code (null, 0)} for each empty slot. The exact amount of invocations is
|
||||||
|
* determined by {@link #getMaxIndex()}.
|
||||||
|
*
|
||||||
|
* @param action the action to run
|
||||||
|
* @see #forEachItem(SlotConsumer)
|
||||||
|
*/
|
||||||
|
public synchronized void forEachSlot(SlotConsumer action) {
|
||||||
|
int maxIndex = getMaxIndex();
|
||||||
|
for (int i = 0; i < maxIndex; ++i) {
|
||||||
|
action.accept(getItem(i), getCount(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes the provided action for each non-empty slot in this container.
|
||||||
|
*
|
||||||
|
* @param action the action to run
|
||||||
|
* @see #forEachSlot(SlotConsumer)
|
||||||
|
*/
|
||||||
|
public synchronized void forEachItem(SlotConsumer action) {
|
||||||
|
int maxIndex = getMaxIndex();
|
||||||
|
for (int i = 0; i < maxIndex; ++i) {
|
||||||
|
|
||||||
|
int count = getCount(i);
|
||||||
|
if (count != 0) {
|
||||||
|
action.accept(getItem(i), count);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty(int index) {
|
||||||
|
return getCount(index) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item.inventory;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.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);
|
||||||
|
this.equipmentSlot = equipmentSlot;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getMassLimit() {
|
||||||
|
return EQUIP_MASS_LIMIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getVolumeLimit() {
|
||||||
|
return EQUIP_VOLUME_LIMIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpeciesData.EquipmentSlot getEquipmentSlot() {
|
||||||
|
return equipmentSlot;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item.inventory;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.Units;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.SpeciesData;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.SpeciesData.Hand;
|
||||||
|
|
||||||
|
public class ItemContainerHand extends ItemContainerSingle {
|
||||||
|
|
||||||
|
private static final float HAND_MASS_LIMIT = Units.get("10 kg");
|
||||||
|
private static final float HAND_VOLUME_LIMIT = Units.get("5 kg");
|
||||||
|
|
||||||
|
private final SpeciesData.Hand hand;
|
||||||
|
|
||||||
|
public ItemContainerHand(String id, Hand hand) {
|
||||||
|
super(id);
|
||||||
|
this.hand = hand;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getMassLimit() {
|
||||||
|
return HAND_MASS_LIMIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getVolumeLimit() {
|
||||||
|
return HAND_VOLUME_LIMIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpeciesData.Hand getHand() {
|
||||||
|
return hand;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item.inventory;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutput;
|
||||||
|
import java.io.IOException;
|
||||||
|
import ru.windcorp.progressia.common.state.Encodable;
|
||||||
|
import ru.windcorp.progressia.common.state.IOContext;
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemData;
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemDataRegistry;
|
||||||
|
|
||||||
|
public abstract class ItemContainerMixed extends ItemContainer {
|
||||||
|
|
||||||
|
public static final int MAX_SLOTS = 10000;
|
||||||
|
|
||||||
|
private static final int GROWTH_STEP = 10;
|
||||||
|
private static final int MINIMUM_CAPACITY = 10;
|
||||||
|
|
||||||
|
private ItemData[] items = new ItemData[MINIMUM_CAPACITY];
|
||||||
|
private int[] counts = new int[MINIMUM_CAPACITY];
|
||||||
|
|
||||||
|
public ItemContainerMixed(String id) {
|
||||||
|
super(id, MAX_SLOTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setCapacity(int minimumCapacity) {
|
||||||
|
if (minimumCapacity < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int newCapacity = ((minimumCapacity - MINIMUM_CAPACITY - 1) / GROWTH_STEP + 1) * GROWTH_STEP + MINIMUM_CAPACITY;
|
||||||
|
|
||||||
|
ItemData[] newItems = new ItemData[newCapacity];
|
||||||
|
int[] newCounts = new int[newCapacity];
|
||||||
|
|
||||||
|
int length = Math.min(this.items.length, newItems.length);
|
||||||
|
System.arraycopy(this.items, 0, newItems, 0, length);
|
||||||
|
System.arraycopy(this.counts, 0, newCounts, 0, length);
|
||||||
|
|
||||||
|
this.items = newItems;
|
||||||
|
this.counts = newCounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void ensureCapacity(int minimumCapacity) {
|
||||||
|
if (items.length >= minimumCapacity) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCapacity(minimumCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void read(DataInput input, IOContext context) throws IOException {
|
||||||
|
int size = input.readInt();
|
||||||
|
|
||||||
|
ensureCapacity(size);
|
||||||
|
|
||||||
|
for (int index = 0; index < size; ++index) {
|
||||||
|
|
||||||
|
ItemData item;
|
||||||
|
int count = input.readInt();
|
||||||
|
|
||||||
|
if (count != 0) {
|
||||||
|
String id = input.readUTF();
|
||||||
|
item = ItemDataRegistry.getInstance().create(id);
|
||||||
|
item.read(input, context);
|
||||||
|
} else {
|
||||||
|
item = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
items[index] = item;
|
||||||
|
counts[index] = count;
|
||||||
|
|
||||||
|
fireSlotChangeEvent(index);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
checkState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void write(DataOutput output, IOContext context) throws IOException {
|
||||||
|
|
||||||
|
int size = items.length;
|
||||||
|
output.writeInt(size);
|
||||||
|
|
||||||
|
for (int index = 0; index < size; ++index) {
|
||||||
|
output.writeInt(counts[index]);
|
||||||
|
ItemData item = items[index];
|
||||||
|
|
||||||
|
if (item != null) {
|
||||||
|
output.writeUTF(item.getId());
|
||||||
|
item.write(output, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copy(Encodable destination) {
|
||||||
|
ItemContainerMixed other = (ItemContainerMixed) destination;
|
||||||
|
int myLength = this.items.length;
|
||||||
|
|
||||||
|
synchronized (this) {
|
||||||
|
synchronized (other) {
|
||||||
|
|
||||||
|
other.setCapacity(myLength);
|
||||||
|
System.arraycopy(this.counts, 0, other.counts, 0, myLength);
|
||||||
|
|
||||||
|
for (int i = 0; i < myLength; ++i) {
|
||||||
|
ItemData myItem = this.items[i];
|
||||||
|
ItemData otherItem;
|
||||||
|
|
||||||
|
if (myItem == null) {
|
||||||
|
otherItem = null;
|
||||||
|
} else {
|
||||||
|
otherItem = ItemDataRegistry.getInstance().create(myItem.getId());
|
||||||
|
myItem.copy(otherItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
other.items[i] = otherItem;
|
||||||
|
other.fireSlotChangeEvent(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemData getItem(int index) {
|
||||||
|
if (index < 0 || index >= items.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return items[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount(int index) {
|
||||||
|
if (index < 0 || index >= counts.length) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return counts[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxIndex() {
|
||||||
|
return items.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean add(int index, ItemData item, int count) {
|
||||||
|
if (!canAdd(index, item, count)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item != null) {
|
||||||
|
ensureCapacity(index + 1);
|
||||||
|
this.items[index] = item;
|
||||||
|
this.counts[index] += count;
|
||||||
|
fireSlotChangeEvent(index);
|
||||||
|
checkState();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean remove(int index, ItemData item, int count) {
|
||||||
|
if (!canRemove(index, item, count)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count != 0) {
|
||||||
|
this.counts[index] -= count;
|
||||||
|
|
||||||
|
if (this.counts[index] == 0) {
|
||||||
|
this.items[index] = null;
|
||||||
|
shrinkIfPossible();
|
||||||
|
}
|
||||||
|
|
||||||
|
fireSlotChangeEvent(index);
|
||||||
|
checkState();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void shrinkIfPossible() {
|
||||||
|
int upperBound;
|
||||||
|
|
||||||
|
for (upperBound = counts.length; upperBound > MINIMUM_CAPACITY; --upperBound) {
|
||||||
|
if (counts[upperBound - 1] != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (upperBound != counts.length) {
|
||||||
|
setCapacity(upperBound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected synchronized void checkState() {
|
||||||
|
super.checkState();
|
||||||
|
|
||||||
|
if (items.length > MAX_SLOTS) {
|
||||||
|
throw new IllegalStateException("Container has more than " + MAX_SLOTS + " slots (items): " + items.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (counts.length > MAX_SLOTS) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Container has more than " + MAX_SLOTS + " slots (counts): " + counts.length
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item.inventory;
|
||||||
|
|
||||||
|
public class ItemContainerMixedSimple extends ItemContainerMixed {
|
||||||
|
|
||||||
|
private final float massLimit;
|
||||||
|
private final float volumeLimit;
|
||||||
|
|
||||||
|
public ItemContainerMixedSimple(String id, float massLimit, float volumeLimit) {
|
||||||
|
super(id);
|
||||||
|
this.massLimit = massLimit;
|
||||||
|
this.volumeLimit = volumeLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getMassLimit() {
|
||||||
|
return massLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getVolumeLimit() {
|
||||||
|
return volumeLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item.inventory;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutput;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.state.Encodable;
|
||||||
|
import ru.windcorp.progressia.common.state.IOContext;
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemData;
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemDataRegistry;
|
||||||
|
|
||||||
|
public abstract class ItemContainerSingle extends ItemContainer {
|
||||||
|
|
||||||
|
private ItemData item;
|
||||||
|
private int count;
|
||||||
|
private ItemSlot slot = new ItemSlot(this, 0);
|
||||||
|
|
||||||
|
public ItemContainerSingle(String id) {
|
||||||
|
super(id, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void read(DataInput input, IOContext context) throws IOException {
|
||||||
|
count = input.readInt();
|
||||||
|
if (count != 0) {
|
||||||
|
String id = input.readUTF();
|
||||||
|
item = ItemDataRegistry.getInstance().create(id);
|
||||||
|
item.read(input, context);
|
||||||
|
} else {
|
||||||
|
item = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
fireSlotChangeEvent(0);
|
||||||
|
checkState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void write(DataOutput output, IOContext context) throws IOException {
|
||||||
|
output.writeInt(count);
|
||||||
|
if (item != null) {
|
||||||
|
output.writeUTF(item.getId());
|
||||||
|
item.write(output, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copy(Encodable destination) {
|
||||||
|
ItemContainerSingle other = (ItemContainerSingle) destination;
|
||||||
|
|
||||||
|
synchronized (this) {
|
||||||
|
synchronized (other) {
|
||||||
|
other.count = this.count;
|
||||||
|
|
||||||
|
if (this.item == null) {
|
||||||
|
other.item = null;
|
||||||
|
} else {
|
||||||
|
if (other.item == null || !other.item.isLike(this.item)) {
|
||||||
|
other.item = ItemDataRegistry.getInstance().create(this.item.getId());
|
||||||
|
}
|
||||||
|
this.item.copy(other.item);
|
||||||
|
other.fireSlotChangeEvent(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemData getItem(int index) {
|
||||||
|
if (index != 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemData getItem() {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount(int index) {
|
||||||
|
if (index != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCount() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemSlot slot() {
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxIndex() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean add(int index, ItemData item, int count) {
|
||||||
|
if (!canAdd(index, item, count)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item != null) {
|
||||||
|
this.item = item;
|
||||||
|
this.count += count;
|
||||||
|
fireSlotChangeEvent(0);
|
||||||
|
checkState();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean remove(int index, ItemData item, int count) {
|
||||||
|
if (!canRemove(index, item, count)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count != 0) {
|
||||||
|
this.count -= count;
|
||||||
|
if (this.count == 0) {
|
||||||
|
this.item = null;
|
||||||
|
}
|
||||||
|
fireSlotChangeEvent(0);
|
||||||
|
checkState();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item.inventory;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to a slot in a container. The container and the index of an
|
||||||
|
* {@code ItemSlot} cannot be changed.
|
||||||
|
* <p>
|
||||||
|
* {@code ItemSlot}s are wrapper objects; there may be multiple objects
|
||||||
|
* referencing a single slot. Slot objects are considered
|
||||||
|
* {@linkplain #equals(Object) equal} iff their indices are equal and they refer
|
||||||
|
* to the same container.
|
||||||
|
* <p>
|
||||||
|
* This class provides public methods for fetching slot contents but not for
|
||||||
|
* changing them. To alter a slot, use an appropriate method from {@link Items}.
|
||||||
|
*/
|
||||||
|
public class ItemSlot {
|
||||||
|
|
||||||
|
private final ItemContainer container;
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
public ItemSlot(ItemContainer container, int index) {
|
||||||
|
this.container = container;
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the container
|
||||||
|
*/
|
||||||
|
public ItemContainer getContainer() {
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the index
|
||||||
|
*/
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Inventory getInventory() {
|
||||||
|
return container.getInventory();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemData getItem() {
|
||||||
|
return container.getItem(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCount() {
|
||||||
|
return container.getCount(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return container.isEmpty(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canAdd(ItemData item, int count) {
|
||||||
|
return container.canAdd(index, item, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canRemove(ItemData item, int count) {
|
||||||
|
return container.canRemove(index, item, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean add(ItemData item, int count) {
|
||||||
|
return container.add(index, item, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean remove(ItemData item, int count) {
|
||||||
|
return container.remove(index, item, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getMass() {
|
||||||
|
synchronized (container) {
|
||||||
|
int count = getCount();
|
||||||
|
if (count == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return count * getItem().getMass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getVolume() {
|
||||||
|
synchronized (container) {
|
||||||
|
int count = getCount();
|
||||||
|
if (count == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return count * getItem().getVolume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For purposes of equality checking, all container instances are considered
|
||||||
|
* different
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + System.identityHashCode(container);
|
||||||
|
result = prime * result + index;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
ItemSlot other = (ItemSlot) obj;
|
||||||
|
if (container != other.container)
|
||||||
|
return false;
|
||||||
|
if (index != other.index)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,264 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item.inventory;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemData;
|
||||||
|
import ru.windcorp.progressia.common.world.item.LinearItemProperty;
|
||||||
|
|
||||||
|
public class Items {
|
||||||
|
|
||||||
|
private static int pour(ItemContainer from, int fromIndex, ItemContainer into, int intoIndex, int max) {
|
||||||
|
synchronized (from) {
|
||||||
|
synchronized (into) {
|
||||||
|
|
||||||
|
if (!from.isRemovingAllowed()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemData item = from.getItem(fromIndex);
|
||||||
|
|
||||||
|
if (item == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!into.canAdd(item)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!into.isEmpty(intoIndex) && !into.getItem(intoIndex).equals(item)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int originalCount = from.getCount(fromIndex);
|
||||||
|
int transferCount = Math.min(originalCount, max);
|
||||||
|
|
||||||
|
for (LinearItemProperty prop : LinearItemProperty.values()) {
|
||||||
|
int canFitPropwise = (int) Math.floor((prop.getLimit(into) - prop.get(into)) / prop.get(item));
|
||||||
|
if (canFitPropwise < transferCount) {
|
||||||
|
transferCount = canFitPropwise;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transferCount == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!into.canAdd(intoIndex, item, transferCount)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!from.remove(fromIndex, item, transferCount)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean success = into.add(intoIndex, item, transferCount);
|
||||||
|
assert success : "Wait, canAdd and canRemove promised the operation would be safe!";
|
||||||
|
|
||||||
|
return transferCount;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to transfer as many items as possible, but no more than
|
||||||
|
* {@code max}, between two slots. The origin of the items is {@code from},
|
||||||
|
* the destination is {@code into}. This method does nothing if the items
|
||||||
|
* could not be removed from origin or could not be inserted into
|
||||||
|
* destination, such as when {@code into} contains different items.
|
||||||
|
*
|
||||||
|
* @param from the slot to transfer item from
|
||||||
|
* @param into the destination of the items
|
||||||
|
* @param max the maximum amount of items to transfer. Use
|
||||||
|
* {@code Integer.MAX_VALUE} to remove the limit
|
||||||
|
* @return the actual amount of items moved between slots
|
||||||
|
*/
|
||||||
|
public static int pour(ItemSlot from, ItemSlot into, int max) {
|
||||||
|
return pour(from.getContainer(), from.getIndex(), into.getContainer(), into.getIndex(), max);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to transfer as many items as possible between two slots. The
|
||||||
|
* origin of the items is {@code from}, the destination is {@code into}.
|
||||||
|
* This method does nothing if the items could not be removed from origin or
|
||||||
|
* could not be inserted into destination, such as when {@code into}
|
||||||
|
* contains different items.
|
||||||
|
*
|
||||||
|
* @param from the slot to transfer item from
|
||||||
|
* @param into the destination of the items
|
||||||
|
* @return the actual amount of items moved between slots
|
||||||
|
*/
|
||||||
|
public static int pour(ItemSlot from, ItemSlot into) {
|
||||||
|
return pour(from.getContainer(), from.getIndex(), into.getContainer(), into.getIndex(), Integer.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to swap the contents of the two slots. Swapping contents of two
|
||||||
|
* empty slots results in a no-op and is considered a success.
|
||||||
|
*
|
||||||
|
* @param a one of the slots
|
||||||
|
* @param b the other slot
|
||||||
|
* @return whether the swap succeeded
|
||||||
|
*/
|
||||||
|
public static boolean swap(ItemSlot a, ItemSlot b) {
|
||||||
|
synchronized (a.getContainer()) {
|
||||||
|
synchronized (b.getContainer()) {
|
||||||
|
|
||||||
|
if (a.isEmpty() && b.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!a.isEmpty() && !a.getContainer().isRemovingAllowed()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!b.isEmpty() && !b.getContainer().isRemovingAllowed()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemData aItem = a.getItem();
|
||||||
|
int aCount = a.getCount();
|
||||||
|
|
||||||
|
ItemData bItem = b.getItem();
|
||||||
|
int bCount = b.getCount();
|
||||||
|
|
||||||
|
a.remove(aItem, aCount);
|
||||||
|
b.remove(bItem, bCount);
|
||||||
|
|
||||||
|
if (a.canAdd(bItem, bCount) && b.canAdd(aItem, aCount)) {
|
||||||
|
a.add(bItem, bCount);
|
||||||
|
b.add(aItem, aCount);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
a.add(aItem, aCount);
|
||||||
|
b.add(bItem, bCount);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to place new items into the specified slot. Either all or none
|
||||||
|
* of the requested items will be spawned.
|
||||||
|
*
|
||||||
|
* @param into destination slot
|
||||||
|
* @param item the item to add
|
||||||
|
* @param count the item count
|
||||||
|
* @return whether the addition succeeded
|
||||||
|
*/
|
||||||
|
public static boolean spawn(ItemSlot into, ItemData item, int count) {
|
||||||
|
synchronized (into.getContainer()) {
|
||||||
|
return into.add(item, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to remove items from the specified slot. Either all or none of
|
||||||
|
* the requested items will be destroyed.
|
||||||
|
*
|
||||||
|
* @param from the slot
|
||||||
|
* @param item the item to remove
|
||||||
|
* @param count the item count
|
||||||
|
* @return whether the removal succeeded
|
||||||
|
*/
|
||||||
|
public static boolean destroy(ItemSlot from, ItemData item, int count) {
|
||||||
|
synchronized (from.getContainer()) {
|
||||||
|
return from.remove(item, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int pour(ItemSlot from, ItemContainer into, int max) {
|
||||||
|
synchronized (from.getContainer()) {
|
||||||
|
synchronized (into) {
|
||||||
|
|
||||||
|
int totalPoured = 0;
|
||||||
|
|
||||||
|
for (int index = 0; max > 0 && index <= into.getMaxIndex(); ++index) {
|
||||||
|
int poured = pour(from.getContainer(), from.getIndex(), into, index, max);
|
||||||
|
max -= poured;
|
||||||
|
totalPoured += poured;
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalPoured;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int pour(ItemSlot from, ItemContainer into) {
|
||||||
|
return pour(from, into, Integer.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean spawn(ItemContainer into, ItemData item, int count) {
|
||||||
|
synchronized (into) {
|
||||||
|
|
||||||
|
if (item == null && count == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!into.canAdd(item)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (LinearItemProperty prop : LinearItemProperty.values()) {
|
||||||
|
float requested = prop.get(item) * count;
|
||||||
|
float available = prop.getLimit(into) - prop.get(into);
|
||||||
|
if (requested > available) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int compatibleSlot = -1;
|
||||||
|
int firstEmptySlot = -1;
|
||||||
|
|
||||||
|
for (int index = 0; index <= into.getMaxIndex(); ++index) {
|
||||||
|
ItemData inSlot = into.getItem(index);
|
||||||
|
if (inSlot == null) {
|
||||||
|
if (firstEmptySlot == -1) {
|
||||||
|
firstEmptySlot = index;
|
||||||
|
}
|
||||||
|
} else if (inSlot.equals(item)) {
|
||||||
|
compatibleSlot = index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compatibleSlot == -1) {
|
||||||
|
compatibleSlot = firstEmptySlot;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compatibleSlot == -1) {
|
||||||
|
// Means the inventory is full due to slot limit
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return into.add(compatibleSlot, item, count);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Items() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item.inventory.event;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.Inventory;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.InventoryUser;
|
||||||
|
|
||||||
|
public class InventoryClosingEvent extends InventoryEvent {
|
||||||
|
|
||||||
|
private final InventoryUser closingUser;
|
||||||
|
|
||||||
|
public InventoryClosingEvent(Inventory inventory, InventoryUser closingUser) {
|
||||||
|
super(inventory);
|
||||||
|
this.closingUser = closingUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InventoryUser getClosingUser() {
|
||||||
|
return closingUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item.inventory.event;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.Inventory;
|
||||||
|
|
||||||
|
public abstract class InventoryEvent {
|
||||||
|
|
||||||
|
private final Inventory inventory;
|
||||||
|
|
||||||
|
public InventoryEvent(Inventory inventory) {
|
||||||
|
this.inventory = inventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the inventory
|
||||||
|
*/
|
||||||
|
public Inventory getInventory() {
|
||||||
|
return inventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item.inventory.event;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.Inventory;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.InventoryUser;
|
||||||
|
|
||||||
|
public class InventoryOpenedEvent extends InventoryEvent {
|
||||||
|
|
||||||
|
private final InventoryUser newUser;
|
||||||
|
|
||||||
|
public InventoryOpenedEvent(Inventory inventory, InventoryUser newUser) {
|
||||||
|
super(inventory);
|
||||||
|
this.newUser = newUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the newUser
|
||||||
|
*/
|
||||||
|
public InventoryUser getNewUser() {
|
||||||
|
return newUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item.inventory.event;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainer;
|
||||||
|
|
||||||
|
public abstract class ItemContainerEvent extends InventoryEvent {
|
||||||
|
|
||||||
|
private final ItemContainer container;
|
||||||
|
|
||||||
|
public ItemContainerEvent(ItemContainer container) {
|
||||||
|
super(container.getInventory());
|
||||||
|
this.container = container;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the container
|
||||||
|
*/
|
||||||
|
public ItemContainer getContainer() {
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item.inventory.event;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainer;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemSlot;
|
||||||
|
|
||||||
|
public class ItemSlotChangedEvent extends ItemSlotEvent {
|
||||||
|
|
||||||
|
public ItemSlotChangedEvent(ItemSlot slot) {
|
||||||
|
super(slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemSlotChangedEvent(ItemContainer container, int index) {
|
||||||
|
super(container, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item.inventory.event;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainer;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemSlot;
|
||||||
|
|
||||||
|
public abstract class ItemSlotEvent extends ItemContainerEvent {
|
||||||
|
|
||||||
|
private ItemSlot slot = null;
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
public ItemSlotEvent(ItemContainer container, int index) {
|
||||||
|
super(container);
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemSlotEvent(ItemSlot slot) {
|
||||||
|
this(slot.getContainer(), slot.getIndex());
|
||||||
|
this.slot = slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the index
|
||||||
|
*/
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the slot
|
||||||
|
*/
|
||||||
|
public ItemSlot getSlot() {
|
||||||
|
if (slot == null) {
|
||||||
|
slot = new ItemSlot(getContainer(), index);
|
||||||
|
}
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -20,11 +20,13 @@ package ru.windcorp.progressia.server;
|
|||||||
|
|
||||||
import glm.vec._3.Vec3;
|
import glm.vec._3.Vec3;
|
||||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
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.entity.EntityDataRegistry;
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemDataRegistry;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.Items;
|
||||||
import ru.windcorp.progressia.server.comms.ClientPlayer;
|
import ru.windcorp.progressia.server.comms.ClientPlayer;
|
||||||
import ru.windcorp.progressia.server.events.PlayerJoinedEvent;
|
import ru.windcorp.progressia.server.events.PlayerJoinedEvent;
|
||||||
import ru.windcorp.progressia.server.events.PlayerLeftEvent;
|
import ru.windcorp.progressia.server.events.PlayerLeftEvent;
|
||||||
import ru.windcorp.progressia.test.TestContent;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -59,21 +61,22 @@ public class PlayerManager {
|
|||||||
|
|
||||||
Player player = getServer().getWorld().getContainer().loadPlayer(login, clientPlayer, getServer());
|
Player player = getServer().getWorld().getContainer().loadPlayer(login, clientPlayer, getServer());
|
||||||
if (player == null) { // create new player
|
if (player == null) { // create new player
|
||||||
EntityData entity = spawnPlayerEntity(clientPlayer, login);
|
EntityData entity = spawnPlayerEntity(login);
|
||||||
player = new Player(entity, getServer(), clientPlayer);
|
player = new Player(entity, getServer(), clientPlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
getServer().getWorld().getData().addEntity(player.getEntity());
|
getServer().getWorld().spawnEntity(player.getEntity());
|
||||||
|
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
|
||||||
private EntityData spawnPlayerEntity(ClientPlayer clientPlayer, String login) {
|
private EntityDataPlayer spawnPlayerEntity(String login) {
|
||||||
EntityData player = EntityDataRegistry.getInstance().create("Test:Player");
|
EntityDataPlayer player = (EntityDataPlayer) EntityDataRegistry.getInstance().create("Core:Player");
|
||||||
|
|
||||||
|
Items.spawn(player.getHand(0).slot(), ItemDataRegistry.getInstance().create("Test:Stick"), 5);
|
||||||
|
Items.spawn(player.getEquipmentSlot(0).slot(), ItemDataRegistry.getInstance().create("Test:CardboardBackpack"), 1);
|
||||||
|
|
||||||
player.setEntityId(TestContent.PLAYER_ENTITY_ID);
|
|
||||||
player.setPosition(getServer().getWorld().getGenerator().suggestSpawnLocation());
|
player.setPosition(getServer().getWorld().getGenerator().suggestSpawnLocation());
|
||||||
|
|
||||||
player.setUpVector(new Vec3(0, 0, 1));
|
player.setUpVector(new Vec3(0, 0, 1));
|
||||||
player.setLookingAt(new Vec3(2, 1, 0));
|
player.setLookingAt(new Vec3(2, 1, 0));
|
||||||
|
|
||||||
|
@ -37,7 +37,6 @@ import ru.windcorp.progressia.server.Player;
|
|||||||
import ru.windcorp.progressia.server.Server;
|
import ru.windcorp.progressia.server.Server;
|
||||||
import ru.windcorp.progressia.server.comms.ClientPlayer;
|
import ru.windcorp.progressia.server.comms.ClientPlayer;
|
||||||
import ru.windcorp.progressia.server.world.io.WorldContainer;
|
import ru.windcorp.progressia.server.world.io.WorldContainer;
|
||||||
import ru.windcorp.progressia.test.TestContent;
|
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@ -125,7 +124,7 @@ public class RegionWorldContainer implements WorldContainer {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityData player = EntityDataRegistry.getInstance().create("Test:Player");
|
EntityData player = EntityDataRegistry.getInstance().create("Core:Player");
|
||||||
try (
|
try (
|
||||||
DataInputStream dataInputStream = new DataInputStream(
|
DataInputStream dataInputStream = new DataInputStream(
|
||||||
new BufferedInputStream(
|
new BufferedInputStream(
|
||||||
@ -136,7 +135,6 @@ public class RegionWorldContainer implements WorldContainer {
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
player.read(dataInputStream, IOContext.SAVE);
|
player.read(dataInputStream, IOContext.SAVE);
|
||||||
player.setEntityId(TestContent.PLAYER_ENTITY_ID);
|
|
||||||
return new Player(player, server, clientPlayer);
|
return new Player(player, server, clientPlayer);
|
||||||
} catch (IOException ioException) {
|
} catch (IOException ioException) {
|
||||||
throw CrashReports.report(ioException, "Could not load player data: " + login);
|
throw CrashReports.report(ioException, "Could not load player data: " + login);
|
||||||
|
@ -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.texture.TexturePrimitive;
|
||||||
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
|
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
|
||||||
import ru.windcorp.progressia.client.world.entity.HumanoidModel;
|
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.EntityRenderRegistry;
|
||||||
import ru.windcorp.progressia.client.world.entity.EntityRenderable;
|
import ru.windcorp.progressia.client.world.entity.EntityRenderable;
|
||||||
import ru.windcorp.progressia.common.util.FloatMathUtil;
|
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.*;
|
import static java.lang.Math.*;
|
||||||
|
|
||||||
public class TestEntityRenderHuman extends EntityRender {
|
public class HumanModelFactory {
|
||||||
|
|
||||||
private static final float SECOND_LAYER_OFFSET = 1 / 12f;
|
private static final float SECOND_LAYER_OFFSET = 1 / 12f;
|
||||||
|
|
||||||
@ -51,9 +50,7 @@ public class TestEntityRenderHuman extends EntityRender {
|
|||||||
|
|
||||||
private final TexturePrimitive skin;
|
private final TexturePrimitive skin;
|
||||||
|
|
||||||
public TestEntityRenderHuman(String id) {
|
public HumanModelFactory() {
|
||||||
super(id);
|
|
||||||
|
|
||||||
this.skin = fetchSkin();
|
this.skin = fetchSkin();
|
||||||
|
|
||||||
ComplexTexture texture = new ComplexTexture(
|
ComplexTexture texture = new ComplexTexture(
|
||||||
@ -203,8 +200,7 @@ public class TestEntityRenderHuman extends EntityRender {
|
|||||||
return b.build();
|
return b.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public EntityRenderable createRenderable(EntityDataPlayer entity) {
|
||||||
public EntityRenderable createRenderable(EntityData entity) {
|
|
||||||
return new HumanoidModel(
|
return new HumanoidModel(
|
||||||
entity,
|
entity,
|
||||||
|
|
||||||
@ -237,7 +233,7 @@ public class TestEntityRenderHuman extends EntityRender {
|
|||||||
0.0f
|
0.0f
|
||||||
),
|
),
|
||||||
|
|
||||||
1.8f / (3 + 3 + 2)
|
SpeciesDataHuman.HEIGHT / (3 + 3 + 2)
|
||||||
)
|
)
|
||||||
.setWalkingArmSwing((float) toRadians(30))
|
.setWalkingArmSwing((float) toRadians(30))
|
||||||
.setWalkingLegSwing((float) toRadians(50))
|
.setWalkingLegSwing((float) toRadians(50))
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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(new EquipmentSlot("Backpack", i -> true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CollisionModel getCollisionModel() {
|
||||||
|
return new AABB(0, 0, HEIGHT / 2, WIDTH, WIDTH, HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.test;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.InventoryHUD;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.HandsHUD;
|
||||||
|
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.EquipmentSlot;
|
||||||
|
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 HandsHUD.Side getHandSide(Hand hand) {
|
||||||
|
return hand.getIndex() == 0 ? HandsHUD.Side.RIGHT : HandsHUD.Side.LEFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InventoryHUD.Side getEquipmentSlotSide(EquipmentSlot equipmentSlot) {
|
||||||
|
return InventoryHUD.Side.LEFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -21,6 +21,7 @@ import glm.vec._3.Vec3;
|
|||||||
import glm.vec._3.i.Vec3i;
|
import glm.vec._3.i.Vec3i;
|
||||||
import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
|
import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
|
||||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
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.BlockLogic;
|
||||||
import ru.windcorp.progressia.server.world.block.TickableBlock;
|
import ru.windcorp.progressia.server.world.block.TickableBlock;
|
||||||
import ru.windcorp.progressia.server.world.context.ServerBlockContext;
|
import ru.windcorp.progressia.server.world.context.ServerBlockContext;
|
||||||
@ -36,7 +37,7 @@ public class TestBlockLogicStatieSpawner extends BlockLogic implements TickableB
|
|||||||
@Override
|
@Override
|
||||||
public void tick(ServerBlockContext context) {
|
public void tick(ServerBlockContext context) {
|
||||||
Vec3i loc = context.toAbsolute(context.getLocation(), null);
|
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));
|
entity.setPosition(new Vec3(loc.x, loc.y, loc.z));
|
||||||
|
|
||||||
context.addEntity(entity);
|
context.addEntity(entity);
|
||||||
|
@ -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.block.BlockRenderRegistry.getBlockTexture;
|
||||||
import static ru.windcorp.progressia.client.world.tile.TileRenderRegistry.getTileTexture;
|
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.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -27,21 +28,33 @@ import java.util.Comparator;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.HUDWorkspace;
|
||||||
import ru.windcorp.progressia.client.world.block.*;
|
import ru.windcorp.progressia.client.world.block.*;
|
||||||
import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerRegistry;
|
import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerRegistry;
|
||||||
import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSimple;
|
import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSimple;
|
||||||
import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSurface;
|
import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSurface;
|
||||||
import ru.windcorp.progressia.client.world.entity.*;
|
import ru.windcorp.progressia.client.world.entity.*;
|
||||||
|
import ru.windcorp.progressia.client.world.item.ItemRender;
|
||||||
|
import ru.windcorp.progressia.client.world.item.ItemRenderRegistry;
|
||||||
|
import ru.windcorp.progressia.client.world.item.ItemRenderSimple;
|
||||||
|
import ru.windcorp.progressia.client.world.item.inventory.InventoryComponent;
|
||||||
|
import ru.windcorp.progressia.client.world.item.inventory.InventoryComponentSimple;
|
||||||
|
import ru.windcorp.progressia.client.world.item.inventory.InventoryRender;
|
||||||
|
import ru.windcorp.progressia.client.world.item.inventory.InventoryRenderRegistry;
|
||||||
import ru.windcorp.progressia.client.world.tile.*;
|
import ru.windcorp.progressia.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.collision.CollisionModel;
|
||||||
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.GravityModelRegistry;
|
||||||
import ru.windcorp.progressia.common.world.block.*;
|
import ru.windcorp.progressia.common.world.block.*;
|
||||||
import ru.windcorp.progressia.common.world.entity.*;
|
import ru.windcorp.progressia.common.world.entity.*;
|
||||||
import ru.windcorp.progressia.common.world.io.ChunkIO;
|
import ru.windcorp.progressia.common.world.io.ChunkIO;
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemData;
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemDataContainer;
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemDataRegistry;
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemDataSimple;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.Inventory;
|
||||||
import ru.windcorp.progressia.common.world.tile.*;
|
import ru.windcorp.progressia.common.world.tile.*;
|
||||||
import ru.windcorp.progressia.server.world.block.*;
|
import ru.windcorp.progressia.server.world.block.*;
|
||||||
import ru.windcorp.progressia.server.world.entity.*;
|
import ru.windcorp.progressia.server.world.entity.*;
|
||||||
@ -57,8 +70,6 @@ import ru.windcorp.progressia.test.trees.BlockRenderLeavesPine;
|
|||||||
public class TestContent {
|
public class TestContent {
|
||||||
|
|
||||||
public static final String PLAYER_LOGIN = "Sasha";
|
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<BlockData> PLACEABLE_BLOCKS = new ArrayList<>();
|
public static final List<BlockData> PLACEABLE_BLOCKS = new ArrayList<>();
|
||||||
public static final List<TileData> PLACEABLE_TILES = new ArrayList<>();
|
public static final List<TileData> PLACEABLE_TILES = new ArrayList<>();
|
||||||
@ -75,6 +86,7 @@ public class TestContent {
|
|||||||
private static void registerWorldContent() {
|
private static void registerWorldContent() {
|
||||||
registerBlocks();
|
registerBlocks();
|
||||||
registerTiles();
|
registerTiles();
|
||||||
|
registerItems();
|
||||||
registerEntities();
|
registerEntities();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,6 +246,26 @@ public class TestContent {
|
|||||||
FLOWERS.registerAllFlowers();
|
FLOWERS.registerAllFlowers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void registerItems() {
|
||||||
|
registerSimplestItem("MoonTypeIceCream", Units.get("200 g"), Units.get("1 L"));
|
||||||
|
registerSimplestItem("Stick", Units.get("260 g"), Units.get("0.5 L"));
|
||||||
|
registerSimplestItem("RedGraniteCobblestone", Units.get("4 kg"), Units.get("1500 cm^3"));
|
||||||
|
|
||||||
|
registerItem(
|
||||||
|
"Test:CardboardBackpack",
|
||||||
|
s -> new ItemDataContainer(
|
||||||
|
"Test:CardboardBackpack",
|
||||||
|
Units.get("0.7 kg"), // Own mass
|
||||||
|
Units.get("5 kg"), // Container mass limit
|
||||||
|
Units.get("125 L"), // Own volume
|
||||||
|
Units.get("125 L"), // Container volume limit
|
||||||
|
false // Whether container contents contribute to item volume
|
||||||
|
)
|
||||||
|
);
|
||||||
|
register(new ItemRenderSimple("Test:CardboardBackpack", getItemTexture("CardboardBackpack")));
|
||||||
|
registerSimplestInventory("Test:CardboardBackpack");
|
||||||
|
}
|
||||||
|
|
||||||
private static void registerSimplestBlock(String name) {
|
private static void registerSimplestBlock(String name) {
|
||||||
String id = "Test:" + name;
|
String id = "Test:" + name;
|
||||||
register(new BlockData(id));
|
register(new BlockData(id));
|
||||||
@ -262,21 +294,41 @@ public class TestContent {
|
|||||||
register(new HangingTileLogic(id));
|
register(new HangingTileLogic(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void registerEntities() {
|
private static void registerSimplestItem(String name, float mass, float volume) {
|
||||||
float scale = 1.8f / 8;
|
String id = "Test:" + name;
|
||||||
registerEntityData("Test:Player", e -> e.setCollisionModel(new AABB(0, 0, 4 * scale, 0.8f, 0.8f, 1.8f)));
|
registerItem(id, s -> new ItemDataSimple(s, mass, volume));
|
||||||
register(new TestEntityRenderHuman("Test:Player"));
|
register(new ItemRenderSimple(id, getItemTexture(name)));
|
||||||
register(new EntityLogic("Test:Player"));
|
}
|
||||||
|
|
||||||
register("Test:Statie", TestEntityDataStatie::new);
|
private static void registerEntities() {
|
||||||
|
registerPlayer();
|
||||||
|
|
||||||
|
registerEntity("Test:Statie", TestEntityDataStatie::new);
|
||||||
register(new TestEntityRenderStatie("Test:Statie"));
|
register(new TestEntityRenderStatie("Test:Statie"));
|
||||||
register(new TestEntityLogicStatie("Test:Statie"));
|
register(new TestEntityLogicStatie("Test:Statie"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void registerSimplestInventory(String id) {
|
||||||
|
InventoryRenderRegistry.getInstance().register(new InventoryRender(id) {
|
||||||
|
@Override
|
||||||
|
public InventoryComponent createComponent(Inventory inventory, HUDWorkspace workspace) {
|
||||||
|
return new InventoryComponentSimple(id, inventory, workspace);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void registerPlayer() {
|
||||||
|
SpeciesData human = new SpeciesDataHuman("Core:Human");
|
||||||
|
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() {
|
private static void regsiterControls() {
|
||||||
TestPlayerControls.getInstance().registerControls();
|
TestPlayerControls.getInstance().registerControls();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void register(BlockData x) {
|
private static void register(BlockData x) {
|
||||||
@ -287,25 +339,15 @@ public class TestContent {
|
|||||||
TileDataRegistry.getInstance().register(x);
|
TileDataRegistry.getInstance().register(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void register(
|
private static void registerItem(String id, IdFactory<ItemData> factory) {
|
||||||
String id,
|
ItemDataRegistry.getInstance().register(id, factory);
|
||||||
Factory<EntityData> factory
|
|
||||||
) {
|
|
||||||
EntityDataRegistry.getInstance().register(id, factory);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void registerEntityData(
|
private static void registerEntity(
|
||||||
String id,
|
String id,
|
||||||
Consumer<EntityData> transform
|
IdFactory<EntityData> factory
|
||||||
) {
|
) {
|
||||||
EntityDataRegistry.getInstance().register(id, new Factory<EntityData>() {
|
EntityDataRegistry.getInstance().register(id, factory);
|
||||||
@Override
|
|
||||||
public EntityData build() {
|
|
||||||
EntityData entity = new EntityData(id);
|
|
||||||
transform.accept(entity);
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void register(BlockRender x) {
|
private static void register(BlockRender x) {
|
||||||
@ -316,6 +358,10 @@ public class TestContent {
|
|||||||
TileRenderRegistry.getInstance().register(x);
|
TileRenderRegistry.getInstance().register(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void register(ItemRender x) {
|
||||||
|
ItemRenderRegistry.getInstance().register(x);
|
||||||
|
}
|
||||||
|
|
||||||
private static void register(EntityRender x) {
|
private static void register(EntityRender x) {
|
||||||
EntityRenderRegistry.getInstance().register(x);
|
EntityRenderRegistry.getInstance().register(x);
|
||||||
}
|
}
|
||||||
|
@ -26,10 +26,6 @@ public class TestEntityDataStatie extends EntityData {
|
|||||||
|
|
||||||
private final IntStateField size = field("Test:Size").setShared().ofInt().build();
|
private final IntStateField size = field("Test:Size").setShared().ofInt().build();
|
||||||
|
|
||||||
public TestEntityDataStatie() {
|
|
||||||
this("Test:Statie");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected TestEntityDataStatie(String id) {
|
protected TestEntityDataStatie(String id) {
|
||||||
super(id);
|
super(id);
|
||||||
setCollisionModel(new AABB(0, 0, 0, 1, 1, 1));
|
setCollisionModel(new AABB(0, 0, 0, 1, 1, 1));
|
||||||
|
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.test.controls;
|
||||||
|
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.Client;
|
||||||
|
import ru.windcorp.progressia.client.ClientState;
|
||||||
|
import ru.windcorp.progressia.client.comms.controls.ControlTriggerRegistry;
|
||||||
|
import ru.windcorp.progressia.client.comms.controls.ControlTriggers;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.KeyMatcher;
|
||||||
|
import ru.windcorp.progressia.common.Units;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
|
||||||
|
|
||||||
|
public class InventoryControls {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum duration of a ctrl stroke for it to be consider holding the key down
|
||||||
|
*/
|
||||||
|
private static final double MIN_CTRL_HOLD_LENGTH = Units.get("200 ms");
|
||||||
|
|
||||||
|
private double lastCtrlPress;
|
||||||
|
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
lastCtrlPress = Double.NEGATIVE_INFINITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerControls() {
|
||||||
|
ControlTriggerRegistry triggers = ControlTriggerRegistry.getInstance();
|
||||||
|
|
||||||
|
triggers.register(
|
||||||
|
ControlTriggers.localOf(
|
||||||
|
"Test:ToggleInventory",
|
||||||
|
KeyEvent.class,
|
||||||
|
this::toggleInventory,
|
||||||
|
new KeyMatcher("E")::matches
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
triggers.register(
|
||||||
|
ControlTriggers.localOf(
|
||||||
|
"Test:HideHUD",
|
||||||
|
KeyEvent.class,
|
||||||
|
this::switchHUD,
|
||||||
|
new KeyMatcher("F1")::matches
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
triggers.register(
|
||||||
|
ControlTriggers.localOf(
|
||||||
|
"Test:SwitchHandsWithCtrl",
|
||||||
|
KeyEvent.class,
|
||||||
|
this::switchHandsWithCtrl,
|
||||||
|
e -> !e.isRepeat(),
|
||||||
|
e -> e.getKey() == GLFW.GLFW_KEY_LEFT_CONTROL || e.getKey() == GLFW.GLFW_KEY_RIGHT_CONTROL
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void toggleInventory() {
|
||||||
|
Client client = ClientState.getInstance();
|
||||||
|
if (client == null || !client.isReady())
|
||||||
|
return;
|
||||||
|
|
||||||
|
client.getHUD().setInventoryShown(!client.getHUD().isInventoryShown());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void switchHUD() {
|
||||||
|
Client client = ClientState.getInstance();
|
||||||
|
if (client == null || !client.isReady())
|
||||||
|
return;
|
||||||
|
|
||||||
|
client.getHUD().setHidden(!client.getHUD().isHidden());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void switchHandsWithCtrl(KeyEvent event) {
|
||||||
|
int change = 0;
|
||||||
|
|
||||||
|
if (event.isPress()) {
|
||||||
|
change = +1;
|
||||||
|
lastCtrlPress = event.getTime();
|
||||||
|
} else {
|
||||||
|
if (event.getTime() - lastCtrlPress > MIN_CTRL_HOLD_LENGTH) {
|
||||||
|
change = -1;
|
||||||
|
lastCtrlPress = Double.NEGATIVE_INFINITY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.hasShift()) {
|
||||||
|
change *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switchHands(change);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void switchHands(int change) {
|
||||||
|
if (change == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ClientState.getInstance() == null || !ClientState.getInstance().isReady()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityDataPlayer entity = ClientState.getInstance().getLocalPlayer().getEntity();
|
||||||
|
|
||||||
|
int selected = entity.getSelectedHandIndex();
|
||||||
|
int maxSelected = entity.getHandCount() - 1;
|
||||||
|
|
||||||
|
selected += change;
|
||||||
|
if (selected < 0) {
|
||||||
|
selected = maxSelected;
|
||||||
|
} else if (selected > maxSelected) {
|
||||||
|
selected = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.setSelectedHandIndexNow(selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user