#include "common/NetworkPackets.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" 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(100); out.writeU8(static_cast<uint8>(ToClientPacket::SET_BLOCK)); out.writeS32(x); out.writeS32(y); out.writeS32(z); out.writeU8(b); Server::send(out, PacketSendMode::RELIABLE); } static void onConnect(Server::Client client) { OutPacket out(100); out.writeU8(static_cast<uint8>(ToClientPacket::WORLD)); for(bool b : world) { out.writeU8(b); } Server::send(client, out, PacketSendMode::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.read(type)) { puts("no data"); return; } switch(static_cast<ToServerPacket>(type)) { case ToServerPacket::SET_BLOCK: { IntVector3 pos; in.read(pos); uint8 type; in.read(type); set(pos[0], pos[1], pos[2], type); break; } case ToServerPacket::PLAYER: { Vector3 pos; in.read(pos[0]); in.read(pos[1]); in.read(pos[2]); OutPacket out(100); out.writeU8(static_cast<uint8>(ToClientPacket::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, PacketSendMode::RELIABLE); } } break; } case ToServerPacket::CHAT: { List<uint32> s; uint32 u; while(!in.read(u)) { s.add(u); } if(s.getLength() > 0 && s[0] == '/') { handleCommand(s); return; } OutPacket out(100); out.writeU8(static_cast<uint8>(ToClientPacket::CHAT)); for(uint32 u : s) { out.writeU32(u); } Server::send(out, PacketSendMode::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(running) { lag += clock.update(); while(lag >= NANOS_PER_TICK) { lag -= NANOS_PER_TICK; tick(); } Clock::Nanos waitNanos = NANOS_PER_TICK - lag; if(waitNanos > 300000) { clock.wait(waitNanos); } } } int main() { if(initConsole()) { return 0; } Error e = Server::start(11196, 50); if(e.has()) { puts(e.message); return 0; } loop(); Server::stop(); return 0; }