Merge remote-tracking branch 'origin/master' into audio
# Conflicts: # src/main/java/ru/windcorp/progressia/client/ProgressiaClientMain.java
This commit is contained in:
commit
437566283c
1
.gitignore
vendored
1
.gitignore
vendored
@ -16,3 +16,4 @@ bin
|
||||
# Ignore MacOS
|
||||
**/.DS_Store
|
||||
.idea/
|
||||
run/
|
||||
|
@ -43,3 +43,4 @@ plugins {
|
||||
* Trove4j
|
||||
* java-graphics/glm - GLM ported to Java. _Maven Central contains an outdated version, a custom repository used instead_
|
||||
* Apache Commons Math (_not currently used_)
|
||||
* log4j
|
||||
|
10
build.gradle
10
build.gradle
@ -17,7 +17,11 @@ dependencies {
|
||||
|
||||
implementation 'ru.windcorp.fork.io.github.java-graphics:glm:1.0.1'
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
// log4j
|
||||
compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.13.3'
|
||||
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.13.3'
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
}
|
||||
|
||||
/*
|
||||
@ -70,4 +74,6 @@ dependencies {
|
||||
runtimeOnly "org.lwjgl:lwjgl-par::$lwjglNatives"
|
||||
runtimeOnly "org.lwjgl:lwjgl-stb::$lwjglNatives"
|
||||
if (lwjglNatives == "natives-macos") runtimeOnly "org.lwjgl:lwjgl-vulkan::$lwjglNatives"
|
||||
}
|
||||
}
|
||||
|
||||
// LWJGL END
|
BIN
pictures/jetbrains_ide.png
Normal file
BIN
pictures/jetbrains_ide.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
@ -0,0 +1,8 @@
|
||||
package ru.windcorp.jputil.functions;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface FloatSupplier {
|
||||
|
||||
float getAsFloat();
|
||||
|
||||
}
|
@ -1,21 +1,18 @@
|
||||
package ru.windcorp.progressia.client;
|
||||
|
||||
import glm.vec._3.Vec3;
|
||||
import ru.windcorp.progressia.client.comms.DefaultClientCommsListener;
|
||||
import ru.windcorp.progressia.client.comms.ServerCommsChannel;
|
||||
import ru.windcorp.progressia.client.graphics.world.Camera;
|
||||
import ru.windcorp.progressia.client.world.WorldRender;
|
||||
import ru.windcorp.progressia.common.world.WorldData;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
|
||||
public class Client {
|
||||
|
||||
private final WorldRender world;
|
||||
private EntityData localPlayer;
|
||||
|
||||
private final Camera camera = new Camera(
|
||||
new Vec3(-6, -6, 20),
|
||||
(float) Math.toRadians(-40), (float) Math.toRadians(-45),
|
||||
(float) Math.toRadians(70)
|
||||
);
|
||||
private final Camera camera = new Camera((float) Math.toRadians(70));
|
||||
|
||||
private final ServerCommsChannel comms;
|
||||
|
||||
@ -30,6 +27,14 @@ public class Client {
|
||||
return world;
|
||||
}
|
||||
|
||||
public EntityData getLocalPlayer() {
|
||||
return localPlayer;
|
||||
}
|
||||
|
||||
public void setLocalPlayer(EntityData localPlayer) {
|
||||
this.localPlayer = localPlayer;
|
||||
}
|
||||
|
||||
public Camera getCamera() {
|
||||
return camera;
|
||||
}
|
||||
|
@ -23,9 +23,14 @@ public class ClientState {
|
||||
public static void connectToLocalServer() {
|
||||
|
||||
WorldData world = new WorldData();
|
||||
Client client = new Client(world, new LocalServerCommsChannel(
|
||||
|
||||
LocalServerCommsChannel channel = new LocalServerCommsChannel(
|
||||
ServerState.getInstance()
|
||||
));
|
||||
);
|
||||
|
||||
Client client = new Client(world, channel);
|
||||
|
||||
channel.connect();
|
||||
|
||||
setInstance(client);
|
||||
|
||||
|
@ -6,26 +6,22 @@ import static ru.windcorp.progressia.client.world.tile.TileRenderRegistry.getTil
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.client.comms.controls.ControlTriggerOnKeyPress;
|
||||
import ru.windcorp.progressia.client.comms.controls.ControlTriggerRegistry;
|
||||
import ru.windcorp.progressia.client.comms.controls.*;
|
||||
import ru.windcorp.progressia.client.graphics.input.KeyMatcher;
|
||||
import ru.windcorp.progressia.client.world.block.*;
|
||||
import ru.windcorp.progressia.client.world.tile.TileRender;
|
||||
import ru.windcorp.progressia.client.world.tile.TileRenderGrass;
|
||||
import ru.windcorp.progressia.client.world.tile.TileRenderRegistry;
|
||||
import ru.windcorp.progressia.client.world.tile.TileRenderSimple;
|
||||
import ru.windcorp.progressia.common.comms.controls.ControlData;
|
||||
import ru.windcorp.progressia.common.comms.controls.ControlDataRegistry;
|
||||
import ru.windcorp.progressia.common.comms.controls.PacketControl;
|
||||
import ru.windcorp.progressia.client.world.entity.*;
|
||||
import ru.windcorp.progressia.client.world.tile.*;
|
||||
import ru.windcorp.progressia.common.comms.controls.*;
|
||||
import ru.windcorp.progressia.common.world.ChunkData;
|
||||
import ru.windcorp.progressia.common.world.block.*;
|
||||
import ru.windcorp.progressia.common.world.tile.TileData;
|
||||
import ru.windcorp.progressia.common.world.tile.TileDataRegistry;
|
||||
import ru.windcorp.progressia.common.world.entity.*;
|
||||
import ru.windcorp.progressia.common.world.tile.*;
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
import ru.windcorp.progressia.server.comms.Client;
|
||||
import ru.windcorp.progressia.server.comms.controls.ControlLogic;
|
||||
import ru.windcorp.progressia.server.comms.controls.ControlLogicRegistry;
|
||||
import ru.windcorp.progressia.server.comms.controls.*;
|
||||
import ru.windcorp.progressia.server.world.block.*;
|
||||
import ru.windcorp.progressia.server.world.entity.*;
|
||||
import ru.windcorp.progressia.server.world.tile.*;
|
||||
|
||||
public class TestContent {
|
||||
|
||||
@ -37,6 +33,7 @@ public class TestContent {
|
||||
private static void registerWorldContent() {
|
||||
registerBlocks();
|
||||
registerTiles();
|
||||
registerEntities();
|
||||
}
|
||||
|
||||
private static void registerBlocks() {
|
||||
@ -64,15 +61,25 @@ public class TestContent {
|
||||
private static void registerTiles() {
|
||||
register(new TileData("Test", "Grass"));
|
||||
register(new TileRenderGrass("Test", "Grass", getTileTexture("grass_top"), getTileTexture("grass_side")));
|
||||
register(new TileLogic("Test", "Grass"));
|
||||
|
||||
register(new TileData("Test", "Stones"));
|
||||
register(new TileRenderSimple("Test", "Stones", getTileTexture("stones")));
|
||||
register(new TileLogic("Test", "Stones"));
|
||||
|
||||
register(new TileData("Test", "YellowFlowers"));
|
||||
register(new TileRenderSimple("Test", "YellowFlowers", getTileTexture("yellow_flowers")));
|
||||
register(new TileLogic("Test", "YellowFlowers"));
|
||||
|
||||
register(new TileData("Test", "Sand"));
|
||||
register(new TileRenderSimple("Test", "Sand", getTileTexture("sand")));
|
||||
register(new TileLogic("Test", "Sand"));
|
||||
}
|
||||
|
||||
private static void registerEntities() {
|
||||
register(new EntityData("Test", "Javapony"));
|
||||
register(new TestEntityRenderJavapony());
|
||||
register(new EntityLogic("Test", "Javapony"));
|
||||
}
|
||||
|
||||
private static void regsiterControls() {
|
||||
@ -105,6 +112,10 @@ public class TestContent {
|
||||
TileDataRegistry.getInstance().register(x);
|
||||
}
|
||||
|
||||
private static void register(EntityData x) {
|
||||
EntityDataRegistry.getInstance().register(x);
|
||||
}
|
||||
|
||||
private static void register(BlockRender x) {
|
||||
BlockRenderRegistry.getInstance().register(x);
|
||||
}
|
||||
@ -113,12 +124,20 @@ public class TestContent {
|
||||
TileRenderRegistry.getInstance().register(x);
|
||||
}
|
||||
|
||||
private static void register(EntityRender x) {
|
||||
EntityRenderRegistry.getInstance().register(x);
|
||||
}
|
||||
|
||||
private static void register(BlockLogic x) {
|
||||
BlockLogicRegistry.getInstance().register(x);
|
||||
}
|
||||
|
||||
// private static void register(TileRender x) {
|
||||
// TileLogicRegistry.getInstance().register(x);
|
||||
// }
|
||||
private static void register(TileLogic x) {
|
||||
TileLogicRegistry.getInstance().register(x);
|
||||
}
|
||||
|
||||
private static void register(EntityLogic x) {
|
||||
EntityLogicRegistry.getInstance().register(x);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,342 @@
|
||||
package ru.windcorp.progressia.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import glm.vec._3.Vec3;
|
||||
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
||||
import ru.windcorp.progressia.client.graphics.backend.Usage;
|
||||
import ru.windcorp.progressia.client.graphics.model.Face;
|
||||
import ru.windcorp.progressia.client.graphics.model.Faces;
|
||||
import ru.windcorp.progressia.client.graphics.model.LambdaModel;
|
||||
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||
import ru.windcorp.progressia.client.graphics.model.Shape;
|
||||
import ru.windcorp.progressia.client.graphics.model.Shapes.PppBuilder;
|
||||
import ru.windcorp.progressia.client.graphics.model.StaticModel;
|
||||
import ru.windcorp.progressia.client.graphics.texture.ComplexTexture;
|
||||
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
|
||||
import ru.windcorp.progressia.client.world.entity.EntityRender;
|
||||
import ru.windcorp.progressia.client.world.entity.EntityRenderRegistry;
|
||||
import ru.windcorp.progressia.client.world.entity.EntityRenderable;
|
||||
import ru.windcorp.progressia.client.world.entity.QuadripedModel;
|
||||
import ru.windcorp.progressia.common.world.block.BlockFace;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
|
||||
public class TestEntityRenderJavapony extends EntityRender {
|
||||
|
||||
private final Renderable body;
|
||||
private final Renderable head;
|
||||
private final Renderable leftForeLeg;
|
||||
private final Renderable leftHindLeg;
|
||||
private final Renderable rightForeLeg;
|
||||
private final Renderable rightHindLeg;
|
||||
|
||||
public TestEntityRenderJavapony() {
|
||||
super("Test", "Javapony");
|
||||
|
||||
ComplexTexture texture = new ComplexTexture(
|
||||
EntityRenderRegistry.getEntityTexture("javapony"),
|
||||
256, 128
|
||||
);
|
||||
|
||||
this.body = createBody(texture);
|
||||
this.head = createHead(texture);
|
||||
this.leftForeLeg = createLeg(texture, 160, 0, true);
|
||||
this.rightForeLeg = createLeg(texture, 160, 0, false);
|
||||
this.leftHindLeg = createLeg(texture, 0, 0, true);
|
||||
this.rightHindLeg = createLeg(texture, 0, 0, false);
|
||||
}
|
||||
|
||||
private static Renderable createBody(ComplexTexture texture) {
|
||||
LambdaModel.Builder b = LambdaModel.lambdaBuilder();
|
||||
|
||||
b.addStaticPart(createMainBody(texture));
|
||||
|
||||
Texture tailStartTexture = texture.get(128, 96, 8, 32);
|
||||
|
||||
b.addStaticPart(
|
||||
new PppBuilder(
|
||||
WorldRenderProgram.getDefault(),
|
||||
BlockFace.mapToFaces(
|
||||
tailStartTexture, tailStartTexture,
|
||||
tailStartTexture, tailStartTexture,
|
||||
tailStartTexture, tailStartTexture
|
||||
)
|
||||
)
|
||||
.setOrigin(-60, -4, 14)
|
||||
.setDepth(32, 0, -16).setWidth(8).setHeight(8)
|
||||
.create()
|
||||
);
|
||||
|
||||
Texture neckTexture = texture.get(0, 48, 16, 16);
|
||||
|
||||
b.addStaticPart(
|
||||
new PppBuilder(
|
||||
WorldRenderProgram.getDefault(),
|
||||
BlockFace.mapToFaces(
|
||||
neckTexture, neckTexture, neckTexture,
|
||||
neckTexture, neckTexture, neckTexture
|
||||
)
|
||||
)
|
||||
.setOrigin(0, -8, 8)
|
||||
.setWidth(16).setDepth(16).setHeight(2, 0, 16)
|
||||
.create()
|
||||
);
|
||||
|
||||
b.addDynamicPart(
|
||||
createTail(texture),
|
||||
m -> m
|
||||
.translate(-60, 0, 24)
|
||||
.rotateX(0.05f * Math.sin(GraphicsInterface.getTime()))
|
||||
.rotateY(0.05f * Math.sin(Math.PI / 3 * GraphicsInterface.getTime()))
|
||||
);
|
||||
|
||||
return new LambdaModel(b);
|
||||
}
|
||||
|
||||
private static Renderable createMainBody(ComplexTexture texture) {
|
||||
WorldRenderProgram program = WorldRenderProgram.getDefault();
|
||||
List<Face> faces = new ArrayList<>();
|
||||
|
||||
final Vec3 color = new Vec3(1, 1, 1);
|
||||
|
||||
// F BODY
|
||||
faces.add(Faces.createRectangle(
|
||||
program, texture.get(80, 16, 32, 32), color,
|
||||
new Vec3(+16, -16, -16),
|
||||
new Vec3(0, +32, 0), new Vec3(0, 0, +32),
|
||||
false
|
||||
));
|
||||
|
||||
// NECK BASE
|
||||
faces.add(Faces.createRectangle(
|
||||
program, texture.get(80, 48, 32, 16), color,
|
||||
new Vec3(+16, -16, +16),
|
||||
new Vec3(0, +32, 0), new Vec3(-16, 0, 0),
|
||||
false
|
||||
));
|
||||
|
||||
// T BODY (BACK)
|
||||
faces.add(Faces.createRectangle(
|
||||
program, texture.get(128, 0, 32, 48), color,
|
||||
new Vec3(0, -16, +16),
|
||||
new Vec3(0, +32, 0), new Vec3(-48, 0, 0),
|
||||
false
|
||||
));
|
||||
|
||||
// BOTTOM B (upper)
|
||||
faces.add(Faces.createRectangle(
|
||||
program, texture.get(144, 48, 32, 16), color,
|
||||
new Vec3(-48, -16, 0),
|
||||
new Vec3(0, 32, 0), new Vec3(0, 0, 16),
|
||||
true
|
||||
));
|
||||
|
||||
// BOTTOM B (lower)
|
||||
faces.add(Faces.createRectangle(
|
||||
program, texture.get(144, 48, 32, 16), color,
|
||||
new Vec3(-48, -16, -16),
|
||||
new Vec3(0, 32, 0), new Vec3(0, 0, 16),
|
||||
true
|
||||
));
|
||||
|
||||
// BOTTOM B (stomach)
|
||||
faces.add(Faces.createRectangle(
|
||||
program, texture.get(144, 48, 32, 16), color,
|
||||
new Vec3(-48, -16, -16),
|
||||
new Vec3(0, 32, 0), new Vec3(16, 0, 0),
|
||||
false
|
||||
));
|
||||
|
||||
// STOMACH
|
||||
faces.add(Faces.createRectangle(
|
||||
program, texture.get(224, 96, 32, 32), color,
|
||||
new Vec3(-32, -16, -16),
|
||||
new Vec3(0, 32, 0), new Vec3(32, 0, 0),
|
||||
false
|
||||
));
|
||||
|
||||
// BOTTOM F
|
||||
faces.add(Faces.createRectangle(
|
||||
program, texture.get(112, 48, 32, 16), color,
|
||||
new Vec3(+16, -16, -16),
|
||||
new Vec3(0, 32, 0), new Vec3(-16, 0, 0),
|
||||
true
|
||||
));
|
||||
|
||||
// BODY L
|
||||
faces.add(Faces.createRectangle(
|
||||
program, texture.get(112, 16, 16, 32), color,
|
||||
new Vec3(+16, +16, -16),
|
||||
new Vec3(-16, 0, 0), new Vec3(0, 0, +32),
|
||||
false
|
||||
));
|
||||
|
||||
// BODY SIDES (left)
|
||||
faces.add(Faces.createRectangle(
|
||||
program, texture.get(96, 96, 32, 32), color,
|
||||
new Vec3(0, +16, -16),
|
||||
new Vec3(-32, 0, 0), new Vec3(0, 0, +32),
|
||||
false
|
||||
));
|
||||
|
||||
// QT MARK (left)
|
||||
faces.add(Faces.createRectangle(
|
||||
program, texture.get(16, 96, 16, 32), color,
|
||||
new Vec3(-32, +16, -16),
|
||||
new Vec3(-16, 0, 0), new Vec3(0, 0, +32),
|
||||
false
|
||||
));
|
||||
|
||||
// BODY R
|
||||
faces.add(Faces.createRectangle(
|
||||
program, texture.get(64, 16, 16, 32), color,
|
||||
new Vec3(0, -16, -16),
|
||||
new Vec3(+16, 0, 0), new Vec3(0, 0, +32),
|
||||
false
|
||||
));
|
||||
|
||||
// BODY SIDES (right)
|
||||
faces.add(Faces.createRectangle(
|
||||
program, texture.get(96, 96, 32, 32), color,
|
||||
new Vec3(0, -16, -16),
|
||||
new Vec3(-32, 0, 0), new Vec3(0, 0, +32),
|
||||
true
|
||||
));
|
||||
|
||||
// QT MARK (right)
|
||||
faces.add(Faces.createRectangle(
|
||||
program, texture.get(16, 96, 16, 32), color,
|
||||
new Vec3(-32, -16, -16),
|
||||
new Vec3(-16, 0, 0), new Vec3(0, 0, +32),
|
||||
true
|
||||
));
|
||||
|
||||
return new Shape(
|
||||
Usage.STATIC, program,
|
||||
faces.toArray(new Face[faces.size()])
|
||||
);
|
||||
}
|
||||
|
||||
private static Renderable createHead(ComplexTexture texture) {
|
||||
WorldRenderProgram program = WorldRenderProgram.getDefault();
|
||||
StaticModel.Builder b = StaticModel.builder();
|
||||
|
||||
// Head
|
||||
b.addPart(new PppBuilder(
|
||||
program, texture.getCuboidTextures(0, 64, 32)
|
||||
).setOrigin(-16, -16, 0).setSize(32).create());
|
||||
|
||||
final float hairOffset = 1f;
|
||||
|
||||
// Hair
|
||||
b.addPart(
|
||||
new PppBuilder(
|
||||
program, texture.getCuboidTextures(128, 64, 32)
|
||||
)
|
||||
.setOrigin(-16 - hairOffset, -16 - hairOffset, -hairOffset)
|
||||
.setSize(32 + 2*hairOffset)
|
||||
.create()
|
||||
);
|
||||
|
||||
// Right ear
|
||||
b.addPart(new PppBuilder(
|
||||
program, texture.getCuboidTextures(48, 128-80, 8)
|
||||
).setOrigin(-16 + 3, -16, 32).setSize(8).create());
|
||||
|
||||
// Left ear
|
||||
b.addPart(new PppBuilder(
|
||||
program, texture.getCuboidTextures(48, 128-80, 8)
|
||||
).setOrigin(-16 + 3, +16, 32).setSize(8, -8, 8).flip().create());
|
||||
|
||||
// Muzzle
|
||||
b.addPart(new PppBuilder(
|
||||
program, BlockFace.mapToFaces(
|
||||
texture.get(32, 64, 0, 0),
|
||||
texture.get(32, 64, 0, 0),
|
||||
texture.get(32 + 8, 64, 16, 8),
|
||||
texture.get(32, 64, 0, 0),
|
||||
texture.get(32, 64, 0, 0),
|
||||
texture.get(32, 64, 0, 0)
|
||||
)
|
||||
).setOrigin(16, -8, 0).setSize(4, 16, 8).create());
|
||||
|
||||
// Nose
|
||||
b.addPart(new PppBuilder(
|
||||
program, BlockFace.mapToFaces(
|
||||
texture.get(32, 64, 0, 0),
|
||||
texture.get(32, 64, 0, 0),
|
||||
texture.get(32 + 12, 64 + 8, 8, 4),
|
||||
texture.get(32, 64, 0, 0),
|
||||
texture.get(32, 64, 0, 0),
|
||||
texture.get(32, 64, 0, 0)
|
||||
)
|
||||
).setOrigin(16, -4, 8).setSize(4, 8, 4).create());
|
||||
|
||||
return new StaticModel(b);
|
||||
}
|
||||
|
||||
private static Renderable createLeg(
|
||||
ComplexTexture texture,
|
||||
int textureX, int textureY,
|
||||
boolean isLeft
|
||||
) {
|
||||
PppBuilder b = new PppBuilder(
|
||||
WorldRenderProgram.getDefault(),
|
||||
texture.getCuboidTextures(textureX, textureY, 16, 48, 16)
|
||||
)
|
||||
.setOrigin(-8, isLeft ? +8 : -8, -48)
|
||||
.setSize(16, isLeft ? -16 : +16, 48);
|
||||
|
||||
if (isLeft) b.flip();
|
||||
|
||||
return b.create();
|
||||
}
|
||||
|
||||
private static Renderable createTail(ComplexTexture texture) {
|
||||
WorldRenderProgram program = WorldRenderProgram.getDefault();
|
||||
StaticModel.Builder b = StaticModel.builder();
|
||||
|
||||
// Main tail
|
||||
b.addPart(new PppBuilder(
|
||||
program, BlockFace.mapToFaces(
|
||||
texture.get(128, 96, 16, 16),
|
||||
texture.get(128, 96, 16, 16),
|
||||
texture.get(128, 96, 16, 32),
|
||||
texture.get(128, 96, 16, 32),
|
||||
texture.get(144, 96, 16, 32),
|
||||
texture.get(144, 96, 16, 32)
|
||||
)
|
||||
).setOrigin(-8, -8, -32).setSize(16, 16, 32).create());
|
||||
|
||||
return new StaticModel(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRenderable createRenderable(EntityData entity) {
|
||||
return new QuadripedModel(
|
||||
entity,
|
||||
|
||||
new QuadripedModel.Body(body),
|
||||
new QuadripedModel.Head(
|
||||
head, new Vec3(12, 0, 20), 60, 45, new Vec3(16, 0, 20)
|
||||
),
|
||||
new QuadripedModel.Leg(
|
||||
leftForeLeg, new Vec3( 6, +8.1f, -16), 0.0f
|
||||
),
|
||||
new QuadripedModel.Leg(
|
||||
rightForeLeg, new Vec3( 6, -8.1f, -16), 2.5f
|
||||
),
|
||||
new QuadripedModel.Leg(
|
||||
leftHindLeg, new Vec3(-36, +8.2f, -16), 2.5f
|
||||
),
|
||||
new QuadripedModel.Leg(
|
||||
rightHindLeg, new Vec3(-36, -8.2f, -16), 0.0f
|
||||
),
|
||||
|
||||
1 / 96f
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -1,12 +1,18 @@
|
||||
package ru.windcorp.progressia.client.comms;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
import ru.windcorp.progressia.client.Client;
|
||||
import ru.windcorp.progressia.client.graphics.world.EntityAnchor;
|
||||
import ru.windcorp.progressia.client.world.ChunkRender;
|
||||
import ru.windcorp.progressia.common.comms.CommsListener;
|
||||
import ru.windcorp.progressia.common.comms.packets.Packet;
|
||||
import ru.windcorp.progressia.common.comms.packets.PacketSetLocalPlayer;
|
||||
import ru.windcorp.progressia.common.comms.packets.PacketWorldChange;
|
||||
import ru.windcorp.progressia.common.world.ChunkData;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
|
||||
public class DefaultClientCommsListener implements CommsListener {
|
||||
|
||||
@ -24,9 +30,41 @@ public class DefaultClientCommsListener implements CommsListener {
|
||||
);
|
||||
|
||||
tmp_reassembleWorld();
|
||||
} else if (packet instanceof PacketSetLocalPlayer) {
|
||||
setLocalPlayer((PacketSetLocalPlayer) packet);
|
||||
}
|
||||
}
|
||||
|
||||
private void setLocalPlayer(PacketSetLocalPlayer packet) {
|
||||
UUID uuid = packet.getLocalPlayerEntityUUID();
|
||||
|
||||
Collection<ChunkData> chunks =
|
||||
getClient().getWorld().getData().getChunks();
|
||||
|
||||
EntityData entity = null;
|
||||
|
||||
synchronized (chunks) {
|
||||
chunkLoop:
|
||||
for (ChunkData chunk : chunks) {
|
||||
for (EntityData anEntity : chunk.getEntities()) {
|
||||
if (anEntity.getUUID().equals(uuid)) {
|
||||
entity = anEntity;
|
||||
break chunkLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (entity == null) {
|
||||
throw new RuntimeException("");
|
||||
}
|
||||
|
||||
getClient().setLocalPlayer(entity);
|
||||
getClient().getCamera().setAnchor(new EntityAnchor(
|
||||
getClient().getWorld().getEntityRenderable(entity)
|
||||
));
|
||||
}
|
||||
|
||||
private void tmp_reassembleWorld() {
|
||||
getClient().getWorld().getChunks().forEach(ChunkRender::markForUpdate);
|
||||
}
|
||||
|
@ -6,10 +6,15 @@ import ru.windcorp.progressia.server.Server;
|
||||
|
||||
public class LocalServerCommsChannel extends ServerCommsChannel {
|
||||
|
||||
private final LocalClient localClient;
|
||||
private LocalClient localClient;
|
||||
private final Server server;
|
||||
|
||||
public LocalServerCommsChannel(Server server) {
|
||||
super(Role.GAME, Role.CHAT);
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public void connect() {
|
||||
setState(State.CONNECTED);
|
||||
|
||||
this.localClient = new LocalClient(
|
||||
|
@ -0,0 +1,27 @@
|
||||
package ru.windcorp.progressia.client.graphics.backend;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
|
||||
public class FaceCulling {
|
||||
|
||||
private static final Deque<Boolean> STACK = new ArrayDeque<>();
|
||||
|
||||
public static void push(boolean useFaceCulling) {
|
||||
GraphicsBackend.setFaceCulling(useFaceCulling);
|
||||
STACK.push(Boolean.valueOf(useFaceCulling));
|
||||
}
|
||||
|
||||
public static void pop() {
|
||||
STACK.pop();
|
||||
|
||||
if (STACK.isEmpty()) {
|
||||
GraphicsBackend.setFaceCulling(false);
|
||||
} else {
|
||||
GraphicsBackend.setFaceCulling(STACK.getFirst());
|
||||
}
|
||||
}
|
||||
|
||||
private FaceCulling() {}
|
||||
|
||||
}
|
@ -35,6 +35,8 @@ public class GraphicsBackend {
|
||||
private static long framesRendered = 0;
|
||||
private static double frameStart = Double.NaN;
|
||||
|
||||
private static boolean faceCullingEnabled = false;
|
||||
|
||||
private GraphicsBackend() {}
|
||||
|
||||
public static void initialize() {
|
||||
@ -109,5 +111,17 @@ public class GraphicsBackend {
|
||||
public static void startNextLayer() {
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
public static void setFaceCulling(boolean useFaceCulling) {
|
||||
if (useFaceCulling == faceCullingEnabled) return;
|
||||
|
||||
if (useFaceCulling) {
|
||||
glEnable(GL_CULL_FACE);
|
||||
} else {
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
|
||||
faceCullingEnabled = useFaceCulling;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -81,7 +81,6 @@ class LWJGLInitializer {
|
||||
private static void initializeOpenGL() {
|
||||
GL.createCapabilities();
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
package ru.windcorp.progressia.client.graphics.flat;
|
||||
|
||||
import ru.windcorp.progressia.client.graphics.Layer;
|
||||
import ru.windcorp.progressia.client.graphics.backend.FaceCulling;
|
||||
|
||||
public abstract class AssembledFlatLayer extends Layer {
|
||||
|
||||
@ -48,11 +49,15 @@ public abstract class AssembledFlatLayer extends Layer {
|
||||
|
||||
@Override
|
||||
protected void doRender() {
|
||||
FaceCulling.push(false);
|
||||
|
||||
for (RenderTarget.Clip clip : clips) {
|
||||
clip.render(helper);
|
||||
}
|
||||
|
||||
helper.reset();
|
||||
|
||||
FaceCulling.pop();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,8 +17,6 @@
|
||||
*******************************************************************************/
|
||||
package ru.windcorp.progressia.client.graphics.flat;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import com.google.common.collect.ObjectArrays;
|
||||
@ -81,9 +79,7 @@ public class FlatRenderProgram extends ShapeRenderProgram {
|
||||
|
||||
@Override
|
||||
public void render(ShapeRenderHelper helper, Shape shape) {
|
||||
glDisable(GL_CULL_FACE);
|
||||
super.render(helper, shape);
|
||||
glEnable(GL_CULL_FACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -30,6 +30,7 @@ import ru.windcorp.progressia.client.graphics.input.bus.Input;
|
||||
import ru.windcorp.progressia.client.graphics.model.LambdaModel;
|
||||
import ru.windcorp.progressia.client.graphics.texture.SimpleTextures;
|
||||
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||
import ru.windcorp.progressia.client.graphics.world.Camera;
|
||||
|
||||
public class LayerTestUI extends AssembledFlatLayer {
|
||||
|
||||
@ -73,7 +74,10 @@ public class LayerTestUI extends AssembledFlatLayer {
|
||||
target.addCustomRenderer(new LambdaModel(LambdaModel.lambdaBuilder()
|
||||
.addDynamicPart(
|
||||
target.createRectagle(0, 0, texSize, texSize, 0xFFFFFF, compassFg),
|
||||
mat -> mat.translate(texSize/2, texSize/2, 0).rotateZ(ClientState.getInstance().getCamera().getYaw()).translate(-texSize/2, -texSize/2, 0)
|
||||
mat ->
|
||||
mat.translate(texSize/2, texSize/2, 0)
|
||||
.rotateZ(getCompassRotation())
|
||||
.translate(-texSize/2, -texSize/2, 0)
|
||||
)
|
||||
));
|
||||
target.popTransform();
|
||||
@ -81,6 +85,15 @@ public class LayerTestUI extends AssembledFlatLayer {
|
||||
drawCross(target);
|
||||
}
|
||||
|
||||
private double getCompassRotation() {
|
||||
Camera.Anchor anchor =
|
||||
ClientState.getInstance().getCamera().getAnchor();
|
||||
|
||||
if (anchor == null) return 0;
|
||||
|
||||
return -anchor.getCameraYaw();
|
||||
}
|
||||
|
||||
private void drawCross(RenderTarget target) {
|
||||
int cx = getWidth() / 2;
|
||||
int cy = getHeight() / 2;
|
||||
|
@ -81,7 +81,7 @@ public class LayerTestGUI extends GUILayer {
|
||||
panel.addChild(new DebugComponent("Bravo", new Vec2i(200, 100), 0x44FF44));
|
||||
|
||||
Component charlie = new DebugComponent("Charlie", null, 0x222222);
|
||||
charlie.setLayout(new LayoutVertical());
|
||||
charlie.setLayout(new LayoutVertical(5));
|
||||
|
||||
//Debug
|
||||
Localizer.getInstance().setLanguage("ru-RU");
|
||||
@ -90,16 +90,16 @@ public class LayerTestGUI extends GUILayer {
|
||||
// These two are swapped in code due to a bug in layouts, fixing ATM
|
||||
charlie.addChild(
|
||||
new Label(
|
||||
"Epsilon",
|
||||
new Font().withColor(0x4444BB).deriveItalic(),
|
||||
() -> epsilon.get().concat("\u269b")
|
||||
"Delta",
|
||||
new Font().withColor(0xCCBB44).deriveShadow().deriveBold(),
|
||||
"Пре-альфа!"
|
||||
)
|
||||
);
|
||||
charlie.addChild(
|
||||
new Label(
|
||||
"Delta",
|
||||
new Font().withColor(0xCCBB44).deriveShadow().deriveBold(),
|
||||
"Пре-альфа!"
|
||||
"Epsilon",
|
||||
new Font().withColor(0x4444BB).deriveItalic(),
|
||||
() -> epsilon.get().concat("\u269b")
|
||||
)
|
||||
);
|
||||
panel.addChild(charlie);
|
||||
|
@ -43,16 +43,14 @@ public class LayoutVertical implements Layout {
|
||||
@Override
|
||||
public void layout(Component c) {
|
||||
int x = c.getX() + margin,
|
||||
y = c.getY() + margin;
|
||||
|
||||
int height;
|
||||
y = c.getY() + c.getHeight();
|
||||
|
||||
synchronized (c.getChildren()) {
|
||||
for (Component child : c.getChildren()) {
|
||||
|
||||
height = child.getPreferredSize().y;
|
||||
int height = child.getPreferredSize().y;
|
||||
y -= gap + height;
|
||||
child.setBounds(x, y, c.getWidth() - 2 * margin, height);
|
||||
y += gap + height;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -17,10 +17,13 @@
|
||||
*******************************************************************************/
|
||||
package ru.windcorp.progressia.client.graphics.model;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import glm.vec._3.Vec3;
|
||||
import ru.windcorp.progressia.client.graphics.backend.Usage;
|
||||
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||
import ru.windcorp.progressia.common.util.Vectors;
|
||||
import ru.windcorp.progressia.common.world.block.BlockFace;
|
||||
|
||||
public class Shapes {
|
||||
|
||||
@ -40,7 +43,9 @@ public class Shapes {
|
||||
Texture northTexture,
|
||||
Texture southTexture,
|
||||
Texture eastTexture,
|
||||
Texture westTexture
|
||||
Texture westTexture,
|
||||
|
||||
boolean flip
|
||||
) {
|
||||
|
||||
Vec3 faceOrigin = Vectors.grab3();
|
||||
@ -52,7 +57,7 @@ public class Shapes {
|
||||
faceOrigin.set(origin).add(height).add(width),
|
||||
faceWidth.set(width).negate(),
|
||||
depth,
|
||||
false
|
||||
flip
|
||||
);
|
||||
|
||||
Face bottom = Faces.createRectangle(
|
||||
@ -61,7 +66,7 @@ public class Shapes {
|
||||
origin,
|
||||
width,
|
||||
depth,
|
||||
false
|
||||
flip
|
||||
);
|
||||
|
||||
Face north = Faces.createRectangle(
|
||||
@ -70,7 +75,7 @@ public class Shapes {
|
||||
faceOrigin.set(origin).add(depth),
|
||||
width,
|
||||
height,
|
||||
false
|
||||
flip
|
||||
);
|
||||
|
||||
Face south = Faces.createRectangle(
|
||||
@ -79,7 +84,7 @@ public class Shapes {
|
||||
faceOrigin.set(origin).add(width),
|
||||
faceWidth.set(width).negate(),
|
||||
height,
|
||||
false
|
||||
flip
|
||||
);
|
||||
|
||||
Face east = Faces.createRectangle(
|
||||
@ -88,7 +93,7 @@ public class Shapes {
|
||||
origin,
|
||||
depth,
|
||||
height,
|
||||
false
|
||||
flip
|
||||
);
|
||||
|
||||
Face west = Faces.createRectangle(
|
||||
@ -97,7 +102,7 @@ public class Shapes {
|
||||
faceOrigin.set(origin).add(width).add(depth),
|
||||
faceWidth.set(depth).negate(),
|
||||
height,
|
||||
false
|
||||
flip
|
||||
);
|
||||
|
||||
Shape result = new Shape(
|
||||
@ -131,6 +136,8 @@ public class Shapes {
|
||||
private final Texture eastTexture;
|
||||
private final Texture westTexture;
|
||||
|
||||
private boolean flip = false;
|
||||
|
||||
public PppBuilder(
|
||||
ShapeRenderProgram program,
|
||||
Texture top,
|
||||
@ -149,6 +156,21 @@ public class Shapes {
|
||||
this.westTexture = west;
|
||||
}
|
||||
|
||||
public PppBuilder(
|
||||
ShapeRenderProgram program,
|
||||
Map<BlockFace, Texture> textureMap
|
||||
) {
|
||||
this(
|
||||
program,
|
||||
textureMap.get(BlockFace.TOP),
|
||||
textureMap.get(BlockFace.BOTTOM),
|
||||
textureMap.get(BlockFace.NORTH),
|
||||
textureMap.get(BlockFace.SOUTH),
|
||||
textureMap.get(BlockFace.EAST),
|
||||
textureMap.get(BlockFace.WEST)
|
||||
);
|
||||
}
|
||||
|
||||
public PppBuilder(ShapeRenderProgram program, Texture texture) {
|
||||
this(program, texture, texture, texture, texture, texture, texture);
|
||||
}
|
||||
@ -219,7 +241,16 @@ public class Shapes {
|
||||
}
|
||||
|
||||
public PppBuilder setSize(float x, float y, float z) {
|
||||
return this.setWidth(x).setDepth(y).setHeight(z);
|
||||
return this.setDepth(x).setWidth(y).setHeight(z);
|
||||
}
|
||||
|
||||
public PppBuilder setSize(float size) {
|
||||
return this.setSize(size, size, size);
|
||||
}
|
||||
|
||||
public PppBuilder flip() {
|
||||
this.flip = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Shape create() {
|
||||
@ -233,7 +264,8 @@ public class Shapes {
|
||||
northTexture,
|
||||
southTexture,
|
||||
eastTexture,
|
||||
westTexture
|
||||
westTexture,
|
||||
flip
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,66 @@
|
||||
package ru.windcorp.progressia.client.graphics.texture;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import glm.vec._2.Vec2;
|
||||
import ru.windcorp.progressia.common.world.block.BlockFace;
|
||||
|
||||
public class ComplexTexture {
|
||||
|
||||
private final TexturePrimitive primitive;
|
||||
|
||||
private final float assumedWidth;
|
||||
private final float assumedHeight;
|
||||
|
||||
public ComplexTexture(
|
||||
TexturePrimitive primitive,
|
||||
int abstractWidth, int abstractHeight
|
||||
) {
|
||||
this.primitive = primitive;
|
||||
|
||||
this.assumedWidth = abstractWidth
|
||||
* primitive.getWidth() / (float) primitive.getBufferWidth();
|
||||
|
||||
this.assumedHeight = abstractHeight
|
||||
* primitive.getHeight() / (float) primitive.getBufferHeight();
|
||||
}
|
||||
|
||||
public Texture get(int x, int y, int width, int height) {
|
||||
return new SimpleTexture(new Sprite(
|
||||
primitive,
|
||||
new Vec2(x / assumedWidth, y / assumedHeight),
|
||||
new Vec2(width / assumedWidth, height / assumedHeight)
|
||||
));
|
||||
}
|
||||
|
||||
public Map<BlockFace, Texture> getCuboidTextures(
|
||||
int x, int y,
|
||||
int width, int height, int depth
|
||||
) {
|
||||
return BlockFace.mapToFaces(
|
||||
get(
|
||||
x + depth + width, y + height + depth,
|
||||
-width, -depth
|
||||
),
|
||||
get(
|
||||
x + depth + width + width, y + height + depth,
|
||||
-width, -depth
|
||||
),
|
||||
get(x + depth, y, width, height),
|
||||
get(
|
||||
x + depth + width + depth, y,
|
||||
width, height
|
||||
),
|
||||
get(x, y, depth, height),
|
||||
get(x + depth + width, y, depth, height)
|
||||
);
|
||||
}
|
||||
|
||||
public Map<BlockFace, Texture> getCuboidTextures(
|
||||
int x, int y,
|
||||
int size
|
||||
) {
|
||||
return getCuboidTextures(x, y, size, size, size);
|
||||
}
|
||||
|
||||
}
|
@ -19,24 +19,62 @@ package ru.windcorp.progressia.client.graphics.world;
|
||||
|
||||
import static java.lang.Math.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import glm.Glm;
|
||||
import glm.mat._4.Mat4;
|
||||
import glm.vec._3.Vec3;
|
||||
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
||||
import ru.windcorp.progressia.client.graphics.world.Camera.Anchor.Mode;
|
||||
import ru.windcorp.progressia.common.util.Vectors;
|
||||
|
||||
public class Camera {
|
||||
|
||||
private final Vec3 position = new Vec3();
|
||||
public static interface Anchor {
|
||||
|
||||
/**
|
||||
* Offset is applied after the rotation.
|
||||
*/
|
||||
public static interface Mode {
|
||||
void getCameraOffset(Vec3 output);
|
||||
void applyCameraRotation(Mat4 output);
|
||||
|
||||
public static Mode of(
|
||||
Consumer<Vec3> offsetGetter,
|
||||
Consumer<Mat4> rotator
|
||||
) {
|
||||
return new Mode() {
|
||||
@Override
|
||||
public void getCameraOffset(Vec3 output) {
|
||||
offsetGetter.accept(output);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyCameraRotation(Mat4 output) {
|
||||
rotator.accept(output);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void getCameraPosition(Vec3 output);
|
||||
void getCameraVelocity(Vec3 output);
|
||||
float getCameraYaw();
|
||||
float getCameraPitch();
|
||||
|
||||
Collection<Mode> getCameraModes();
|
||||
|
||||
}
|
||||
|
||||
private float pitch;
|
||||
private float yaw;
|
||||
private Anchor anchor;
|
||||
|
||||
private Anchor.Mode[] modes;
|
||||
private int currentModeIndex;
|
||||
|
||||
private float fieldOfView;
|
||||
|
||||
public Camera(Vec3 position, float pitch, float yaw, float fieldOfView) {
|
||||
teleport(position);
|
||||
setPitch(pitch);
|
||||
setYaw(yaw);
|
||||
public Camera(float fieldOfView) {
|
||||
setFieldOfView(fieldOfView);
|
||||
}
|
||||
|
||||
@ -46,6 +84,7 @@ public class Camera {
|
||||
applyPerspective(helper);
|
||||
rotateCoordinateSystem(helper);
|
||||
|
||||
applyMode(helper);
|
||||
applyDirection(helper);
|
||||
applyPosition(helper);
|
||||
}
|
||||
@ -64,14 +103,38 @@ public class Camera {
|
||||
private void rotateCoordinateSystem(WorldRenderHelper helper) {
|
||||
helper.pushViewTransform().rotateX(-PI / 2).rotateZ(PI / 2);
|
||||
}
|
||||
|
||||
private void applyMode(WorldRenderHelper helper) {
|
||||
Mode mode = getMode();
|
||||
|
||||
Mat4 matrix = helper.pushViewTransform();
|
||||
|
||||
Vec3 offset = Vectors.grab3();
|
||||
mode.getCameraOffset(offset);
|
||||
|
||||
offset.negate();
|
||||
matrix.translate(offset);
|
||||
|
||||
Vectors.release(offset);
|
||||
|
||||
mode.applyCameraRotation(matrix);
|
||||
}
|
||||
|
||||
private void applyDirection(WorldRenderHelper helper) {
|
||||
helper.pushViewTransform().rotateY(pitch).rotateZ(yaw);
|
||||
helper.pushViewTransform()
|
||||
.rotateY(-anchor.getCameraPitch())
|
||||
.rotateZ(-anchor.getCameraYaw());
|
||||
}
|
||||
|
||||
private void applyPosition(WorldRenderHelper helper) {
|
||||
helper.pushViewTransform().translate(position.negate());
|
||||
position.negate();
|
||||
Vec3 v = Vectors.grab3();
|
||||
|
||||
anchor.getCameraPosition(v);
|
||||
v.negate();
|
||||
|
||||
helper.pushViewTransform().translate(v);
|
||||
|
||||
Vectors.release(v);
|
||||
}
|
||||
|
||||
private float computeFovY() {
|
||||
@ -87,45 +150,6 @@ public class Camera {
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
public Vec3 getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void teleport(Vec3 pos) {
|
||||
position.set(pos);
|
||||
}
|
||||
|
||||
public void move(Vec3 pos) {
|
||||
position.add(pos);
|
||||
}
|
||||
|
||||
public float getPitch() {
|
||||
return pitch;
|
||||
}
|
||||
|
||||
public void setPitch(float pitch) {
|
||||
final float maxPitch = (float) (Math.PI / 2);
|
||||
this.pitch = Glm.clamp(pitch, -maxPitch, +maxPitch);
|
||||
}
|
||||
|
||||
public float getYaw() {
|
||||
return yaw;
|
||||
}
|
||||
|
||||
public void setYaw(float yaw) {
|
||||
this.yaw = Glm.mod(yaw, 2 * (float) PI);
|
||||
}
|
||||
|
||||
public void setDirection(float pitch, float yaw) {
|
||||
setPitch(pitch);
|
||||
setYaw(yaw);
|
||||
}
|
||||
|
||||
public void turn(float pitchChange, float yawChange) {
|
||||
setPitch(getPitch() + pitchChange);
|
||||
setYaw(getYaw() + yawChange);
|
||||
}
|
||||
|
||||
public float getFieldOfView() {
|
||||
return fieldOfView;
|
||||
@ -134,5 +158,47 @@ public class Camera {
|
||||
public void setFieldOfView(float fieldOfView) {
|
||||
this.fieldOfView = fieldOfView;
|
||||
}
|
||||
|
||||
public Anchor getAnchor() {
|
||||
return anchor;
|
||||
}
|
||||
|
||||
public boolean hasAnchor() {
|
||||
return anchor != null;
|
||||
}
|
||||
|
||||
public void setAnchor(Anchor anchor) {
|
||||
if (anchor == null) {
|
||||
this.anchor = null;
|
||||
this.modes = null;
|
||||
return;
|
||||
}
|
||||
|
||||
Collection<Mode> modesCollection = anchor.getCameraModes();
|
||||
|
||||
if (modesCollection.isEmpty()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Anchor " + anchor + " returned no camera modes,"
|
||||
+ " at least one required"
|
||||
);
|
||||
}
|
||||
|
||||
this.anchor = anchor;
|
||||
|
||||
this.modes = modesCollection.toArray(new Mode[modesCollection.size()]);
|
||||
this.currentModeIndex = 0;
|
||||
}
|
||||
|
||||
public Anchor.Mode getMode() {
|
||||
return modes[currentModeIndex];
|
||||
}
|
||||
|
||||
public void selectNextMode() {
|
||||
if (currentModeIndex == modes.length - 1) {
|
||||
currentModeIndex = 0;
|
||||
} else {
|
||||
currentModeIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,67 @@
|
||||
package ru.windcorp.progressia.client.graphics.world;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import glm.vec._3.Vec3;
|
||||
import ru.windcorp.progressia.client.graphics.world.Camera.Anchor;
|
||||
import ru.windcorp.progressia.client.world.entity.EntityRenderable;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
|
||||
public class EntityAnchor implements Anchor {
|
||||
|
||||
private final EntityData entity;
|
||||
private final EntityRenderable model;
|
||||
|
||||
private final Collection<Mode> modes;
|
||||
|
||||
public EntityAnchor(EntityRenderable model) {
|
||||
this.entity = model.getData();
|
||||
this.model = model;
|
||||
|
||||
this.modes = ImmutableList.of(
|
||||
// From viewpoint / first person
|
||||
Mode.of(v -> v.set(0), m -> {}),
|
||||
|
||||
// Third person, looking forward
|
||||
Mode.of(
|
||||
v -> v.set(-3.5f, +0.5f, 0),
|
||||
m -> {}
|
||||
),
|
||||
|
||||
// Third person, looking back
|
||||
Mode.of(
|
||||
v -> v.set(-3.5f, 0, 0),
|
||||
m -> m.rotateZ((float) Math.PI)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getCameraPosition(Vec3 output) {
|
||||
model.getViewPoint(output);
|
||||
output.add(entity.getPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getCameraVelocity(Vec3 output) {
|
||||
output.set(entity.getVelocity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCameraYaw() {
|
||||
return entity.getYaw();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCameraPitch() {
|
||||
return entity.getPitch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Mode> getCameraModes() {
|
||||
return modes;
|
||||
}
|
||||
|
||||
}
|
@ -19,18 +19,23 @@ package ru.windcorp.progressia.client.graphics.world;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import glm.Glm;
|
||||
import glm.mat._3.Mat3;
|
||||
import glm.vec._2.Vec2;
|
||||
import glm.vec._3.Vec3;
|
||||
import ru.windcorp.progressia.client.Client;
|
||||
import ru.windcorp.progressia.client.comms.controls.InputBasedControls;
|
||||
import ru.windcorp.progressia.client.graphics.Layer;
|
||||
import ru.windcorp.progressia.client.graphics.backend.FaceCulling;
|
||||
import ru.windcorp.progressia.client.graphics.backend.GraphicsBackend;
|
||||
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
||||
import ru.windcorp.progressia.client.graphics.input.CursorMoveEvent;
|
||||
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
||||
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
||||
import ru.windcorp.progressia.client.graphics.input.bus.Input;
|
||||
import ru.windcorp.progressia.common.util.FloatMathUtils;
|
||||
import ru.windcorp.progressia.common.util.Vectors;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
|
||||
public class LayerWorld extends Layer {
|
||||
|
||||
@ -66,11 +71,20 @@ public class LayerWorld extends Layer {
|
||||
|
||||
@Override
|
||||
protected void doRender() {
|
||||
client.getCamera().apply(helper);
|
||||
renderWorld();
|
||||
helper.reset();
|
||||
if (client.getLocalPlayer() != null) {
|
||||
tmp_handleControls();
|
||||
}
|
||||
|
||||
angMat.set().rotateZ(-client.getCamera().getYaw());
|
||||
Camera camera = client.getCamera();
|
||||
if (camera.hasAnchor()) {
|
||||
renderWorld();
|
||||
}
|
||||
}
|
||||
|
||||
private void tmp_handleControls() {
|
||||
EntityData player = client.getLocalPlayer();
|
||||
|
||||
angMat.set().rotateZ(player.getYaw());
|
||||
|
||||
Vec3 movement = Vectors.grab3();
|
||||
|
||||
@ -88,13 +102,21 @@ public class LayerWorld extends Layer {
|
||||
Vec3 velCopy = Vectors.grab3().set(velocity);
|
||||
|
||||
velCopy.mul((float) (GraphicsInterface.getFrameLength() * 60));
|
||||
client.getCamera().move(velCopy);
|
||||
|
||||
player.getPosition().add(velCopy);
|
||||
player.getVelocity().set(velocity);
|
||||
|
||||
Vectors.release(velCopy);
|
||||
}
|
||||
|
||||
private void renderWorld() {
|
||||
client.getCamera().apply(helper);
|
||||
FaceCulling.push(true);
|
||||
|
||||
this.client.getWorld().render(helper);
|
||||
|
||||
FaceCulling.pop();
|
||||
helper.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -156,6 +178,14 @@ public class LayerWorld extends Layer {
|
||||
flag = !flag;
|
||||
break;
|
||||
|
||||
case GLFW.GLFW_KEY_F5:
|
||||
if (!event.isPress()) return false;
|
||||
|
||||
if (client.getCamera().hasAnchor()) {
|
||||
client.getCamera().selectNextMode();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -166,12 +196,26 @@ public class LayerWorld extends Layer {
|
||||
private void onMouseMoved(CursorMoveEvent event) {
|
||||
if (!flag) return;
|
||||
|
||||
final float yawScale = 0.002f;
|
||||
final float yawScale = -0.002f;
|
||||
final float pitchScale = yawScale;
|
||||
|
||||
EntityData player = client.getLocalPlayer();
|
||||
|
||||
client.getCamera().turn(
|
||||
(float) (event.getChangeY() * pitchScale),
|
||||
(float) (event.getChangeX() * yawScale)
|
||||
if (player != null) {
|
||||
normalizeAngles(player.getDirection().add(
|
||||
(float) (event.getChangeX() * yawScale),
|
||||
(float) (event.getChangeY() * pitchScale)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private void normalizeAngles(Vec2 dir) {
|
||||
// Normalize yaw
|
||||
dir.x = FloatMathUtils.normalizeAngle(dir.x);
|
||||
|
||||
// Clamp pitch
|
||||
dir.y = Glm.clamp(
|
||||
dir.y, -FloatMathUtils.PI_F/2, +FloatMathUtils.PI_F/2
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -18,19 +18,27 @@
|
||||
package ru.windcorp.progressia.client.world;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.client.graphics.backend.FaceCulling;
|
||||
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
|
||||
import ru.windcorp.progressia.client.world.entity.EntityRenderRegistry;
|
||||
import ru.windcorp.progressia.client.world.entity.EntityRenderable;
|
||||
import ru.windcorp.progressia.common.world.ChunkData;
|
||||
import ru.windcorp.progressia.common.world.WorldData;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
|
||||
public class WorldRender {
|
||||
|
||||
private final WorldData data;
|
||||
|
||||
private final Map<ChunkData, ChunkRender> chunks = new HashMap<>();
|
||||
private final Map<EntityData, EntityRenderable> entityModels =
|
||||
Collections.synchronizedMap(new WeakHashMap<>());
|
||||
|
||||
public WorldRender(WorldData data) {
|
||||
this.data = data;
|
||||
@ -60,6 +68,34 @@ public class WorldRender {
|
||||
for (ChunkRender chunk : getChunks()) {
|
||||
chunk.render(renderer);
|
||||
}
|
||||
|
||||
renderEntities(renderer);
|
||||
}
|
||||
|
||||
private void renderEntities(ShapeRenderHelper renderer) {
|
||||
FaceCulling.push(false);
|
||||
|
||||
for (ChunkRender chunk : getChunks()) {
|
||||
chunk.getData().forEachEntity(entity -> {
|
||||
renderer.pushTransform().translate(entity.getPosition());
|
||||
getEntityRenderable(entity).render(renderer);
|
||||
renderer.popTransform();
|
||||
});
|
||||
}
|
||||
|
||||
FaceCulling.pop();
|
||||
}
|
||||
|
||||
public EntityRenderable getEntityRenderable(EntityData entity) {
|
||||
return entityModels.computeIfAbsent(
|
||||
entity,
|
||||
WorldRender::createEntityRenderable
|
||||
);
|
||||
}
|
||||
|
||||
private static EntityRenderable createEntityRenderable(EntityData entity) {
|
||||
return EntityRenderRegistry.getInstance().get(entity.getId())
|
||||
.createRenderable(entity);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,14 @@
|
||||
package ru.windcorp.progressia.client.world.entity;
|
||||
|
||||
import ru.windcorp.progressia.common.util.Namespaced;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
|
||||
public abstract class EntityRender extends Namespaced {
|
||||
|
||||
public EntityRender(String namespace, String name) {
|
||||
super(namespace, name);
|
||||
}
|
||||
|
||||
public abstract EntityRenderable createRenderable(EntityData entity);
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package ru.windcorp.progressia.client.world.entity;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
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;
|
||||
import ru.windcorp.progressia.common.util.NamespacedRegistry;
|
||||
|
||||
public class EntityRenderRegistry extends NamespacedRegistry<EntityRender> {
|
||||
|
||||
private static final EntityRenderRegistry INSTANCE =
|
||||
new EntityRenderRegistry();
|
||||
|
||||
public static EntityRenderRegistry getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public static TexturePrimitive getEntityTexture(String name) {
|
||||
try {
|
||||
return new TexturePrimitive(
|
||||
TextureLoader.loadPixels(
|
||||
ResourceManager.getTextureResource(
|
||||
"entities/" + name
|
||||
),
|
||||
new TextureSettings(false)
|
||||
).getData()
|
||||
);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package ru.windcorp.progressia.client.world.entity;
|
||||
|
||||
import glm.vec._3.Vec3;
|
||||
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
|
||||
public abstract class EntityRenderable implements Renderable {
|
||||
|
||||
private final EntityData data;
|
||||
|
||||
public EntityRenderable(EntityData data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public EntityData getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void getViewPoint(Vec3 output) {
|
||||
output.set(0, 0, 0);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,236 @@
|
||||
package ru.windcorp.progressia.client.world.entity;
|
||||
|
||||
import static java.lang.Math.*;
|
||||
import static ru.windcorp.progressia.common.util.FloatMathUtils.*;
|
||||
|
||||
import glm.Glm;
|
||||
import glm.mat._4.Mat4;
|
||||
import glm.vec._3.Vec3;
|
||||
import glm.vec._4.Vec4;
|
||||
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
||||
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
|
||||
import ru.windcorp.progressia.common.util.Matrices;
|
||||
import ru.windcorp.progressia.common.util.Vectors;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
|
||||
public class QuadripedModel extends EntityRenderable {
|
||||
|
||||
private static abstract class BodyPart {
|
||||
private final Renderable renderable;
|
||||
private final Vec3 translation = new Vec3();
|
||||
|
||||
public BodyPart(Renderable renderable, Vec3 joint) {
|
||||
this.renderable = renderable;
|
||||
if (joint != null) {
|
||||
this.translation.set(joint);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void render(
|
||||
ShapeRenderHelper renderer, QuadripedModel model
|
||||
) {
|
||||
renderer.pushTransform().translate(translation);
|
||||
applyTransform(renderer.pushTransform(), model);
|
||||
renderable.render(renderer);
|
||||
renderer.popTransform();
|
||||
renderer.popTransform();
|
||||
}
|
||||
|
||||
protected abstract void applyTransform(Mat4 mat, QuadripedModel model);
|
||||
|
||||
public Vec3 getTranslation() {
|
||||
return translation;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Body extends BodyPart {
|
||||
public Body(Renderable renderable) {
|
||||
super(renderable, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTransform(Mat4 mat, QuadripedModel model) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
public static class Head extends BodyPart {
|
||||
private final float maxYaw;
|
||||
private final float maxPitch;
|
||||
|
||||
private final Vec3 viewPoint;
|
||||
|
||||
public Head(
|
||||
Renderable renderable, Vec3 joint,
|
||||
double maxYawDegrees, double maxPitchDegrees,
|
||||
Vec3 viewPoint
|
||||
) {
|
||||
super(renderable, joint);
|
||||
this.maxYaw = (float) toRadians(maxYawDegrees);
|
||||
this.maxPitch = (float) toRadians(maxPitchDegrees);
|
||||
this.viewPoint = viewPoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTransform(Mat4 mat, QuadripedModel model) {
|
||||
mat.rotateZ(model.headYaw).rotateY(model.headPitch);
|
||||
}
|
||||
|
||||
public Vec3 getViewPoint() {
|
||||
return viewPoint;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Leg extends BodyPart {
|
||||
private final float animationOffset;
|
||||
|
||||
public Leg(
|
||||
Renderable renderable, Vec3 joint,
|
||||
float animationOffset
|
||||
) {
|
||||
super(renderable, joint);
|
||||
this.animationOffset = animationOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTransform(Mat4 mat, QuadripedModel model) {
|
||||
mat.rotateY(sin(model.walkingFrequency * model.walkingAnimationParameter + animationOffset) * model.walkingSwing * model.velocityCoeff);
|
||||
}
|
||||
}
|
||||
|
||||
private final Body body;
|
||||
private final Head head;
|
||||
private final Leg leftForeLeg, rightForeLeg;
|
||||
private final Leg leftHindLeg, rightHindLeg;
|
||||
|
||||
private final float scale;
|
||||
|
||||
private float walkingAnimationParameter = 0;
|
||||
private float velocityCoeff = 0;
|
||||
private float velocity = 0;
|
||||
|
||||
/**
|
||||
* Controls how quickly velocityCoeff approaches 1
|
||||
*/
|
||||
private float velocityCutoff = 10;
|
||||
|
||||
private float walkingFrequency = 0.15f;
|
||||
private float walkingSwing = (float) toRadians(30);
|
||||
|
||||
private float bodyYaw = Float.NaN;
|
||||
private float headYaw;
|
||||
private float headPitch;
|
||||
|
||||
public QuadripedModel(
|
||||
EntityData entity,
|
||||
|
||||
Body body, Head head,
|
||||
Leg leftForeLeg, Leg rightForeLeg,
|
||||
Leg leftHindLeg, Leg rightHindLeg,
|
||||
|
||||
float scale
|
||||
) {
|
||||
super(entity);
|
||||
|
||||
this.body = body;
|
||||
this.head = head;
|
||||
this.leftForeLeg = leftForeLeg;
|
||||
this.rightForeLeg = rightForeLeg;
|
||||
this.leftHindLeg = leftHindLeg;
|
||||
this.rightHindLeg = rightHindLeg;
|
||||
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(ShapeRenderHelper renderer) {
|
||||
renderer.pushTransform().scale(scale).rotateZ(bodyYaw);
|
||||
body.render(renderer, this);
|
||||
head.render(renderer, this);
|
||||
leftForeLeg.render(renderer, this);
|
||||
rightForeLeg.render(renderer, this);
|
||||
leftHindLeg.render(renderer, this);
|
||||
rightHindLeg.render(renderer, this);
|
||||
renderer.popTransform();
|
||||
|
||||
accountForVelocity();
|
||||
evaluateAngles();
|
||||
}
|
||||
|
||||
private void evaluateAngles() {
|
||||
float globalYaw = normalizeAngle(getData().getYaw());
|
||||
|
||||
if (Float.isNaN(bodyYaw)) {
|
||||
bodyYaw = globalYaw;
|
||||
headYaw = 0;
|
||||
} else {
|
||||
headYaw = normalizeAngle(globalYaw - bodyYaw);
|
||||
|
||||
if (headYaw > +head.maxYaw) {
|
||||
bodyYaw += headYaw - +head.maxYaw;
|
||||
headYaw = +head.maxYaw;
|
||||
} else if (headYaw < -head.maxYaw) {
|
||||
bodyYaw += headYaw - -head.maxYaw;
|
||||
headYaw = -head.maxYaw;
|
||||
}
|
||||
}
|
||||
|
||||
bodyYaw = normalizeAngle(bodyYaw);
|
||||
|
||||
headPitch = Glm.clamp(
|
||||
getData().getPitch(),
|
||||
-head.maxPitch, head.maxPitch
|
||||
);
|
||||
}
|
||||
|
||||
private void accountForVelocity() {
|
||||
Vec3 horizontal = Vectors.grab3();
|
||||
horizontal.set(getData().getVelocity());
|
||||
horizontal.z = 0;
|
||||
|
||||
velocity = horizontal.length();
|
||||
|
||||
evaluateVelocityCoeff();
|
||||
|
||||
// TODO switch to world time
|
||||
walkingAnimationParameter += velocity * GraphicsInterface.getFrameLength() * 1000;
|
||||
|
||||
bodyYaw += velocityCoeff * normalizeAngle(
|
||||
(float) (atan2(horizontal.y, horizontal.x) - bodyYaw)
|
||||
) * min(1, GraphicsInterface.getFrameLength() * 10);
|
||||
Vectors.release(horizontal);
|
||||
}
|
||||
|
||||
private void evaluateVelocityCoeff() {
|
||||
if (velocity * velocityCutoff > 1) {
|
||||
velocityCoeff = 1;
|
||||
} else {
|
||||
velocityCoeff = velocity * velocityCutoff;
|
||||
velocityCoeff *= velocityCoeff;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getViewPoint(Vec3 output) {
|
||||
Mat4 m = Matrices.grab4();
|
||||
Vec4 v = Vectors.grab4();
|
||||
|
||||
m.identity()
|
||||
.scale(scale)
|
||||
.rotateZ(bodyYaw)
|
||||
.translate(head.getTranslation())
|
||||
.rotateZ(headYaw)
|
||||
.rotateY(headPitch);
|
||||
|
||||
v.set(head.getViewPoint(), 1);
|
||||
m.mul(v);
|
||||
|
||||
output.set(v.x, v.y, v.z);
|
||||
|
||||
Vectors.release(v);
|
||||
Matrices.release(m);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package ru.windcorp.progressia.client.world.tile;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.common.world.block.BlockFace;
|
||||
|
||||
public class TileLocation {
|
||||
|
||||
public final Vec3i pos = new Vec3i();
|
||||
public BlockFace face;
|
||||
public int layer;
|
||||
|
||||
public TileLocation() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
public TileLocation(TileLocation src) {
|
||||
this.pos.set(src.pos.x, src.pos.y, src.pos.z);
|
||||
this.face = src.face;
|
||||
this.layer = src.layer;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package ru.windcorp.progressia.common.comms.packets;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class PacketSetLocalPlayer extends Packet {
|
||||
|
||||
private final UUID localPlayerEntityUUID;
|
||||
|
||||
public PacketSetLocalPlayer(UUID uuid) {
|
||||
super("Core", "SetLocalPlayer");
|
||||
this.localPlayerEntityUUID = uuid;
|
||||
}
|
||||
|
||||
public UUID getLocalPlayerEntityUUID() {
|
||||
return localPlayerEntityUUID;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package ru.windcorp.progressia.common.util;
|
||||
|
||||
import org.apache.commons.math3.util.FastMath;
|
||||
|
||||
public class FloatMathUtils {
|
||||
|
||||
public static final float PI_F = (float) Math.PI;
|
||||
|
||||
public static float floor(float x) {
|
||||
return (float) FastMath.floor(x);
|
||||
}
|
||||
|
||||
public static float normalizeAngle(float a) {
|
||||
return a - 2*PI_F * floor((a + PI_F) / (2*PI_F));
|
||||
}
|
||||
|
||||
private FloatMathUtils() {}
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package ru.windcorp.progressia.common.util;
|
||||
|
||||
import glm.mat._3.Mat3;
|
||||
import glm.mat._4.Mat4;
|
||||
import glm.mat._4.d.Mat4d;
|
||||
|
||||
/**
|
||||
* A set of caches for GLM matrix objects. Use this instead of allocating new
|
||||
* matrices when the objects are effectively local.
|
||||
* <p>
|
||||
* All {@code grab}bed objects must be {@code release}d as soon as possible.
|
||||
* Ideally, user code should be:
|
||||
* <pre>
|
||||
* Mat4 myMatrix = Vectors.grab4();
|
||||
* try {
|
||||
* // use myMatrix
|
||||
* } finally {
|
||||
* Matrices.release(myMatrix);
|
||||
* }
|
||||
* </pre>
|
||||
* Provided objects may be reused after {@code release} has been invoked;
|
||||
* do not store them.
|
||||
* <p>
|
||||
* This class is thread- and recursion-safe.
|
||||
*
|
||||
* @see Vectors
|
||||
*/
|
||||
public class Matrices {
|
||||
|
||||
private static final LowOverheadCache<Mat3> MAT3S =
|
||||
new LowOverheadCache<>(Mat3::new);
|
||||
|
||||
public static Mat3 grab3() {
|
||||
return MAT3S.grab();
|
||||
}
|
||||
|
||||
public static void release(Mat3 m) {
|
||||
MAT3S.release(m);
|
||||
}
|
||||
|
||||
private static final LowOverheadCache<Mat4> MAT4S =
|
||||
new LowOverheadCache<>(Mat4::new);
|
||||
|
||||
public static Mat4 grab4() {
|
||||
return MAT4S.grab();
|
||||
}
|
||||
|
||||
public static void release(Mat4 m) {
|
||||
MAT4S.release(m);
|
||||
}
|
||||
|
||||
private static final LowOverheadCache<Mat4d> MAT4DS =
|
||||
new LowOverheadCache<>(Mat4d::new);
|
||||
|
||||
public static Mat4d grab4d() {
|
||||
return MAT4DS.grab();
|
||||
}
|
||||
|
||||
public static void release(Mat4d m) {
|
||||
MAT4DS.release(m);
|
||||
}
|
||||
|
||||
private Matrices() {}
|
||||
|
||||
}
|
@ -25,6 +25,8 @@ import glm.vec._4.i.Vec4i;
|
||||
* do not store them.
|
||||
* <p>
|
||||
* This class is thread- and recursion-safe.
|
||||
*
|
||||
* @see Matrices
|
||||
*/
|
||||
public class Vectors {
|
||||
|
||||
|
@ -20,18 +20,25 @@ package ru.windcorp.progressia.common.world;
|
||||
import static ru.windcorp.progressia.common.world.block.BlockFace.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import glm.vec._2.Vec2;
|
||||
import glm.vec._3.Vec3;
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.client.world.tile.TileLocation;
|
||||
import ru.windcorp.progressia.common.util.SizeLimitedList;
|
||||
import ru.windcorp.progressia.common.util.VectorUtil;
|
||||
import ru.windcorp.progressia.common.util.Vectors;
|
||||
import ru.windcorp.progressia.common.world.block.BlockData;
|
||||
import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
|
||||
import ru.windcorp.progressia.common.world.block.BlockFace;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
import ru.windcorp.progressia.common.world.tile.TileData;
|
||||
import ru.windcorp.progressia.common.world.tile.TileDataRegistry;
|
||||
|
||||
@ -53,6 +60,9 @@ public class ChunkData {
|
||||
BLOCK_FACE_COUNT
|
||||
];
|
||||
|
||||
private final List<EntityData> entities =
|
||||
Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
public ChunkData(int x, int y, int z, WorldData world) {
|
||||
this.position.set(x, y, z);
|
||||
this.world = world;
|
||||
@ -121,6 +131,14 @@ public class ChunkData {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EntityData javapony = new EntityData("Test", "Javapony");
|
||||
javapony.setUUID(UUID.nameUUIDFromBytes(new byte[] {42}));
|
||||
javapony.setPosition(new Vec3(-6, -6, 20));
|
||||
javapony.setDirection(new Vec2(
|
||||
(float) Math.toRadians(40), (float) Math.toRadians(45)
|
||||
));
|
||||
getEntities().add(javapony);
|
||||
}
|
||||
|
||||
public BlockData getBlock(Vec3i posInChunk) {
|
||||
@ -214,6 +232,10 @@ public class ChunkData {
|
||||
face.getId();
|
||||
}
|
||||
|
||||
public List<EntityData> getEntities() {
|
||||
return entities;
|
||||
}
|
||||
|
||||
private static void checkLocalCoordinates(Vec3i posInChunk) {
|
||||
if (!isInBounds(posInChunk)) {
|
||||
throw new IllegalArgumentException(
|
||||
@ -249,6 +271,38 @@ public class ChunkData {
|
||||
action
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over all tiles in this chunk. Tiles are referenced using their
|
||||
* primary block (so that the face is
|
||||
* {@linkplain BlockFace#isPrimary() primary}).
|
||||
*
|
||||
* @param action the action to perform. {@code TileLocation} refers to each
|
||||
* tile using its primary block
|
||||
*/
|
||||
public void forEachTile(BiConsumer<TileLocation, TileData> action) {
|
||||
TileLocation loc = new TileLocation();
|
||||
|
||||
forEachBlock(blockInChunk -> {
|
||||
loc.pos.set(blockInChunk.x, blockInChunk.y, blockInChunk.z);
|
||||
|
||||
for (BlockFace face : BlockFace.getPrimaryFaces()) {
|
||||
List<TileData> list = getTilesOrNull(blockInChunk, face);
|
||||
if (list == null) continue;
|
||||
|
||||
loc.face = face;
|
||||
|
||||
for (loc.layer = 0; loc.layer < list.size(); ++loc.layer) {
|
||||
TileData tile = list.get(loc.layer);
|
||||
action.accept(loc, tile);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void forEachEntity(Consumer<EntityData> action) {
|
||||
getEntities().forEach(action);
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return position.x;
|
||||
|
@ -18,6 +18,7 @@
|
||||
package ru.windcorp.progressia.common.world.block;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
|
||||
@ -58,6 +59,21 @@ public final class BlockFace extends BlockRelation {
|
||||
b.counterFace = a;
|
||||
}
|
||||
|
||||
public static <E> ImmutableMap<BlockFace, E> mapToFaces(
|
||||
E top, E bottom,
|
||||
E north, E south,
|
||||
E east, E west
|
||||
) {
|
||||
return ImmutableMap.<BlockFace, E>builderWithExpectedSize(6)
|
||||
.put(TOP, top)
|
||||
.put(BOTTOM, bottom)
|
||||
.put(NORTH, north)
|
||||
.put(SOUTH, south)
|
||||
.put(EAST, east)
|
||||
.put(WEST, west)
|
||||
.build();
|
||||
}
|
||||
|
||||
private static int nextId = 0;
|
||||
|
||||
private final int id;
|
||||
|
@ -0,0 +1,62 @@
|
||||
package ru.windcorp.progressia.common.world.entity;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import glm.vec._2.Vec2;
|
||||
import glm.vec._3.Vec3;
|
||||
import ru.windcorp.progressia.common.util.Namespaced;
|
||||
|
||||
public class EntityData extends Namespaced {
|
||||
|
||||
private final Vec3 position = new Vec3();
|
||||
private final Vec3 velocity = new Vec3();
|
||||
|
||||
private final Vec2 direction = new Vec2();
|
||||
|
||||
private UUID uuid;
|
||||
|
||||
public EntityData(String namespace, String name) {
|
||||
super(namespace, name);
|
||||
}
|
||||
|
||||
public Vec3 getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setPosition(Vec3 position) {
|
||||
this.position.set(position);
|
||||
}
|
||||
|
||||
public Vec3 getVelocity() {
|
||||
return velocity;
|
||||
}
|
||||
|
||||
public void setVelocity(Vec3 velocity) {
|
||||
this.velocity.set(velocity);
|
||||
}
|
||||
|
||||
public Vec2 getDirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
public void setDirection(Vec2 direction) {
|
||||
this.direction.set(direction.x, direction.y);
|
||||
}
|
||||
|
||||
public float getYaw() {
|
||||
return getDirection().x;
|
||||
}
|
||||
|
||||
public float getPitch() {
|
||||
return getDirection().y;
|
||||
}
|
||||
|
||||
public UUID getUUID() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public void setUUID(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package ru.windcorp.progressia.common.world.entity;
|
||||
|
||||
import ru.windcorp.progressia.common.util.NamespacedRegistry;
|
||||
|
||||
public class EntityDataRegistry extends NamespacedRegistry<EntityData> {
|
||||
|
||||
private static final EntityDataRegistry INSTANCE = new EntityDataRegistry();
|
||||
|
||||
public static EntityDataRegistry getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
}
|
@ -4,12 +4,14 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import gnu.trove.TCollections;
|
||||
import gnu.trove.map.TIntObjectMap;
|
||||
import gnu.trove.map.hash.TIntObjectHashMap;
|
||||
import ru.windcorp.progressia.common.comms.CommsChannel.Role;
|
||||
import ru.windcorp.progressia.common.comms.CommsChannel.State;
|
||||
import ru.windcorp.progressia.common.comms.packets.Packet;
|
||||
import ru.windcorp.progressia.common.comms.packets.PacketSetLocalPlayer;
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
|
||||
public class ClientManager {
|
||||
@ -36,6 +38,11 @@ public class ClientManager {
|
||||
clientsById.put(client.getId(), client);
|
||||
|
||||
client.addListener(new DefaultServerCommsListener(this, client));
|
||||
|
||||
client.sendPacket(new PacketSetLocalPlayer(
|
||||
server.getWorld().getData().getChunk(new Vec3i(0, 0, 0))
|
||||
.getEntities().get(0).getUUID()
|
||||
));
|
||||
}
|
||||
|
||||
public void disconnectClient(Client client) {
|
||||
|
@ -2,43 +2,82 @@ package ru.windcorp.progressia.server.world;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.client.world.tile.TileLocation;
|
||||
import ru.windcorp.progressia.common.world.ChunkData;
|
||||
import ru.windcorp.progressia.common.world.block.BlockFace;
|
||||
import ru.windcorp.progressia.common.world.tile.TileData;
|
||||
import ru.windcorp.progressia.server.world.block.BlockLogic;
|
||||
import ru.windcorp.progressia.server.world.block.BlockLogicRegistry;
|
||||
import ru.windcorp.progressia.server.world.block.Tickable;
|
||||
import ru.windcorp.progressia.server.world.block.TickableBlock;
|
||||
import ru.windcorp.progressia.server.world.tile.TickableTile;
|
||||
import ru.windcorp.progressia.server.world.tile.TileLogic;
|
||||
import ru.windcorp.progressia.server.world.tile.TileLogicRegistry;
|
||||
|
||||
public class ChunkLogic {
|
||||
|
||||
private final WorldLogic world;
|
||||
private final ChunkData data;
|
||||
|
||||
private final Collection<Vec3i> ticking = new ArrayList<>();
|
||||
private final Collection<Vec3i> tickingBlocks = new ArrayList<>();
|
||||
private final Collection<TileLocation> tickingTiles = new ArrayList<>();
|
||||
|
||||
private final Map<List<TileData>, List<TileLogic>> tileLogicLists =
|
||||
Collections.synchronizedMap(new WeakHashMap<>());
|
||||
|
||||
public ChunkLogic(WorldLogic world, ChunkData data) {
|
||||
this.world = world;
|
||||
this.data = data;
|
||||
|
||||
generateTickList();
|
||||
generateTickLists();
|
||||
}
|
||||
|
||||
private void generateTickList() {
|
||||
private void generateTickLists() {
|
||||
MutableBlockTickContext blockTickContext =
|
||||
new MutableBlockTickContext();
|
||||
|
||||
MutableTileTickContext tileTickContext =
|
||||
new MutableTileTickContext();
|
||||
|
||||
blockTickContext.setWorld(getWorld());
|
||||
blockTickContext.setChunk(this);
|
||||
|
||||
tileTickContext.setWorld(getWorld());
|
||||
tileTickContext.setChunk(this);
|
||||
|
||||
data.forEachBlock(blockInChunk -> {
|
||||
BlockLogic block = getBlock(blockInChunk);
|
||||
|
||||
if (block instanceof Tickable) {
|
||||
if (block instanceof TickableBlock) {
|
||||
blockTickContext.setCoordsInChunk(blockInChunk);
|
||||
|
||||
if (((Tickable) block).doesTickRegularly(blockTickContext)) {
|
||||
ticking.add(new Vec3i(blockInChunk));
|
||||
if (((TickableBlock) block)
|
||||
.doesTickRegularly(blockTickContext)
|
||||
) {
|
||||
tickingBlocks.add(new Vec3i(blockInChunk));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
data.forEachTile((loc, tileData) -> {
|
||||
TileLogic tile =
|
||||
TileLogicRegistry.getInstance().get(tileData.getId());
|
||||
|
||||
if (tile instanceof TickableTile) {
|
||||
tileTickContext.setCoordsInChunk(loc.pos);
|
||||
tileTickContext.setFace(loc.face);
|
||||
tileTickContext.setLayer(loc.layer);
|
||||
|
||||
if (((TickableTile) tile).doesTickRegularly(tileTickContext)) {
|
||||
tickingTiles.add(new TileLocation(loc));
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -53,19 +92,57 @@ public class ChunkLogic {
|
||||
}
|
||||
|
||||
public boolean hasTickingBlocks() {
|
||||
return ticking.isEmpty();
|
||||
return !tickingBlocks.isEmpty();
|
||||
}
|
||||
|
||||
public boolean hasTickingTiles() {
|
||||
return !tickingTiles.isEmpty();
|
||||
}
|
||||
|
||||
public void forEachTickingBlock(BiConsumer<Vec3i, BlockLogic> action) {
|
||||
ticking.forEach(blockInChunk -> {
|
||||
tickingBlocks.forEach(blockInChunk -> {
|
||||
action.accept(blockInChunk, getBlock(blockInChunk));
|
||||
});
|
||||
}
|
||||
|
||||
public void forEachTickingTile(BiConsumer<TileLocation, TileLogic> action) {
|
||||
tickingTiles.forEach(location -> {
|
||||
action.accept(
|
||||
location,
|
||||
getTilesOrNull(location.pos, location.face)
|
||||
.get(location.layer)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
public BlockLogic getBlock(Vec3i blockInChunk) {
|
||||
return BlockLogicRegistry.getInstance().get(
|
||||
getData().getBlock(blockInChunk).getId()
|
||||
);
|
||||
}
|
||||
|
||||
public List<TileLogic> getTiles(Vec3i blockInChunk, BlockFace face) {
|
||||
return wrapTileList(getData().getTiles(blockInChunk, face));
|
||||
}
|
||||
|
||||
public List<TileLogic> getTilesOrNull(Vec3i blockInChunk, BlockFace face) {
|
||||
List<TileData> tiles = getData().getTilesOrNull(blockInChunk, face);
|
||||
if (tiles == null) return null;
|
||||
return wrapTileList(tiles);
|
||||
}
|
||||
|
||||
private List<TileLogic> wrapTileList(List<TileData> tileDataList) {
|
||||
return tileLogicLists.computeIfAbsent(
|
||||
tileDataList,
|
||||
ChunkLogic::createWrapper
|
||||
);
|
||||
}
|
||||
|
||||
private static List<TileLogic> createWrapper(List<TileData> tileDataList) {
|
||||
return Lists.transform(
|
||||
tileDataList,
|
||||
data -> TileLogicRegistry.getInstance().get(data.getId())
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,57 +3,15 @@ package ru.windcorp.progressia.server.world;
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.common.util.Vectors;
|
||||
import ru.windcorp.progressia.common.world.Coordinates;
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
import ru.windcorp.progressia.server.world.block.BlockTickContext;
|
||||
|
||||
public class MutableBlockTickContext implements BlockTickContext {
|
||||
|
||||
private double tickLength;
|
||||
|
||||
private Server server;
|
||||
private WorldLogic world;
|
||||
|
||||
private ChunkLogic chunk;
|
||||
public class MutableBlockTickContext
|
||||
extends MutableChunkTickContext
|
||||
implements BlockTickContext {
|
||||
|
||||
private final Vec3i blockInWorld = new Vec3i();
|
||||
private final Vec3i blockInChunk = new Vec3i();
|
||||
|
||||
public double getTickLength() {
|
||||
return tickLength;
|
||||
}
|
||||
|
||||
public void setTickLength(double tickLength) {
|
||||
this.tickLength = tickLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Server getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public void setServer(Server server) {
|
||||
this.server = server;
|
||||
setWorld(server.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldLogic getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
public void setWorld(WorldLogic world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkLogic getChunk() {
|
||||
return chunk;
|
||||
}
|
||||
|
||||
public void setChunk(ChunkLogic chunk) {
|
||||
this.chunk = chunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3i getCoords() {
|
||||
return this.blockInWorld;
|
||||
@ -82,10 +40,4 @@ public class MutableBlockTickContext implements BlockTickContext {
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestBlockTick(Vec3i blockInWorld) {
|
||||
// TODO implement
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,66 @@
|
||||
package ru.windcorp.progressia.server.world;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.common.world.block.BlockFace;
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
|
||||
public class MutableChunkTickContext implements ChunkTickContext {
|
||||
|
||||
private double tickLength;
|
||||
private Server server;
|
||||
private WorldLogic world;
|
||||
private ChunkLogic chunk;
|
||||
|
||||
public MutableChunkTickContext() {
|
||||
super();
|
||||
}
|
||||
|
||||
public double getTickLength() {
|
||||
return tickLength;
|
||||
}
|
||||
|
||||
public void setTickLength(double tickLength) {
|
||||
this.tickLength = tickLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Server getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public void setServer(Server server) {
|
||||
this.server = server;
|
||||
setWorld(server.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldLogic getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
public void setWorld(WorldLogic world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkLogic getChunk() {
|
||||
return chunk;
|
||||
}
|
||||
|
||||
public void setChunk(ChunkLogic chunk) {
|
||||
this.chunk = chunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestBlockTick(Vec3i blockInWorld) {
|
||||
// TODO implement
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestTileTick(Vec3i blockInWorld, BlockFace face, int layer) {
|
||||
// TODO implement
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package ru.windcorp.progressia.server.world;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.common.util.Vectors;
|
||||
import ru.windcorp.progressia.common.world.Coordinates;
|
||||
import ru.windcorp.progressia.common.world.block.BlockFace;
|
||||
import ru.windcorp.progressia.server.world.tile.TileTickContext;
|
||||
|
||||
public class MutableTileTickContext
|
||||
extends MutableChunkTickContext
|
||||
implements TileTickContext {
|
||||
|
||||
private final Vec3i blockInWorld = new Vec3i();
|
||||
private final Vec3i blockInChunk = new Vec3i();
|
||||
|
||||
private BlockFace face;
|
||||
private int layer;
|
||||
|
||||
@Override
|
||||
public Vec3i getCoords() {
|
||||
return this.blockInWorld;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3i getChunkCoords() {
|
||||
return this.blockInChunk;
|
||||
}
|
||||
|
||||
public void setCoordsInWorld(Vec3i coords) {
|
||||
getCoords().set(coords.x, coords.y, coords.z);
|
||||
Coordinates.convertInWorldToInChunk(getCoords(), getChunkCoords());
|
||||
|
||||
Vec3i chunk = Vectors.grab3i();
|
||||
Coordinates.convertInWorldToChunk(coords, chunk);
|
||||
setChunk(getWorld().getChunk(chunk));
|
||||
Vectors.release(chunk);
|
||||
}
|
||||
|
||||
public void setCoordsInChunk(Vec3i coords) {
|
||||
getChunkCoords().set(coords.x, coords.y, coords.z);
|
||||
Coordinates.getInWorld(
|
||||
getChunkData().getPosition(), getChunkCoords(),
|
||||
getCoords()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockFace getFace() {
|
||||
return face;
|
||||
}
|
||||
|
||||
public void setFace(BlockFace face) {
|
||||
this.face = face;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLayer() {
|
||||
return layer;
|
||||
}
|
||||
|
||||
public void setLayer(int layer) {
|
||||
this.layer = layer;
|
||||
}
|
||||
|
||||
}
|
@ -2,6 +2,7 @@ package ru.windcorp.progressia.server.world;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.common.world.WorldData;
|
||||
import ru.windcorp.progressia.common.world.block.BlockFace;
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
|
||||
public interface TickContext {
|
||||
@ -19,5 +20,7 @@ public interface TickContext {
|
||||
}
|
||||
|
||||
void requestBlockTick(Vec3i blockInWorld);
|
||||
|
||||
void requestTileTick(Vec3i blockInWorld, BlockFace face, int layer);
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
package ru.windcorp.progressia.server.world;
|
||||
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
import ru.windcorp.progressia.server.world.block.Tickable;
|
||||
import ru.windcorp.progressia.server.world.block.TickableBlock;
|
||||
import ru.windcorp.progressia.server.world.tile.TickableTile;
|
||||
|
||||
public class Ticker implements Runnable {
|
||||
|
||||
@ -11,6 +12,9 @@ public class Ticker implements Runnable {
|
||||
private final MutableBlockTickContext blockTickContext =
|
||||
new MutableBlockTickContext();
|
||||
|
||||
private final MutableTileTickContext tileTickContext =
|
||||
new MutableTileTickContext();
|
||||
|
||||
private final Server server;
|
||||
|
||||
public Ticker(Server server) {
|
||||
@ -26,30 +30,41 @@ public class Ticker implements Runnable {
|
||||
}
|
||||
|
||||
private void tickChunk(ChunkLogic chunk) {
|
||||
MutableBlockTickContext context = this.blockTickContext;
|
||||
MutableBlockTickContext blockContext = this.blockTickContext;
|
||||
MutableTileTickContext tileContext = this.tileTickContext;
|
||||
|
||||
context.setServer(server);
|
||||
context.setChunk(chunk);
|
||||
blockContext.setServer(server);
|
||||
tileContext.setServer(server);
|
||||
|
||||
tickRegularBlocks(chunk, context);
|
||||
tickRandomBlocks(chunk, context);
|
||||
tickRegularTickers(chunk, blockContext, tileContext);
|
||||
tickRandomBlocks(chunk, blockContext, tileContext);
|
||||
|
||||
flushChanges(chunk);
|
||||
}
|
||||
|
||||
private void tickRegularBlocks(
|
||||
private void tickRegularTickers(
|
||||
ChunkLogic chunk,
|
||||
MutableBlockTickContext context
|
||||
MutableBlockTickContext blockContext,
|
||||
MutableTileTickContext tileContext
|
||||
) {
|
||||
chunk.forEachTickingBlock((blockInChunk, block) -> {
|
||||
context.setCoordsInChunk(blockInChunk);
|
||||
((Tickable) block).tick(context, tracker);
|
||||
blockContext.setCoordsInChunk(blockInChunk);
|
||||
((TickableBlock) block).tick(blockContext, tracker);
|
||||
});
|
||||
|
||||
chunk.forEachTickingTile((locInChunk, tile) -> {
|
||||
tileContext.setCoordsInChunk(locInChunk.pos);
|
||||
tileContext.setFace(locInChunk.face);
|
||||
tileContext.setLayer(locInChunk.layer);
|
||||
|
||||
((TickableTile) tile).tick(tileContext, tracker);
|
||||
});
|
||||
}
|
||||
|
||||
private void tickRandomBlocks(
|
||||
ChunkLogic chunk,
|
||||
MutableBlockTickContext context
|
||||
MutableBlockTickContext blockContext,
|
||||
MutableTileTickContext tileContext
|
||||
) {
|
||||
// TODO implement
|
||||
}
|
||||
|
@ -4,11 +4,12 @@ import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.common.world.ChunkData;
|
||||
import ru.windcorp.progressia.common.world.WorldData;
|
||||
import ru.windcorp.progressia.common.world.block.BlockData;
|
||||
import ru.windcorp.progressia.common.world.block.BlockFace;
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
import ru.windcorp.progressia.server.world.ChunkLogic;
|
||||
import ru.windcorp.progressia.server.world.WorldLogic;
|
||||
|
||||
public class ForwardingBlockTickContext {
|
||||
public class ForwardingBlockTickContext implements BlockTickContext {
|
||||
|
||||
private BlockTickContext parent;
|
||||
|
||||
@ -24,46 +25,62 @@ public class ForwardingBlockTickContext {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkLogic getChunk() {
|
||||
return parent.getChunk();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ChunkData getChunkData() {
|
||||
return parent.getChunkData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTickLength() {
|
||||
return parent.getTickLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Server getServer() {
|
||||
return parent.getServer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3i getCoords() {
|
||||
return parent.getCoords();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldLogic getWorld() {
|
||||
return parent.getWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldData getWorldData() {
|
||||
return parent.getWorldData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3i getChunkCoords() {
|
||||
return parent.getChunkCoords();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestBlockTick(Vec3i blockInWorld) {
|
||||
parent.requestBlockTick(blockInWorld);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestTileTick(Vec3i blockInWorld, BlockFace face, int layer) {
|
||||
parent.requestTileTick(blockInWorld, face, layer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockLogic getBlock() {
|
||||
return parent.getBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockData getBlockData() {
|
||||
return parent.getBlockData();
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package ru.windcorp.progressia.server.world.block;
|
||||
|
||||
import ru.windcorp.progressia.server.world.Changer;
|
||||
|
||||
public interface Tickable {
|
||||
public interface TickableBlock {
|
||||
|
||||
void tick(BlockTickContext context, Changer changer);
|
||||
|
@ -2,7 +2,7 @@ package ru.windcorp.progressia.server.world.block;
|
||||
|
||||
import ru.windcorp.progressia.server.world.Changer;
|
||||
|
||||
public interface Updatable {
|
||||
public interface UpdatableBlock {
|
||||
|
||||
void update(BlockTickContext context, Changer changer);
|
||||
|
@ -0,0 +1,11 @@
|
||||
package ru.windcorp.progressia.server.world.entity;
|
||||
|
||||
import ru.windcorp.progressia.common.util.Namespaced;
|
||||
|
||||
public class EntityLogic extends Namespaced {
|
||||
|
||||
public EntityLogic(String namespace, String name) {
|
||||
super(namespace, name);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package ru.windcorp.progressia.server.world.entity;
|
||||
|
||||
import ru.windcorp.progressia.common.util.NamespacedRegistry;
|
||||
|
||||
public class EntityLogicRegistry extends NamespacedRegistry<EntityLogic> {
|
||||
|
||||
private static final EntityLogicRegistry INSTANCE =
|
||||
new EntityLogicRegistry();
|
||||
|
||||
public static EntityLogicRegistry getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,132 @@
|
||||
package ru.windcorp.progressia.server.world.tile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.common.world.ChunkData;
|
||||
import ru.windcorp.progressia.common.world.WorldData;
|
||||
import ru.windcorp.progressia.common.world.block.BlockData;
|
||||
import ru.windcorp.progressia.common.world.block.BlockFace;
|
||||
import ru.windcorp.progressia.common.world.tile.TileData;
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
import ru.windcorp.progressia.server.world.ChunkLogic;
|
||||
import ru.windcorp.progressia.server.world.WorldLogic;
|
||||
import ru.windcorp.progressia.server.world.block.BlockLogic;
|
||||
|
||||
public class ForwardingTileTickContext implements TileTickContext {
|
||||
|
||||
private TileTickContext parent;
|
||||
|
||||
public ForwardingTileTickContext(TileTickContext parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public TileTickContext getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public void setParent(TileTickContext parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkLogic getChunk() {
|
||||
return parent.getChunk();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkData getChunkData() {
|
||||
return parent.getChunkData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTickLength() {
|
||||
return parent.getTickLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Server getServer() {
|
||||
return parent.getServer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldLogic getWorld() {
|
||||
return parent.getWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldData getWorldData() {
|
||||
return parent.getWorldData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestBlockTick(Vec3i blockInWorld) {
|
||||
parent.requestBlockTick(blockInWorld);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestTileTick(Vec3i blockInWorld, BlockFace face, int layer) {
|
||||
parent.requestTileTick(blockInWorld, face, layer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3i getCoords() {
|
||||
return parent.getCoords();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3i getChunkCoords() {
|
||||
return parent.getChunkCoords();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockFace getFace() {
|
||||
return parent.getFace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLayer() {
|
||||
return parent.getLayer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileLogic getTile() {
|
||||
return parent.getTile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileData getTileData() {
|
||||
return parent.getTileData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TileLogic> getTiles() {
|
||||
return parent.getTiles();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TileLogic> getTilesOrNull() {
|
||||
return parent.getTilesOrNull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TileData> getTileDataList() {
|
||||
return parent.getTileDataList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TileData> getTileDataListOrNull() {
|
||||
return parent.getTileDataListOrNull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockLogic getBlock() {
|
||||
return parent.getBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockData getBlockData() {
|
||||
return parent.getBlockData();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package ru.windcorp.progressia.server.world.tile;
|
||||
|
||||
import ru.windcorp.progressia.server.world.Changer;
|
||||
|
||||
public interface TickableTile {
|
||||
|
||||
void tick(TileTickContext context, Changer changer);
|
||||
|
||||
default boolean doesTickRegularly(TileTickContext context) {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean doesTickRandomly(TileTickContext context) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package ru.windcorp.progressia.server.world.tile;
|
||||
|
||||
import ru.windcorp.progressia.common.util.Namespaced;
|
||||
import ru.windcorp.progressia.common.world.block.BlockFace;
|
||||
|
||||
public class TileLogic extends Namespaced {
|
||||
|
||||
public TileLogic(String namespace, String name) {
|
||||
super(namespace, name);
|
||||
}
|
||||
|
||||
public boolean canOccupyFace(TileTickContext context) {
|
||||
return canOccupyFace(context.getFace());
|
||||
}
|
||||
|
||||
public boolean canOccupyFace(BlockFace face) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isSolid(TileTickContext context) {
|
||||
return isSolid();
|
||||
}
|
||||
|
||||
public boolean isSolid() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package ru.windcorp.progressia.server.world.tile;
|
||||
|
||||
import ru.windcorp.progressia.common.util.NamespacedRegistry;
|
||||
|
||||
public class TileLogicRegistry extends NamespacedRegistry<TileLogic> {
|
||||
|
||||
private static final TileLogicRegistry INSTANCE = new TileLogicRegistry();
|
||||
|
||||
public static TileLogicRegistry getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package ru.windcorp.progressia.server.world.tile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.common.world.block.BlockData;
|
||||
import ru.windcorp.progressia.common.world.block.BlockFace;
|
||||
import ru.windcorp.progressia.common.world.tile.TileData;
|
||||
import ru.windcorp.progressia.server.world.ChunkTickContext;
|
||||
import ru.windcorp.progressia.server.world.block.BlockLogic;
|
||||
|
||||
public interface TileTickContext extends ChunkTickContext {
|
||||
|
||||
/**
|
||||
* Returns the current world coordinates.
|
||||
* @return the world coordinates of the tile being ticked
|
||||
*/
|
||||
Vec3i getCoords();
|
||||
|
||||
/**
|
||||
* Returns the current chunk coordinates.
|
||||
* @return the chunk coordinates of the tile being ticked
|
||||
*/
|
||||
Vec3i getChunkCoords();
|
||||
|
||||
/**
|
||||
* Returns the current block face. This face is always
|
||||
* {@linkplain BlockFace#isPrimary() primary}.
|
||||
* @return the block face that the tile being ticked occupies
|
||||
*/
|
||||
BlockFace getFace();
|
||||
|
||||
/**
|
||||
* Returns the current layer.
|
||||
* @return the layer that the tile being ticked occupies in the tile stack
|
||||
*/
|
||||
int getLayer();
|
||||
|
||||
default TileLogic getTile() {
|
||||
return getTiles().get(getLayer());
|
||||
}
|
||||
|
||||
default TileData getTileData() {
|
||||
return getTileDataList().get(getLayer());
|
||||
}
|
||||
|
||||
default List<TileLogic> getTiles() {
|
||||
return getChunk().getTiles(getChunkCoords(), getFace());
|
||||
}
|
||||
|
||||
default List<TileLogic> getTilesOrNull() {
|
||||
return getChunk().getTilesOrNull(getChunkCoords(), getFace());
|
||||
}
|
||||
|
||||
default List<TileData> getTileDataList() {
|
||||
return getChunkData().getTiles(getChunkCoords(), getFace());
|
||||
}
|
||||
|
||||
default List<TileData> getTileDataListOrNull() {
|
||||
return getChunkData().getTilesOrNull(getChunkCoords(), getFace());
|
||||
}
|
||||
|
||||
default BlockLogic getBlock() {
|
||||
return getChunk().getBlock(getChunkCoords());
|
||||
}
|
||||
|
||||
default BlockData getBlockData() {
|
||||
return getChunkData().getBlock(getChunkCoords());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package ru.windcorp.progressia.server.world.tile;
|
||||
|
||||
import ru.windcorp.progressia.server.world.Changer;
|
||||
|
||||
public interface UpdatableTile {
|
||||
|
||||
void update(TileTickContext context, Changer changer);
|
||||
|
||||
}
|
BIN
src/main/resources/assets/textures/entities/javapony.png
Normal file
BIN
src/main/resources/assets/textures/entities/javapony.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
34
src/main/resources/log4j2.xml
Normal file
34
src/main/resources/log4j2.xml
Normal file
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="WARN">
|
||||
<Properties>
|
||||
<Property name="LOG_PATTERN">%d{yyyy-MM-dd'T'HH:mm:ss.SSSZ} %p %m%n</Property>
|
||||
<Property name="APP_LOG_ROOT">logs</Property>
|
||||
</Properties>
|
||||
|
||||
<Appenders>
|
||||
|
||||
<Console name="Console" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
|
||||
</Console>
|
||||
|
||||
<RollingFile name="FileLog" fileName="${APP_LOG_ROOT}/game.log"
|
||||
filePattern="${APP_LOG_ROOT}/game-%d{yyyy-MM-dd}-%i.log">
|
||||
<LevelRangeFilter minLevel="FATAL" maxLevel="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
|
||||
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
|
||||
<Policies>
|
||||
<SizeBasedTriggeringPolicy size="18MB" />
|
||||
</Policies>
|
||||
<DefaultRolloverStrategy max="10"/>
|
||||
</RollingFile>
|
||||
|
||||
</Appenders>
|
||||
|
||||
<Loggers>
|
||||
|
||||
<Root level="info">
|
||||
<AppenderRef ref="FileLog" />
|
||||
<AppenderRef ref="Console" />
|
||||
</Root>
|
||||
|
||||
</Loggers>
|
||||
</Configuration>
|
Reference in New Issue
Block a user