#include "client/Main.h" #include "client/Controls.h" #include "client/Network.h" #include "client/Player.h" #include "client/World.h" #include "common/NetworkPackets.h" #include "data/Array.h" #include "data/RingBuffer.h" #include "math/Box.h" #include "math/View.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 Shader fontShader; static VertexBuffer markVertexBuffer; static VertexBuffer fontBuffer; static Texture fontTexture; HashMap players; static Array chat; static int chatIndex = 0; bool renderInput = false; void addToChat(const ChatMessage& msg) { chat[chatIndex] = msg; chatIndex = (chatIndex + 1) % chat.getLength(); } static bool isRunning() { return !Window::shouldClose(); } 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() { if(World::init()) { return true; } Error 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; } 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.setData(buffer, GL::STATIC_DRAW); Controls::init(); return false; } static void tick() { if(renderInput) { if(Controls::wasReleased(Controls::enter)) { OutPacket out(100); out.writeU8(static_cast(ToServerPacket::CHAT)); for(uint32 u : Window::Input::getUnicode()) { out.writeU32(u); } Client::send(out, PacketSendMode::RELIABLE); Window::Input::reset(); } if(Controls::wasReleased(Controls::escape)) { Window::Input::disable(); Window::trapCursor(); renderInput = false; } } else { if(Controls::isDown(Controls::chat)) { Window::Input::enable(); Window::freeCursor(); renderInput = true; } if(Controls::wasReleased(Controls::primaryClick)) { Window::trapCursor(); } if(Controls::wasReleased(Controls::escape)) { Window::freeCursor(); } } Player::tick(); for(OtherPlayer& p : players.values()) { p.position.update(); } Network::tick(); if(Controls::wasReleased(Controls::primaryClick) && !renderInput) { RayTrace rt = World::rayTrace(Player::getPosition() + Vector3(0.0f, 0.8f, 0.0f), Player::getLook(), 10.0f); if(rt.type == RayTrace::Type::BLOCK) { World::set(rt.block[0], rt.block[1], rt.block[2], false); OutPacket out(100); out.writeU8(static_cast(ToServerPacket::SET_BLOCK)); out.writeVector(rt.block); out.writeU8(0); Client::send(out, PacketSendMode::RELIABLE); } } OutPacket out(100); out.writeU8(static_cast(ToServerPacket::PLAYER)); out.writeVector(Player::getPosition()); out.writeS32(-1); Client::send(out, PacketSendMode::RELIABLE); } 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.setData(buffer, GL::DYNAMIC_DRAW); fontBuffer.draw(vertices); } static void render(float lag) { GL::clear(); GL::enableDepthTesting(); World::render(lag); RayTrace rt = World::rayTrace(Player::getPosition(lag) + Vector3(0.0f, 0.8f, 0.0f), Player::getLook(lag), 10.0f); if(rt.type == RayTrace::Type::BLOCK) { World::shader.setVector("color", Vector3(0.8f, 0.6f, 0.6f)); Matrix model; model.translate(Vector3(-0.5f, -0.5f, -0.5f)); model.scale(1.01f); model.translate(Vector3(0.5f, 0.5f, 0.5f)); model.translate(rt.block.toFloat()); World::shader.setMatrix("model", model); markVertexBuffer.draw(36); } World::shader.setVector("color", Vector3(1.0f, 0.0f, 0.0f)); for(const OtherPlayer& p : players.values()) { Matrix model; model.translateTo(Vector3(-0.5f, -0.5f, -0.5f)); model.scale(0.8f); model.translate(p.position.get(lag) + Vector3(0.0f, 0.4f, 0.0f)); World::shader.setMatrix("model", model); markVertexBuffer.draw(36); } World::shader.setMatrix("proj", Matrix()); World::shader.setMatrix("view", Matrix()); World::shader.setVector("color", Vector3(1.0f, 0.0f, 1.0f)); Matrix model; model.translateTo(Vector3(-0.5f, -0.5f, -0.5f)); model.scale(0.05f); World::shader.setMatrix("model", model); markVertexBuffer.draw(36); GL::disableDepthTesting(); GL::enableBlending(); fontShader.use(); fontShader.setMatrix("proj", Matrix()); Matrix v; IntVector2 size = Window::getSize(); v.scale(Vector3(2.0f / size[0], -2.0f / size[1], 1.0f)); v.translate(Vector3(-1.0f, 1.0f, 0.0f)); fontShader.setMatrix("view", v); 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); 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); 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); renderString("_"); } GL::disableBlending(); } static void startWindow() { Window::Options options(4, 3, IntVector2(1024, 600), false, "test"); Error e = Window::open(options); if(e.has()) { e.message.printLine(); return; } else if(!init()) { Window::show(); Window::run(50'000'000); } Window::close(); } int main(int argAmount, const char* const* args) { const char* server = "127.0.0.1"; if(argAmount >= 2) { server = args[1]; } if(Network::start(server)) { return 0; } startWindow(); Network::stop(); return 0; }