Browse Source

recoded most features and more dirty to be faster

Kajetan Johannes Hammerle 2 years ago
parent
commit
f33191df97

+ 655 - 6
client/Main.cpp

@@ -1,11 +1,660 @@
-#include "client/Game.h"
-#include "client/GameClient.h"
-#include "client/rendering/Engine.h"
+#include "GLFW/glfw3.h"
 
-int main() {
-    if(GameClient::init() || Engine::init() || Game::init()) {
+#include "common/Box.h"
+#include "common/Packets.h"
+#include "data/Array.h"
+#include "data/HashMap.h"
+#include "data/RingBuffer.h"
+#include "math/Frustum.h"
+#include "network/Client.h"
+#include "rendering/Shader.h"
+#include "rendering/Texture.h"
+#include "rendering/VertexBuffer.h"
+#include "rendering/Window.h"
+#include "utils/Buffer.h"
+
+static constexpr int WORLD_SIZE = 16;
+
+static Array<bool, WORLD_SIZE * WORLD_SIZE * WORLD_SIZE> world(true);
+static Shader shader;
+static Shader fontShader;
+static VertexBuffer vertexBuffer;
+static VertexBuffer markVertexBuffer;
+static VertexBuffer fontBuffer;
+static Texture fontTexture;
+static bool dirtyVertexBuffer = true;
+static int vertices = 0;
+static Frustum frustum(80.0f, 0.1f, 1000.0f);
+
+static Vector3 lastPosition(8.0f, 30.0f, 8.0f);
+static Vector3 position(lastPosition);
+static float lastWidthAngle = 0.0f;
+static float widthAngle = lastWidthAngle;
+static float lastLengthAngle = 0.0f;
+static float lengthAngle = lastLengthAngle;
+static Vector3 velocity;
+static Vector3 acceleration;
+static bool onGround = false;
+
+static Window::Controls::ButtonId leftKey;
+static Window::Controls::ButtonId rightKey;
+static Window::Controls::ButtonId upKey;
+static Window::Controls::ButtonId downKey;
+static Window::Controls::ButtonId jumpKey;
+static Window::Controls::ButtonId sneakKey;
+static Window::Controls::ButtonId escapeKey;
+static Window::Controls::ButtonId chatKey;
+static Window::Controls::ButtonId sendChatKey;
+static Window::Controls::ButtonId primaryClick;
+
+static bool trappedMoused = false;
+
+static Vector3 up;
+static Vector3 down;
+static Vector3 left;
+static Vector3 right;
+static Vector3 front;
+static Vector3 back;
+
+static Vector3 focus;
+static bool hasFocus = false;
+
+struct Player {
+    Vector3 lastPosition;
+    Vector3 position;
+};
+
+static HashMap<int, Player> players;
+
+typedef StringBuffer<50> ChatMessage;
+static Array<ChatMessage, 20> chat;
+static int chatIndex = 0;
+static bool renderInput = false;
+
+static void addToChat(const ChatMessage& msg) {
+    chat[chatIndex] = msg;
+    chatIndex = (chatIndex + 1) % chat.getLength();
+}
+
+static bool isRunning() {
+    return !Window::shouldClose();
+    // return !Window::shouldClose() &&
+    //       (Client::isConnecting() || Client::isConnected());
+}
+
+static void set(int x, int y, int z, bool b) {
+    if(x < 0 || x >= WORLD_SIZE || y < 0 || y >= WORLD_SIZE || z < 0 ||
+       z >= WORLD_SIZE) {
+        return;
+    }
+    world[x * WORLD_SIZE * WORLD_SIZE + y * WORLD_SIZE + z] = b;
+    dirtyVertexBuffer = true;
+}
+
+static void onPacket(InPacket& in) {
+    uint8 type = 0;
+    if(in.readU8(type)) {
+        puts("no data");
+        return;
+    }
+    switch(static_cast<Packet::Type>(type)) {
+        case Packet::Type::WORLD: {
+            for(bool& b : world) {
+                uint8 data = 0;
+                if(in.readU8(data)) {
+                    puts("too less data in world packet");
+                    return;
+                }
+                b = data;
+            }
+            dirtyVertexBuffer = true;
+            break;
+        }
+        case Packet::Type::SET_BLOCK: {
+            Vector3 pos;
+            in.readFloat(pos[0]);
+            in.readFloat(pos[1]);
+            in.readFloat(pos[2]);
+            uint8 type;
+            in.readU8(type);
+            set(pos[0], pos[1], pos[2], type);
+            break;
+        }
+        case Packet::Type::PLAYER: {
+            Vector3 pos;
+            in.readFloat(pos[0]);
+            in.readFloat(pos[1]);
+            in.readFloat(pos[2]);
+            int client = -1;
+            in.readS32(client);
+
+            Player* p = players.search(client);
+            if(p != nullptr) {
+                p->position = pos;
+            } else {
+                players.add(client, {pos, pos});
+            }
+            break;
+        }
+        case Packet::Type::CHAT: {
+            ChatMessage msg;
+            uint32 u;
+            int i = 0;
+            while(!in.readU32(u)) {
+                i++;
+                msg.appendUnicode(u);
+            }
+            printf("%d\n", i);
+            addToChat(msg);
+            break;
+        }
+        default: printf("invalid package type %d\n", static_cast<int>(type));
+    }
+}
+
+static void onDisconnect() {
+    puts("Disconnect");
+}
+
+static void addTriangle(Buffer& buffer, const Vector3& a, const Vector3& b,
+                        const Vector3& c) {
+    Vector3 normal = (b - a).cross(c - a);
+    buffer.add(a).add(normal).add(b).add(normal).add(c).add(normal);
+}
+
+static bool init() {
+    Error e =
+        shader.compile("resources/shader/test.vs", "resources/shader/test.fs");
+    if(e.has()) {
+        e.message.printLine();
+        return true;
+    }
+    e = fontShader.compile("resources/shader/fontTest.vs",
+                           "resources/shader/fontTest.fs");
+    if(e.has()) {
+        e.message.printLine();
+        return true;
+    }
+    e = fontTexture.load("resources/font8x8.png", 0);
+    if(e.has()) {
+        e.message.printLine();
+        return true;
+    }
+    vertexBuffer.init(VertexBuffer::Attributes().addFloat(3).addFloat(3));
+    markVertexBuffer.init(VertexBuffer::Attributes().addFloat(3).addFloat(3));
+    fontBuffer.init(VertexBuffer::Attributes().addFloat(3).addFloat(2));
+
+    Vector3 v000(0, 0, 0);
+    Vector3 v001(0, 0, 1);
+    Vector3 v010(0, 1, 0);
+    Vector3 v011(0, 1, 1);
+    Vector3 v100(1, 0, 0);
+    Vector3 v101(1, 0, 1);
+    Vector3 v110(1, 1, 0);
+    Vector3 v111(1, 1, 1);
+
+    Buffer buffer(100);
+    addTriangle(buffer, v000, v100, v001);
+    addTriangle(buffer, v100, v101, v001);
+    addTriangle(buffer, v010, v011, v110);
+    addTriangle(buffer, v110, v011, v111);
+    addTriangle(buffer, v000, v001, v010);
+    addTriangle(buffer, v001, v011, v010);
+    addTriangle(buffer, v100, v110, v101);
+    addTriangle(buffer, v101, v110, v111);
+    addTriangle(buffer, v001, v101, v011);
+    addTriangle(buffer, v111, v011, v101);
+    addTriangle(buffer, v000, v010, v100);
+    addTriangle(buffer, v110, v100, v010);
+    markVertexBuffer.setStaticData(buffer.getLength(), buffer);
+
+    Client::setPacketHandler(onPacket);
+    Client::setDisconnectHandler(onDisconnect);
+
+    leftKey = Window::Controls::add("Left");
+    Window::Controls::bindKey(leftKey, GLFW_KEY_A);
+    rightKey = Window::Controls::add("Right");
+    Window::Controls::bindKey(rightKey, GLFW_KEY_D);
+    upKey = Window::Controls::add("Up");
+    Window::Controls::bindKey(upKey, GLFW_KEY_W);
+    downKey = Window::Controls::add("Right");
+    Window::Controls::bindKey(downKey, GLFW_KEY_S);
+    jumpKey = Window::Controls::add("Jump");
+    Window::Controls::bindKey(jumpKey, GLFW_KEY_SPACE);
+    sneakKey = Window::Controls::add("Sneak");
+    Window::Controls::bindKey(sneakKey, GLFW_KEY_LEFT_SHIFT);
+    escapeKey = Window::Controls::add("Escape");
+    Window::Controls::bindKey(escapeKey, GLFW_KEY_ESCAPE);
+    chatKey = Window::Controls::add("Chat");
+    Window::Controls::bindKey(chatKey, GLFW_KEY_T);
+    sendChatKey = Window::Controls::add("Send Chat");
+    Window::Controls::bindKey(sendChatKey, GLFW_KEY_ENTER);
+    primaryClick = Window::Controls::add("Primary Click");
+    Window::Controls::bindMouse(primaryClick, GLFW_MOUSE_BUTTON_LEFT);
+    return false;
+}
+
+static void updateDirections(float lag) {
+    front.setAngles(Math::interpolate(lastLengthAngle, lengthAngle, lag),
+                    Math::interpolate(lastWidthAngle, widthAngle, lag));
+    back = -front;
+    right = front.cross(Vector3(0.0f, 1.0f, 0.0f));
+    right.normalize();
+    left = -right;
+    up = front.cross(left);
+    down = -up;
+}
+
+static bool isAir(int x, int y, int z) {
+    if(x < 0 || x >= WORLD_SIZE || y < 0 || y >= WORLD_SIZE || z < 0 ||
+       z >= WORLD_SIZE) {
+        return true;
+    }
+    return !world[x * WORLD_SIZE * WORLD_SIZE + y * WORLD_SIZE + z];
+}
+
+static List<Box> getBoxes(const Box& box) {
+    int minX = floorf(box.getMin()[0]);
+    int minY = floorf(box.getMin()[1]);
+    int minZ = floorf(box.getMin()[2]);
+    int maxX = floorf(box.getMax()[0]);
+    int maxY = floorf(box.getMax()[1]);
+    int maxZ = floorf(box.getMax()[2]);
+
+    Box base(Vector3(1.0f, 1.0f, 1.0f));
+    List<Box> boxes;
+    for(int x = minX; x <= maxX; x++) {
+        for(int y = minY; y <= maxY; y++) {
+            for(int z = minZ; z <= maxZ; z++) {
+                if(!isAir(x, y, z)) {
+                    boxes.add(base.offset(Vector3(x, y, z)));
+                }
+            }
+        }
+    }
+    return boxes;
+}
+
+static Vector3 limitMove() {
+    Vector3 move = velocity;
+    Box box(Vector3(0.8f, 0.8f, 0.8f));
+    box = box.offset(position - Vector3(0.4f, 0.0f, 0.4f));
+
+    List<Box> boxes = getBoxes(box.expand(move));
+    if(boxes.getLength() == 0) {
+        return move;
+    }
+    Vector3 realMove;
+
+    constexpr float step = 0.05f;
+    while(move[0] != 0.0f || move[1] != 0.0f || move[2] != 0.0f) {
+        for(int i = 0; i < 3; i++) {
+            Vector3 old = realMove;
+            if(move[i] > step) {
+                realMove[i] += step;
+                move[i] -= step;
+            } else if(move[i] < -step) {
+                realMove[i] -= step;
+                move[i] += step;
+            } else if(move[i] != 0.0f) {
+                realMove[i] += move[i];
+                move[i] = 0.0f;
+            }
+            Box moved = box.offset(realMove);
+            for(const Box& box : boxes) {
+                if(box.collidesWith(moved)) {
+                    move[i] = 0.0f;
+                    realMove = old;
+                    break;
+                }
+            }
+        }
+    }
+    return realMove;
+}
+
+static void tick() {
+    if(renderInput) {
+        if(Window::Controls::wasReleased(sendChatKey)) {
+            OutPacket out = Packet::build(Packet::Type::CHAT);
+            for(uint32 u : Window::Input::getUnicode()) {
+                out.writeU32(u);
+            }
+            Client::send(out, PacketType::RELIABLE);
+            Window::Input::reset();
+        }
+        if(Window::Controls::wasReleased(escapeKey)) {
+            Window::Input::disable();
+            Window::trapCursor();
+            trappedMoused = true;
+            renderInput = false;
+        }
+    } else {
+        if(Window::Controls::isDown(chatKey)) {
+            Window::Input::enable();
+            Window::freeCursor();
+            trappedMoused = false;
+            renderInput = true;
+        }
+        if(Window::Controls::wasReleased(primaryClick)) {
+            Window::trapCursor();
+            trappedMoused = true;
+        }
+        if(Window::Controls::wasReleased(escapeKey)) {
+            Window::freeCursor();
+            trappedMoused = false;
+        }
+    }
+
+    lastPosition = position;
+    lastWidthAngle = widthAngle;
+    lastLengthAngle = lengthAngle;
+
+    for(Player& p : players.values()) {
+        p.lastPosition = p.position;
+    }
+    Client::tick();
+
+    updateDirections(0.0f);
+
+    Vector3 b = back;
+    b[1] = 0.0f;
+    b.normalize();
+
+    Vector3 r = right;
+    r[1] = 0.0f;
+    r.normalize();
+
+    if(!renderInput) {
+        Vector3 force;
+        if(Window::Controls::isDown(downKey)) {
+            force += b;
+        }
+        if(Window::Controls::isDown(upKey)) {
+            force -= b;
+        }
+        if(Window::Controls::isDown(leftKey)) {
+            force -= r;
+        }
+        if(Window::Controls::isDown(rightKey)) {
+            force += r;
+        }
+        if(force.squareLength() > 0.0f) {
+            force.normalize();
+        }
+        acceleration += force * 0.1f;
+
+        if(Window::Controls::isDown(jumpKey) && onGround) {
+            acceleration[1] += (0.42f / 0.98f + 0.08f);
+        }
+    }
+
+    if(trappedMoused) {
+        Vector2 diff = (Window::Controls::getLastMousePosition() -
+                        Window::Controls::getMousePosition()) *
+                       0.1f;
+        widthAngle += diff[1];
+        lengthAngle += diff[0];
+        if(widthAngle > 89.0f) {
+            widthAngle = 89.0f;
+        }
+        if(widthAngle < -89.0f) {
+            widthAngle = -89.0f;
+        }
+    }
+
+    hasFocus = false;
+    Vector3 p = position + Vector3(0.0f, 0.8f, 0.0f);
+    Vector3 step = front * 0.125f;
+    for(int i = 0; i < 80; i++) {
+        if(!isAir(p[0], p[1], p[2])) {
+            hasFocus = true;
+            focus = Vector3(static_cast<int>(p[0]), static_cast<int>(p[1]),
+                            static_cast<int>(p[2]));
+            break;
+        }
+        p += step;
+    }
+
+    if(hasFocus && Window::Controls::wasReleased(primaryClick) &&
+       !renderInput) {
+        set(focus[0], focus[1], focus[2], false);
+        dirtyVertexBuffer = true;
+
+        OutPacket out = Packet::build(Packet::Type::SET_BLOCK);
+        out.writeFloat(focus[0]);
+        out.writeFloat(focus[1]);
+        out.writeFloat(focus[2]);
+        out.writeU8(0);
+        Client::send(out, PacketType::RELIABLE);
+    }
+
+    OutPacket out = Packet::build(Packet::Type::PLAYER);
+    out.writeFloat(position[0]);
+    out.writeFloat(position[1]);
+    out.writeFloat(position[2]);
+    out.writeS32(-1);
+    Client::send(out, PacketType::RELIABLE);
+
+    velocity += acceleration;
+    velocity *= Vector3(0.686f, 0.98f, 0.686f);
+    acceleration = Vector3(0.0f, -0.08f, 0.0f);
+
+    Vector3 move = limitMove();
+    if(move[1] + position[1] < 0.0f) {
+        move[1] = -position[1];
+    }
+    position += move;
+    onGround = move[1] == 0.0f && velocity[1] < 0.0f;
+    velocity = move;
+}
+
+static void addCube(Buffer& buffer, int x, int y, int z) {
+    if(isAir(x, y, z)) {
+        return;
+    }
+    Vector3 v000(x, y, z);
+    Vector3 v001(x, y, z + 1);
+    Vector3 v010(x, y + 1, z);
+    Vector3 v011(x, y + 1, z + 1);
+    Vector3 v100(x + 1, y, z);
+    Vector3 v101(x + 1, y, z + 1);
+    Vector3 v110(x + 1, y + 1, z);
+    Vector3 v111(x + 1, y + 1, z + 1);
+
+    if(isAir(x, y - 1, z)) {
+        addTriangle(buffer, v000, v100, v001);
+        addTriangle(buffer, v100, v101, v001);
+    }
+    if(isAir(x, y + 1, z)) {
+        addTriangle(buffer, v010, v011, v110);
+        addTriangle(buffer, v110, v011, v111);
+    }
+    if(isAir(x - 1, y, z)) {
+        addTriangle(buffer, v000, v001, v010);
+        addTriangle(buffer, v001, v011, v010);
+    }
+    if(isAir(x + 1, y, z)) {
+        addTriangle(buffer, v100, v110, v101);
+        addTriangle(buffer, v101, v110, v111);
+    }
+    if(isAir(x, y, z + 1)) {
+        addTriangle(buffer, v001, v101, v011);
+        addTriangle(buffer, v111, v011, v101);
+    }
+    if(isAir(x, y, z - 1)) {
+        addTriangle(buffer, v000, v010, v100);
+        addTriangle(buffer, v110, v100, v010);
+    }
+}
+
+static void buildRenderingBuffer() {
+    Buffer buffer(100);
+    for(int x = 0; x < WORLD_SIZE; x++) {
+        for(int y = 0; y < WORLD_SIZE; y++) {
+            for(int z = 0; z < WORLD_SIZE; z++) {
+                addCube(buffer, x, y, z);
+            }
+        }
+    }
+    vertices = buffer.getLength() / (2 * sizeof(Vector3));
+    vertexBuffer.setStaticData(buffer.getLength(), buffer);
+}
+
+static void renderString(const char* text) {
+    static Buffer buffer(50);
+    buffer.clear();
+    constexpr float fontSize = 8.0f;
+    constexpr float fontStep = 8.0f / 128.0f;
+    int index = 0;
+    Vector3 pos;
+    int vertices = 0;
+    while(text[index] != '\0') {
+        Vector3 right = pos + Vector3(fontSize, 0.0f, 0.0f);
+        Vector3 down = pos + Vector3(0.0f, fontSize, 0.0f);
+        Vector3 downRight = pos + Vector3(fontSize, fontSize, 0.0f);
+
+        int i = text[index];
+        if(i < 0 && text[index + 1] != '\0') {
+            index++;
+            i = ((i & 0x1F) << 6) | (text[index] & 0x3F);
+        }
+        Vector2 tPos(fontStep * (i % 16), fontStep * (i / 16));
+        Vector2 tRight = tPos + Vector2(fontStep, 0.0f);
+        Vector2 tDown = tPos + Vector2(0.0f, fontStep);
+        Vector2 tDownRight = tPos + Vector2(fontStep, fontStep);
+
+        buffer.add(pos).add(tPos).add(down).add(tDown).add(right).add(tRight);
+        buffer.add(down).add(tDown).add(right).add(tRight).add(downRight).add(
+            tDownRight);
+        pos += Vector3(fontSize, 0.0f, 0.0f);
+        vertices += 6;
+        index++;
+    }
+    fontBuffer.setDynamicData(buffer.getLength(), buffer);
+    fontBuffer.draw(vertices);
+}
+
+static void render(float lag) {
+    GL::clear();
+    GL::enableDepthTesting();
+    if(dirtyVertexBuffer) {
+        dirtyVertexBuffer = false;
+        buildRenderingBuffer();
+        puts("rebuilt buffer");
+    }
+
+    shader.use();
+    GL::setViewport(Window::getSize()[0], Window::getSize()[1]);
+    const Matrix& proj = frustum.updateProjection(Window::getSize());
+    shader.setMatrix("proj", proj.getValues());
+    updateDirections(lag);
+    Matrix view;
+    Vector3 center = Math::interpolate(lastPosition, position, lag) +
+                     Vector3(0.0f, 0.8f, 0.0f);
+    view.set(0, Vector4(right[0], right[1], right[2], right.dot(-center)));
+    view.set(1, Vector4(up[0], up[1], up[2], up.dot(-center)));
+    view.set(2, Vector4(back[0], back[1], back[2], back.dot(-center)));
+    view.set(3, Vector4(0.0f, 0.0f, 0.0f, 1.0f));
+    shader.setMatrix("view", view.getValues());
+    shader.setVector("color", Vector3(1.0f, 1.0f, 1.0f));
+    Matrix model;
+    shader.setMatrix("model", model.getValues());
+    vertexBuffer.draw(vertices);
+
+    if(hasFocus) {
+        shader.setVector("color", Vector3(0.8f, 0.6f, 0.6f));
+        model.translate(Vector3(-0.5f, -0.5f, -0.5f));
+        model.scale(1.01f);
+        model.translate(Vector3(0.5f, 0.5f, 0.5f));
+        model.translate(focus);
+        shader.setMatrix("model", model.getValues());
+        markVertexBuffer.draw(36);
+    }
+
+    shader.setVector("color", Vector3(1.0f, 0.0f, 0.0f));
+    for(const Player& p : players.values()) {
+        model.translateTo(Vector3(-0.5f, -0.5f, -0.5f));
+        model.scale(0.8f);
+        model.translate(Math::interpolate(p.lastPosition, p.position, lag) +
+                        Vector3(0.0f, 0.4f, 0.0f));
+        shader.setMatrix("model", model.getValues());
+        markVertexBuffer.draw(36);
+    }
+
+    shader.setMatrix("proj", Matrix().getValues());
+    shader.setMatrix("view", Matrix().getValues());
+    shader.setVector("color", Vector3(1.0f, 0.0f, 1.0f));
+    model.translateTo(Vector3(-0.5f, -0.5f, -0.5f));
+    model.scale(0.05f);
+    shader.setMatrix("model", model.getValues());
+    markVertexBuffer.draw(36);
+
+    GL::disableDepthTesting();
+    GL::enableBlending();
+    fontShader.use();
+    fontShader.setMatrix("proj", Matrix().getValues());
+    view.translateTo(Vector3(0.0f, 0.0f, 0.0f));
+    IntVector2 size = Window::getSize();
+    view.scale(Vector3(2.0f / size[0], -2.0f / size[1], 1.0f));
+    view.translate(Vector3(-1.0f, 1.0f, 0.0f));
+    fontShader.setMatrix("view", view.getValues());
+    fontTexture.bindTo(0);
+
+    for(int i = 0; i < chat.getLength(); i++) {
+        model.translateTo(Vector3(0.0f, i * 8.0f, 0.0f)).scale(3.0f);
+        fontShader.setMatrix("model", model.getValues());
+        renderString(chat[(i + chatIndex) % chat.getLength()]);
+    }
+
+    if(renderInput) {
+        model.translateTo(Vector3(0.0f, chat.getLength() * 8.0f, 0.0f))
+            .scale(3.0f);
+        fontShader.setMatrix("model", model.getValues());
+        StringBuffer<256> s;
+        Window::Input::toString(s);
+        renderString(s);
+
+        model
+            .translateTo(Vector3(Window::Input::getCursor() * 8.0f,
+                                 chat.getLength() * 8.0f + 2.0f, 0.0f))
+            .scale(3.0f);
+        fontShader.setMatrix("model", model.getValues());
+        renderString("_");
+    }
+
+    GL::disableBlending();
+}
+
+int main(int argAmount, const char* const* args) {
+    const char* server = "127.0.0.1";
+    if(argAmount >= 2) {
+        server = args[1];
+    }
+    Error e = Client::start();
+    if(e.has()) {
+        e.message.printLine();
+        return 0;
+    }
+    e = Client::connect(server, 11196, 40);
+    if(e.has()) {
+        e.message.printLine();
+        return 0;
+    }
+    Window::Options options(4, 3, IntVector2(1024, 600), false, "test");
+    e = Window::open(options);
+    if(e.has()) {
+        e.message.printLine();
+        Client::stop();
+        return 0;
+    }
+    if(init()) {
+        Client::stop();
         return 0;
     }
-    Engine::run();
+    Window::show();
+    Window::run<isRunning, tick, render>(50'000'000);
+    Window::close();
+    Client::stop();
     return 0;
 }

+ 7 - 0
common/Packets.cpp

@@ -0,0 +1,7 @@
+#include "common/Packets.h"
+
+OutPacket Packet::build(Type t) {
+    OutPacket out(100);
+    out.writeU8(static_cast<uint8>(t));
+    return out;
+}

+ 12 - 0
common/Packets.h

@@ -0,0 +1,12 @@
+#ifndef PACKETS_H
+#define PACKETS_H
+
+#include "network/Packet.h"
+
+namespace Packet {
+    enum class Type { WORLD, SET_BLOCK, PLAYER, CHAT };
+
+    OutPacket build(Type t);
+}
+
+#endif

+ 6 - 26
meson.build

@@ -1,38 +1,18 @@
 project('cubes plus plus', 'cpp')
 
 src_common = [
-    'common/Block.cpp', 
-    'common/BlockStorage.cpp',
+    'common/Packets.cpp',
     'common/Box.cpp',
-    'common/entities/Entity.cpp',
-    'common/network/toserver/PlayerUpdatePacket.cpp',
-    'common/network/toclient/EntityUpdatePacket.cpp',
 ]
 
-src_server = ['server/Main.cpp',
-    'server/Game.cpp',
-    'server/World.cpp', 
-    'server/commands/Commands.cpp',
-    'server/commands/DefaultCommands.cpp',
-    'server/commands/SnuviCommands.cpp',
+src_server = [
+    'server/Main.cpp',
+    'raw-terminal/Console.c',
     'server/snuviscript/Snuvi.cpp',
-    'server/GameServer.cpp',
-    'server/entities/ServerPlayer.cpp',
-    'server/packets/WorldPackets.cpp',
 ]
 
-src_client = ['client/Main.cpp',
-    'client/rendering/Engine.cpp',
-    'client/rendering/Mesh.cpp',
-    'client/Game.cpp',
-    'client/GameClient.cpp',
-    'client/World.cpp', 
-    'client/rendering/ShaderMatrix.cpp',
-    'client/input/Controller.cpp',
-    'client/rendering/Renderer.cpp',
-    'client/gui/BaseGUI.cpp',
-    'client/gui/StartGUI.cpp',
-    'client/packets/WorldPackets.cpp',
+src_client = [
+    'client/Main.cpp',
 ]
 
 sources_test = ['tests/Main.cpp']

+ 1 - 1
raw-terminal

@@ -1 +1 @@
-Subproject commit 5d832b3daba5f53794dcb8d28a6459bd7f135b9d
+Subproject commit fb155139084ebbe385c73dd97c8a111180da7503

+ 3 - 3
resources/scripts/test.snuvi

@@ -1,8 +1,8 @@
 void main() {
     for(int i = 0; i < 5; i++) {
-        print("HaࠠI Th𐀠eröüäe\n");
+        print("Hi there\n");
     }
-    print("----------\n");
+    /*print("----------\n");
     while(true) {
         wait();
         print("Wusi\n");
@@ -18,5 +18,5 @@ void main() {
         }
         delete data;
         print("\n");
-    }
+    }*/
 }

+ 11 - 0
resources/shader/fontTest.fs

@@ -0,0 +1,11 @@
+#version 430
+
+layout(binding = 0) uniform sampler2D samp;
+
+in vec2 varTex;
+
+out vec4 outColor;
+
+void main(void) {
+    outColor = vec4(1.0, 0.0, 1.0, texture(samp, varTex).x);
+}

+ 15 - 0
resources/shader/fontTest.vs

@@ -0,0 +1,15 @@
+#version 430
+
+layout (location = 0) in vec3 position;
+layout (location = 1) in vec2 tex;
+
+uniform mat4 proj;
+uniform mat4 view;
+uniform mat4 model;
+
+out vec2 varTex;
+
+void main(void) { 
+    varTex = tex;
+    gl_Position = proj * view * model * vec4(position, 1.0);
+}

+ 11 - 0
resources/shader/test.fs

@@ -0,0 +1,11 @@
+#version 430
+
+uniform vec3 color;
+
+in float varLight;
+
+out vec4 outColor;
+
+void main(void) {
+    outColor = vec4(color * varLight, 1.0);
+}

+ 17 - 0
resources/shader/test.vs

@@ -0,0 +1,17 @@
+#version 430
+
+layout (location = 0) in vec3 position;
+layout (location = 1) in vec3 normal;
+
+uniform mat4 proj;
+uniform mat4 view;
+uniform mat4 model;
+
+out float varLight;
+
+void main(void) { 
+    varLight = 1.0f;
+    varLight -= abs(normal.x) * 0.15;
+    varLight -= abs(normal.z) * 0.30;
+    gl_Position = proj * view * model * vec4(position, 1.0);
+}

+ 160 - 11
server/Main.cpp

@@ -1,18 +1,164 @@
-#include "server/Game.h"
-#include "server/GameServer.h"
-#include "server/commands/Commands.h"
+#include "common/Packets.h"
+#include "data/Array.h"
+#include "data/HashMap.h"
+#include "math/Vector.h"
+#include "network/Server.h"
+#include "raw-terminal/Console.h"
 #include "server/snuviscript/Snuvi.h"
+#include "utils/Clock.h"
+#include "utils/Random.h"
+#include "utils/SplitString.h"
 
-void loop() {
+static constexpr int WORLD_SIZE = 16;
+
+static bool running = true;
+static Array<bool, WORLD_SIZE * WORLD_SIZE * WORLD_SIZE> world(false);
+
+static HashMap<Server::Client, int> players;
+
+static void handleCommands() {
+    const ConsoleLine* line = readConsoleLine("> ");
+    if(line != nullptr) {
+        StringBuffer<50> buffer;
+        for(int i = 0; i < line->length; i++) {
+            buffer.appendUnicode(line->data[i]);
+        }
+        buffer.printLine();
+        if(buffer == "stop") {
+            running = false;
+        }
+    }
+}
+
+static void handleCommand(List<uint32>& s) {
+    StringBuffer<256> buffer;
+    for(uint32 u : s) {
+        buffer.appendUnicode(u);
+    }
+    SplitString<256> split(buffer);
+    if(split.getLength() >= 1) {
+        if(strcmp(split[0], "/script") == 0) {
+            if(split.getLength() >= 2) {
+                Snuvi::start(split[1]);
+            } else {
+                puts("/script <script>");
+            }
+        }
+    }
+}
+
+static void set(int x, int y, int z, bool b) {
+    if(x < 0 || x >= WORLD_SIZE || y < 0 || y >= WORLD_SIZE || z < 0 ||
+       z >= WORLD_SIZE) {
+        return;
+    }
+    world[x * WORLD_SIZE * WORLD_SIZE + y * WORLD_SIZE + z] = b;
+
+    OutPacket out = Packet::build(Packet::Type::SET_BLOCK);
+    out.writeFloat(x);
+    out.writeFloat(y);
+    out.writeFloat(z);
+    out.writeU8(b);
+    Server::send(out, PacketType::RELIABLE);
+}
+
+static void onConnect(Server::Client client) {
+    OutPacket out = Packet::build(Packet::Type::WORLD);
+    for(bool b : world) {
+        out.writeU8(b);
+    }
+    Server::send(client, out, PacketType::RELIABLE);
+    players.add(client, 0);
+}
+
+static void onDisconnect(Server::Client client) {
+    players.remove(client);
+}
+
+static void onPacket(Server::Client client, InPacket& in) {
+    uint8 type = 0;
+    if(in.readU8(type)) {
+        puts("no data");
+        return;
+    }
+    switch(static_cast<Packet::Type>(type)) {
+        case Packet::Type::SET_BLOCK: {
+            Vector3 pos;
+            in.readFloat(pos[0]);
+            in.readFloat(pos[1]);
+            in.readFloat(pos[2]);
+            uint8 type;
+            in.readU8(type);
+            set(pos[0], pos[1], pos[2], type);
+            break;
+        }
+        case Packet::Type::PLAYER: {
+            Vector3 pos;
+            in.readFloat(pos[0]);
+            in.readFloat(pos[1]);
+            in.readFloat(pos[2]);
+
+            OutPacket out = Packet::build(Packet::Type::PLAYER);
+            out.writeFloat(pos[0]);
+            out.writeFloat(pos[1]);
+            out.writeFloat(pos[2]);
+            out.writeS32(client);
+            for(Server::Client c : players.keys()) {
+                if(c != client) {
+                    Server::send(c, out, PacketType::RELIABLE);
+                }
+            }
+            break;
+        }
+        case Packet::Type::CHAT: {
+            List<uint32> s;
+            uint32 u;
+            while(!in.readU32(u)) {
+                s.add(u);
+            }
+
+            if(s.getLength() > 0 && s[0] == '/') {
+                handleCommand(s);
+                return;
+            }
+
+            OutPacket out = Packet::build(Packet::Type::CHAT);
+            for(uint32 u : s) {
+                out.writeU32(u);
+            }
+            Server::send(out, PacketType::RELIABLE);
+            break;
+        }
+        default: printf("invalid package type %d\n", static_cast<int>(type));
+    }
+}
+
+static void init() {
+    Snuvi::init();
+    Server::setPacketHandler(onPacket);
+    Server::setConnectHandler(onConnect);
+    Server::setDisconnectHandler(onDisconnect);
+    Random r(0);
+    for(bool& b : world) {
+        b = r.next() & 1;
+    }
+}
+
+static void tick() {
+    handleCommands();
+    Server::tick();
+}
+
+static void loop() {
+    init();
     Clock clock;
     constexpr Clock::Nanos NANOS_PER_TICK = 50000000;
     Clock::Nanos lag = 0;
-    while(Game::isRunning()) {
+    while(running) {
         lag += clock.update();
         while(lag >= NANOS_PER_TICK) {
             lag -= NANOS_PER_TICK;
-            GameServer::tick();
-            Game::tick();
+            tick();
         }
         Clock::Nanos waitNanos = NANOS_PER_TICK - lag;
         if(waitNanos > 300000) {
@@ -22,12 +168,15 @@ void loop() {
 }
 
 int main() {
-    Snuvi::init();
-    Commands::init();
-    if(GameServer::init(11196, 50)) {
+    if(initConsole()) {
+        return 0;
+    }
+    Error e = Server::start(11196, 50);
+    if(e.has()) {
+        puts(e.message);
         return 0;
     }
-    Game::init();
     loop();
+    Server::stop();
     return 0;
 }

+ 8 - 2
server/snuviscript/Snuvi.cpp

@@ -1,9 +1,12 @@
 #include "server/snuviscript/Snuvi.h"
 #include "Compiler.h"
+#include "data/HashMap.h"
+#undef MATH_H
+#include "common/Packets.h"
 #include "libraries/Math.h"
 #include "libraries/Time.h"
+#include "network/Server.h"
 #include "tokenizer/Tokenizer.h"
-#include "utils/HashMap.h"
 #include "utils/StringBuffer.h"
 #include "vm/Script.h"
 
@@ -35,15 +38,18 @@ static void printString(Script* sc) {
     if(!sPopPointer(sc, &p) || sGetPointerLength(sc, &p, &length)) {
         return;
     }
+    OutPacket out = Packet::build(Packet::Type::CHAT);
     for(int i = 0; i < length; i++) {
         const void* data = sCheckAddress(sc, &p, sizeof(int));
         if(data != nullptr) {
             int c;
             memcpy(&c, data, sizeof(int));
             printf(unicode(c));
+            out.writeU32(c);
         }
         p.offset += sizeof(int);
     }
+    Server::send(out, PacketType::RELIABLE);
 }
 
 static void printInt32(Script* sc) {
@@ -60,7 +66,7 @@ static void wait(Script* sc) {
 static Snuvi::Event event = Snuvi::Event::NONE;
 
 static void getEvent(Script* sc) {
-    sPushInt32(sc, event);
+    sPushInt32(sc, static_cast<int>(event));
 }
 
 static void initPrinter() {

+ 1 - 1
server/snuviscript/Snuvi.h

@@ -5,7 +5,7 @@
 #include "utils/StringBuffer.h"
 
 namespace Snuvi {
-    enum Event { NONE, COMMAND };
+    enum class Event { NONE, COMMAND };
 
     void init();
 

+ 1 - 1
subprojects/gaming-core

@@ -1 +1 @@
-Subproject commit 25066d5c6adcd5a13e318ce99e3065b38cdea019
+Subproject commit 18790f58accfe58d37bc84eddd1b12c94f131449