From 104592aabdc70b21065c35fe4d092fc6cdaa1f49 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Wed, 2 Sep 2015 22:33:08 +0200 Subject: [PATCH] client-side implementation of login packet chunk loading has to change: need to stop the client from generating chunks on its own and the server must be able to load chunks for multiple bases also, I've not written a single test for all this crap shame on me --- .gitignore | 1 + Makefile | 5 +++- building => doc/building | 4 +++ doc/protocol | 25 ++++++++++++++++ running => doc/running | 0 src/app/ClientState.cpp | 58 +++++++++++++++++++++++++++++++++++-- src/app/ClientState.hpp | 7 +++++ src/app/WorldState.cpp | 1 - src/app/runtime.cpp | 2 +- src/net/Client.hpp | 3 ++ src/net/Packet.hpp | 5 +++- src/net/Server.hpp | 2 ++ src/net/net.cpp | 62 ++++++++++++++++++++++++++++++++++++++-- 13 files changed, 166 insertions(+), 9 deletions(-) rename building => doc/building (90%) create mode 100644 doc/protocol rename running => doc/running (100%) diff --git a/.gitignore b/.gitignore index eeb5465..5a84607 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ blank.test build cachegrind.out.* callgrind.out.* +client-saves saves diff --git a/Makefile b/Makefile index e6e24d9..c23e9ac 100644 --- a/Makefile +++ b/Makefile @@ -67,6 +67,9 @@ run: $(ASSET_DEP) blank server: $(ASSET_DEP) blank ./blank --server --save-path saves/ +client: $(ASSET_DEP) blank + ./blank --client --save-path client-saves/ + gdb: $(ASSET_DEP) blank.debug gdb ./blank.debug @@ -88,7 +91,7 @@ clean: distclean: clean rm -f $(BIN) cachegrind.out.* callgrind.out.* - rm -Rf build saves + rm -Rf build client-saves saves .PHONY: all release debug profile tests run gdb cachegrind callgrind test clean distclean diff --git a/building b/doc/building similarity index 90% rename from building rename to doc/building index ef83775..b850668 100644 --- a/building +++ b/doc/building @@ -34,6 +34,10 @@ run: server: same as run, only in server mode +server: + same as run, only in client mode and the save path is set to + ./client-saved to prevent clashes with a running `make server` + test: build and run unittests diff --git a/doc/protocol b/doc/protocol new file mode 100644 index 0000000..723f3cf --- /dev/null +++ b/doc/protocol @@ -0,0 +1,25 @@ +Packets +======= + +Ping +---- + +To tell the other side we're still alive. +Both server and client will send this if they haven't sent something in +a while. + +Code: 0 +Payload: none + + +Login +----- + +Sent from client to serveri as a request to join. The server may +respond negatively if the player name is already taken or some cap has +been reached. + +Code: 1 +Payload: + player name, max 32 byte UTF-8 string, + shorter names should be zero terminated diff --git a/running b/doc/running similarity index 100% rename from running rename to doc/running diff --git a/src/app/ClientState.cpp b/src/app/ClientState.cpp index c371235..b4ed3f8 100644 --- a/src/app/ClientState.cpp +++ b/src/app/ClientState.cpp @@ -1,6 +1,7 @@ #include "ClientState.hpp" #include "Environment.hpp" +#include "init.hpp" #include "TextureIndex.hpp" namespace blank { @@ -9,19 +10,55 @@ ClientState::ClientState( Environment &env, const World::Config &wc, const WorldSave &ws, + const Interface::Config &ic, const Client::Config &cc ) : env(env) , block_types() , world(block_types, wc, ws) +, chunk_renderer(world, wc.load.load_dist) +, interface(ic, env, world) , client(cc, world) { + TextureIndex tex_index; + env.loader.LoadBlockTypes("default", block_types, tex_index); + chunk_renderer.LoadTextures(env.loader, tex_index); + chunk_renderer.FogDensity(wc.fog_density); + // TODO: better solution for initializing HUD + interface.SelectNext(); + client.SendLogin(ic.player_name); +} + +void ClientState::OnEnter() { + env.window.GrabMouse(); } void ClientState::Handle(const SDL_Event &event) { - if (event.type == SDL_QUIT) { - env.state.PopAll(); + switch (event.type) { + case SDL_KEYDOWN: + interface.HandlePress(event.key); + break; + case SDL_KEYUP: + interface.HandleRelease(event.key); + break; + case SDL_MOUSEBUTTONDOWN: + interface.HandlePress(event.button); + break; + case SDL_MOUSEBUTTONUP: + interface.HandleRelease(event.button); + break; + case SDL_MOUSEMOTION: + interface.Handle(event.motion); + break; + case SDL_MOUSEWHEEL: + interface.Handle(event.wheel); + break; + case SDL_QUIT: + env.state.Pop(); + break; + default: + break; } } @@ -32,11 +69,26 @@ void ClientState::Update(int dt) { if (client.TimedOut()) { env.state.Pop(); } + + interface.Update(dt); + world.Update(dt); + chunk_renderer.Rebase(interface.Player().ChunkCoords()); + chunk_renderer.Update(dt); + + glm::mat4 trans = interface.Player().Transform(interface.Player().ChunkCoords()); + glm::vec3 dir(trans * glm::vec4(0.0f, 0.0f, -1.0f, 0.0f)); + glm::vec3 up(trans * glm::vec4(0.0f, 1.0f, 0.0f, 0.0f)); + env.audio.Position(interface.Player().Position()); + env.audio.Velocity(interface.Player().Velocity()); + env.audio.Orientation(dir, up); } void ClientState::Render(Viewport &viewport) { - + viewport.WorldPosition(interface.Player().Transform(interface.Player().ChunkCoords())); + chunk_renderer.Render(viewport); + world.Render(viewport); + interface.Render(viewport); } } diff --git a/src/app/ClientState.hpp b/src/app/ClientState.hpp index f54e56f..8868c98 100644 --- a/src/app/ClientState.hpp +++ b/src/app/ClientState.hpp @@ -3,7 +3,9 @@ #include "State.hpp" #include "../net/Client.hpp" +#include "../ui/Interface.hpp" #include "../world/BlockTypeRegistry.hpp" +#include "../world/ChunkRenderer.hpp" #include "../world/World.hpp" @@ -19,9 +21,12 @@ public: Environment &, const World::Config &, const WorldSave &, + const Interface::Config &, const Client::Config & ); + void OnEnter() override; + void Handle(const SDL_Event &) override; void Update(int dt) override; void Render(Viewport &) override; @@ -30,6 +35,8 @@ private: Environment &env; BlockTypeRegistry block_types; World world; + ChunkRenderer chunk_renderer; + Interface interface; Client client; }; diff --git a/src/app/WorldState.cpp b/src/app/WorldState.cpp index 521f5b5..fabd332 100644 --- a/src/app/WorldState.cpp +++ b/src/app/WorldState.cpp @@ -79,7 +79,6 @@ void WorldState::Update(int dt) { env.audio.Position(interface.Player().Position()); env.audio.Velocity(interface.Player().Velocity()); env.audio.Orientation(dir, up); - } void WorldState::Render(Viewport &viewport) { diff --git a/src/app/runtime.cpp b/src/app/runtime.cpp index f979c65..2d12863 100644 --- a/src/app/runtime.cpp +++ b/src/app/runtime.cpp @@ -357,7 +357,7 @@ void Runtime::RunClient() { } Application app(env); - ClientState client_state(env, config.world, save, config.client); + ClientState client_state(env, config.world, save, config.interface, config.client); app.PushState(&client_state); Run(app); } diff --git a/src/net/Client.hpp b/src/net/Client.hpp index 63c3fdd..5b83061 100644 --- a/src/net/Client.hpp +++ b/src/net/Client.hpp @@ -29,6 +29,9 @@ public: bool TimedOut() { return conn.TimedOut(); } + void SendPing(); + void SendLogin(const std::string &); + private: void HandlePacket(const UDPpacket &); diff --git a/src/net/Packet.hpp b/src/net/Packet.hpp index 7b482e5..d547990 100644 --- a/src/net/Packet.hpp +++ b/src/net/Packet.hpp @@ -2,6 +2,7 @@ #define BLANK_NET_PACKET_HPP_ #include +#include namespace blank { @@ -11,7 +12,8 @@ struct Packet { static constexpr std::uint32_t TAG = 0xFB1AB1AF; enum Type { - PING, + PING = 0, + LOGIN = 1, }; struct Header { @@ -25,6 +27,7 @@ struct Packet { void Tag() noexcept; std::size_t Ping() noexcept; + std::size_t Login(const std::string &name) noexcept; }; diff --git a/src/net/Server.hpp b/src/net/Server.hpp index b6a72a9..6a1e996 100644 --- a/src/net/Server.hpp +++ b/src/net/Server.hpp @@ -33,6 +33,8 @@ private: void OnConnect(Connection &); void OnDisconnect(Connection &); + void HandleLogin(Connection &client, const UDPpacket &); + private: UDPsocket serv_sock; UDPpacket serv_pack; diff --git a/src/net/net.cpp b/src/net/net.cpp index 73ed73c..20b6f5c 100644 --- a/src/net/net.cpp +++ b/src/net/net.cpp @@ -5,6 +5,7 @@ #include "Server.hpp" #include "../app/init.hpp" +#include "../world/World.hpp" #include #include @@ -42,7 +43,7 @@ Client::Client(const Config &conf, World &world) client_pack.data = new Uint8[sizeof(Packet)]; client_pack.maxlen = sizeof(Packet); // establish connection - conn.SendPing(client_pack, client_sock); + SendPing(); } Client::~Client() { @@ -83,10 +84,20 @@ void Client::Update(int dt) { if (conn.TimedOut()) { cout << "connection timed out :(" << endl; } else if (conn.ShouldPing()) { - conn.SendPing(client_pack, client_sock); + SendPing(); } } +void Client::SendPing() { + conn.SendPing(client_pack, client_sock); +} + +void Client::SendLogin(const string &name) { + Packet &pack = *reinterpret_cast(client_pack.data); + client_pack.len = pack.Login(name); + conn.Send(client_pack, client_sock); +} + Connection::Connection(const IPaddress &addr) : addr(addr) @@ -160,6 +171,20 @@ size_t Packet::Ping() noexcept { return sizeof(Header); } +size_t Packet::Login(const string &name) noexcept { + constexpr size_t maxname = 32; + + Tag(); + header.type = LOGIN; + if (name.size() < maxname) { + memset(payload, '\0', maxname); + memcpy(payload, name.c_str(), name.size()); + } else { + memcpy(payload, name.c_str(), maxname); + } + return sizeof(Header) + maxname; +} + Server::Server(const Config &conf, World &world) : serv_sock(nullptr) @@ -206,6 +231,18 @@ void Server::HandlePacket(const UDPpacket &udp_pack) { Connection &client = GetClient(udp_pack.address); client.FlagRecv(); + + switch (pack.header.type) { + case Packet::PING: + // already done all that's supposed to do + break; + case Packet::LOGIN: + HandleLogin(client, udp_pack); + break; + default: + // just drop packets of unknown type + break; + } } Connection &Server::GetClient(const IPaddress &addr) { @@ -244,4 +281,25 @@ void Server::OnDisconnect(Connection &client) { cout << "connection timeout from " << client.Address() << endl; } + +void Server::HandleLogin(Connection &client, const UDPpacket &udp_pack) { + const Packet &pack = *reinterpret_cast(udp_pack.data); + size_t maxlen = min(udp_pack.len - int(sizeof(Packet::Header)), 32); + string name; + name.reserve(maxlen); + for (size_t i = 0; i < maxlen && pack.payload[i] != '\0'; ++i) { + name.push_back(pack.payload[i]); + } + cout << "got login request from player \"" << name << '"' << endl; + + Entity *player = world.AddPlayer(name); + if (player) { + // success! + cout << "\taccepted" << endl; + } else { + // aw no :( + cout << "\trejected" << endl; + } +} + } -- 2.39.2