Send IndexIdentifier information over the network.

- Improve scene manager
- Fix title screen
- Add ConnectScene scene
master
Nicole Collings 2019-07-22 01:22:40 -07:00
parent 2d4e093757
commit 1eeacfb102
39 changed files with 601 additions and 281 deletions

View File

@ -6,6 +6,9 @@
<file path="$PROJECT_DIR$/src" />
<file path="$PROJECT_DIR$/test" />
</sourceRoots>
<libraryRoots>
<file path="$PROJECT_DIR$/lib" />
</libraryRoots>
<excludeRoots>
<file path="$PROJECT_DIR$/Libraries" />
<file path="$PROJECT_DIR$/cmake-build-install" />

View File

@ -2,6 +2,5 @@
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
<mapping directory="$PROJECT_DIR$/lib/dynamic/enet" vcs="Git" />
</component>
</project>

View File

@ -59,8 +59,8 @@ set(ZEUS_SRC_FILES
util/net/Packet.h
server/conn/ServerPlayer.cpp
server/conn/ServerPlayer.h
game/scene/net/ServerConnection.cpp
game/scene/net/ServerConnection.h
game/scene/net/ClientNetworkInterpreter.cpp
game/scene/net/ClientNetworkInterpreter.h
def/gen/MapGen.cpp
def/gen/MapGen.h
util/net/NetHandler.cpp
@ -173,6 +173,6 @@ set(ZEUS_SRC_FILES
util/net/NetState.h
game/scene/ConnectScene.cpp
game/scene/ConnectScene.h
util/net/Address.h)
util/net/Address.h game/scene/net/ServerConnection.cpp game/scene/net/ServerConnection.h)
add_library (zeusCore ${ZEUS_SRC_FILES})

View File

@ -12,8 +12,6 @@ LocalDefs::LocalDefs(std::string tex_path) :
textureAtlas.loadDirectory(tex_path + "/game");
textureAtlas.loadDirectory(tex_path + "/gui");
textureAtlas.loadDirectory(tex_path + "/ent");
blockAtlas = LocalBlockAtlas();
}
LocalDefs::LocalDefs(const LocalDefs &copy) : LocalDefs(copy.tex_path) {

View File

@ -8,16 +8,28 @@ LocalBlockAtlas::LocalBlockAtlas() {
//Register Air Node
LocalBlockModel nullModel; nullModel.visible = false, nullModel.culls = false;
LocalBlockDef air("builtin:air", static_cast<int>(definitions.size()), nullModel, false, {{0, 0, 0}, {1, 1, 1}});
registerBlock(std::move(air));
definitions.push_back(air);
identifierIndexTable["builtin:air"] = AIR;
}
int LocalBlockAtlas::definitionsSize() {
return static_cast<int>(definitions.size());
}
void LocalBlockAtlas::setIdentifiers(std::vector<std::string> &identifiers) {
for (int i = 0; i < identifiers.size(); i++) {
identifierIndexTable.insert({identifiers[i], -1});
}
}
void LocalBlockAtlas::registerBlock(LocalBlockDef def) {
definitions.push_back(def);
identifierIndexTable.insert({def.getIdentifier(), def.getIndex()});
if (!identifierIndexTable.count(def.getIdentifier())) {
std::cout << Log::err << "Client/Server block identifier desync: " + def.getIdentifier() + "!" << Log::endl;
return;
}
identifierIndexTable[def.getIdentifier()] = def.getIndex();
}
LocalBlockDef& LocalBlockAtlas::fromIndex(int id) {
@ -36,4 +48,4 @@ LocalBlockDef &LocalBlockAtlas::fromIdentifier(std::string identifier) {
std::cout << Log::err << "Block Identifier \"" << identifier << "\" (undefined) requested! Returning air." << Log::endl;
return definitions.at(0);
}
}

View File

@ -15,6 +15,7 @@ class LocalBlockAtlas : public BlockAtlas {
public:
LocalBlockAtlas();
void setIdentifiers(std::vector<std::string>& identifiers);
void registerBlock(LocalBlockDef def);
int definitionsSize() override;
@ -22,6 +23,7 @@ public:
LocalBlockDef& fromIndex(int id) override;
LocalBlockDef& fromIdentifier(std::string identifier) override;
private:
const static int UNDEFINED = -1;
const static int AIR = 0;
std::vector<LocalBlockDef> definitions;

View File

@ -6,7 +6,7 @@
Client::Client(char* path, int width, int height) :
renderer(width, height),
state {renderer, LocalDefs("../res/tex"), 0, 0} {
state {renderer, {}, LocalDefs("../res/tex"), "this", 0, 0} {
// Start Local Server
// if (path != nullptr) {
@ -30,13 +30,18 @@ Client::Client(char* path, int width, int height) :
void Client::loop() {
Timer t("Client Loop");
if (!startedGame && timeElapsed > 1) {
// std::unique_ptr<Scene> scene = std::make_unique<ConnectScene>(state);
std::unique_ptr<Scene> scene = std::make_unique<GameScene>(state);
if (!startedGame && timeElapsed > 1.5) {
std::unique_ptr<Scene> scene = std::make_unique<ConnectScene>(state, Address{"127.0.0.1", 12345});
sceneManager.setScene(std::move(scene));
startedGame = true;
}
if (state.desiredState == "game") {
state.desiredState = "this";
std::unique_ptr<Scene> scene = std::make_unique<GameScene>(state);
sceneManager.setScene(std::move(scene));
}
double now = glfwGetTime();
state.deltaTime = now - timeElapsed;
timeElapsed = now;

View File

@ -13,6 +13,7 @@
#include "../util/Timer.h"
#include "scene/GameScene.h"
#include "scene/MenuScene.h"
#include "scene/ConnectScene.h"
class Client {
public:

View File

@ -6,13 +6,17 @@
#define ZEUS_CLIENTSTATE_H
#include "graph/Renderer.h"
#include "scene/net/ServerConnection.h"
#include "scene/net/ClientNetworkInterpreter.h"
#include "../def/LocalDefs.h"
#include "scene/net/ServerConnection.h"
struct ClientState {
Renderer& renderer;
ServerConnection connection;
LocalDefs defs;
// ServerConnection connection;
//TODO: Not this
std::string desiredState;
double fps = 0;
double deltaTime = 0;

View File

@ -55,13 +55,13 @@ void DebugGui::positionElements(glm::vec2 bufferSize) {
dataText.setPos(glm::vec3(10, 10, 0));
serverGenGraph .setPosition({bufferWidth - 254, bufferHeight - 70 - 160});
serverPacketGraph.setPosition({bufferWidth - 254, bufferHeight - 70 - 240});
meshUpdatesGraph .setPosition({bufferWidth - 254, bufferHeight - 70 - 80 });
chunkUpdatesGraph.setPosition({bufferWidth - 254, bufferHeight - 70 });
fpsGraph .setPosition({10, bufferHeight - 70 });
drawCallsGraph .setPosition({10, bufferHeight - 70 - 80 });
vRamGraph .setPosition({bufferWidth - 254, 10 });
serverGenGraph.setPos({bufferWidth - 254, bufferHeight - 70 - 160});
serverPacketGraph.setPos({bufferWidth - 254, bufferHeight - 70 - 240});
meshUpdatesGraph.setPos({bufferWidth - 254, bufferHeight - 70 - 80});
chunkUpdatesGraph.setPos({bufferWidth - 254, bufferHeight - 70});
fpsGraph.setPos({10, bufferHeight - 70});
drawCallsGraph.setPos({10, bufferHeight - 70 - 80});
vRamGraph.setPos({bufferWidth - 254, 10});
}
void DebugGui::update(Player& player, LocalWorld& world, LocalDefs& defs, double fps, int chunks, int drawCalls, int ssGen, int ssPack) {

View File

@ -4,59 +4,53 @@
#include "StatGraph.h"
StatGraph::StatGraph(std::string title, int graphLength, int graphScale, Texture *graphTex, Texture *textTex) {
construct(std::move(title), 244, 64, graphLength, graphScale, graphTex, textTex);
}
StatGraph::StatGraph(std::string title, int graphLength, int graphScale, Texture *graphTex, Texture *textTex) :
StatGraph(std::move(title), 244, 64, graphLength, graphScale, graphTex, textTex) {}
StatGraph::StatGraph(std::string title, int xSize, int ySize, int graphLength, int graphScale, Texture* graphTex, Texture* textTex) {
construct(std::move(title), xSize, ySize, graphLength, graphScale, graphTex, textTex);
}
StatGraph::StatGraph(std::string title, int xSize, int ySize, int graphLength, int graphScale, Texture* graphTex, Texture* textTex) :
title(std::move(title)),
background({0.1, 0.1, 0.1, 0.2}, {0.1, 0.1, 0.1, 0.2}, {0.1, 0.1, 0.1, 0.7}, {0.1, 0.1, 0.1, 0.7}),
graph(graphTex, graphLength, graphScale, true),
text(textTex) {
void StatGraph::construct(std::string title, int xSize, int ySize, int graphLength, int graphScale, Texture *graphTex, Texture *textTex) {
for (int i = 0; i < 10; i++) history[i] = 0;
background.setScale({xSize, ySize, 1});
graph.setScale({(xSize - GRAPH_PAD_X * 2) / graphLength, 28, 1});
text.setScale(2);
background = new TextureRect({0.1, 0.1, 0.1, 0.2}, {0.1, 0.1, 0.1, 0.2}, {0.1, 0.1, 0.1, 0.7}, {0.1, 0.1, 0.1, 0.7});
background->setScale({xSize, ySize, 1});
for (float &i : history) i = 0;
graph = new GraphEntity(graphTex, graphLength, graphScale, true);
graph->setScale({(xSize - GRAPH_PAD_X * 2) / graphLength, 28, 1});
this->title = std::move(title);
text = new TextEntity(textTex);
text->setScale(2);
setPosition({0, 0});
setPos({0, 0});
}
void StatGraph::setPosition(glm::vec2 pos) {
text->setPos({pos.x + TEXT_PAD_X, pos.y + TEXT_PAD_Y, 0});
graph->setPos({pos.x + GRAPH_PAD_X, pos.y + GRAPH_PAD_Y, 0});
background->setPos({pos.x, pos.y, 0});
void StatGraph::setPos(glm::vec2 pos) {
text.setPos({pos.x + TEXT_PAD_X, pos.y + TEXT_PAD_Y, 0});
graph.setPos({pos.x + GRAPH_PAD_X, pos.y + GRAPH_PAD_Y, 0});
background.setPos({pos.x, pos.y, 0});
}
void StatGraph::update(float value) {
graph->push_back(value);
graph.push_back(value);
history[ind] = value;
if (++ind >= 10) {
if (++ind >= 5) {
ind = 0;
float val = 0;
for (float i : history) val += i / 10;
for (float i : history) val += i / 5;
std::string stringVal = (value == static_cast<int>(value))
? std::to_string(static_cast<int>(value))
: Util::floatToString(value);
text->set(title + ": " + stringVal);
text.set(title + ": " + stringVal);
}
}
void StatGraph::draw(Renderer &renderer) {
if (isVisible()) {
background->draw(renderer);
graph->draw(renderer);
text->draw(renderer);
background.draw(renderer);
graph.draw(renderer);
text.draw(renderer);
}
}

View File

@ -16,21 +16,19 @@ public:
StatGraph(std::string title, int xSize, int ySize, int graphLength, int graphScale, Texture* graphTex, Texture* textTex);
StatGraph(std::string title, int graphLength, int graphScale, Texture* graphTex, Texture* textTex);
void setPosition(glm::vec2 pos);
void setPos(glm::vec2 pos);
void update(float value);
void draw(Renderer& renderer) override;
private:
void construct(std::string title, int xSize, int ySize, int graphLength, int graphScale, Texture* graphTex, Texture* textTex);
const static int GRAPH_PAD_X = 2, GRAPH_PAD_Y = 62, TEXT_PAD_X = 4, TEXT_PAD_Y = 8;
int ind = 0;
float history[10];
float history[5];
TextureRect* background;
GraphEntity* graph;
TextEntity* text;
TextureRect background;
GraphEntity graph;
TextEntity text;
std::string title;
};

View File

@ -156,3 +156,7 @@ int TextEntity::getWidthSubtract(int c) {
}
return 0;
}
std::string TextEntity::get() {
return text;
}

View File

@ -14,6 +14,7 @@ public:
explicit TextEntity(Texture* texture, bool background = false, int scale = 2);
void set(std::string text);
std::string get();
private:
int getWidthSubtract(int c);

View File

@ -327,4 +327,8 @@ void Renderer::enableTexture(Texture *texture) {
Renderer::~Renderer() {
worldGeometryShader.cleanup();
guiShader.cleanup();
}
}
void Renderer::setClearColor(unsigned char r, unsigned char g, unsigned char b) {
clearColor = {static_cast<float>(r)/255.f, static_cast<float>(g)/255.f, static_cast<float>(b)/255.f, 1};
}

View File

@ -33,6 +33,8 @@ public:
void beginGUIDrawCalls();
void swapBuffers();
void setClearColor(unsigned char r, unsigned char g, unsigned char b);
void setModelMatrix(const glm::mat4& modelMatrix);
void enableTexture(Texture* texture);
@ -59,7 +61,7 @@ private:
noise::module::Perlin swayNoise;
unsigned char* swayData = nullptr;
glm::vec4 clearColor {0.58f, 0.76f, 0.94f, 1.0f};
glm::vec4 clearColor {0, 0, 0, 1};
Texture* activeTexture;
Shader worldGeometryShader;

View File

@ -4,7 +4,101 @@
#include "ConnectScene.h"
ConnectScene::ConnectScene(ClientState &state, Address addr) : Scene(state) {
ServerConnection connection(std::move(addr), state.defs);
// connection.
ConnectScene::ConnectScene(ClientState &state, Address addr) : Scene(state),
connection(state.connection),
fontTexture(const_cast<char*>("../res/tex/gui/font.png")),
statusText(&fontTexture) {
state.renderer.setClearColor(10, 10, 10);
statusText.set("Connecting...");
statusText.setScale(2);
statusText.setPos(glm::vec3(32, 24, 0));
connection.attemptConnect(std::move(addr));
}
void ConnectScene::update() {
switch (connectState) {
default:
std::cout << Log::err << "Invalid connectState" << Log::endl;
exit(1);
case State::CONNECTING:
handleConnecting();
break;
case State::IDENTIFIER_LIST: {
ENetEvent e;
if (connection.pollEvents(&e) && e.type == ENET_EVENT_TYPE_RECEIVE) {
Packet p(e.packet);
statusText.set(statusText.get() + "Recieved block index-identifier table.\n");
std::vector<std::string> indexIdentifierTable {};
indexIdentifierTable.reserve(static_cast<unsigned long>(Serializer::decodeInt(&p.data[0])));
unsigned int ind = 4;
while (true) {
auto len = Serializer::decodeInt(&p.data[ind]);
indexIdentifierTable.emplace_back(&p.data[ind + 4], &p.data[ind + 4 + len]);
ind += 4 + len;
if (ind >= p.data.length()) break;
}
state.defs.blocks().setIdentifiers(indexIdentifierTable);
Packet r(PacketType::CONNECT_DATA_RECVD);
r.sendTo(connection.getPeer(), PacketChannel::CONNECT);
state.desiredState = "game";
}
}
}
}
void ConnectScene::handleConnecting() {
Packet resp(PacketType::IDENTIFIER_LIST);
switch (connection.getConnectionStatus()) {
default:
std::cout << Log::err << "Undefined connection error. Exiting." << Log::endl;
case ServerConnection::State::FAILED_CONNECT:
case ServerConnection::State::ENET_ERROR:
exit(1);
break;
case ServerConnection::State::ATTEMPTING_CONNECT:
connection.processConnecting();
dotsTime += state.deltaTime;
if (dotsTime > 1) {
dotsTime -= 1;
statusText.set(statusText.get() + ".");
}
break;
case ServerConnection::State::CONNECTED:
connectState = State::IDENTIFIER_LIST;
statusText.set(statusText.get() + " Connected!~\n");
resp.sendTo(connection.getPeer(), PacketChannel::CONNECT);
break;
}
}
void ConnectScene::draw() {
Renderer& renderer = state.renderer;
renderer.beginChunkDeferredCalls();
renderer.endDeferredCalls();
renderer.beginGUIDrawCalls();
statusText.draw(renderer);
renderer.swapBuffers();
}

View File

@ -7,9 +7,33 @@
#include <utility>
#include "../graph/scene/Scene.h"
#include "../entity/hud/TextEntity.h"
#include "net/ServerConnection.h"
class ConnectScene : public Scene {
public:
enum class State {
CONNECTING,
IDENTIFIER_LIST,
};
ConnectScene(ClientState& state, Address addr);
void update() override;
void handleConnecting();
void draw() override;
void cleanup() override {};
private:
State connectState = State::CONNECTING;
ServerConnection& connection;
Texture fontTexture;
TextEntity statusText;
double dotsTime = 0;
};
#endif //ZEUS_CONNECTSCENE_H

View File

@ -6,6 +6,7 @@
GameScene::GameScene(ClientState& state) : Scene(state),
defs(state.defs),
//TODO: Give `server` `state.connection` instead of a NetHandler.
server({"127.0.0.1", 12345}, defs),
world(defs, &playerPos, &server),
@ -14,6 +15,8 @@ GameScene::GameScene(ClientState& state) : Scene(state),
gameGui (state.renderer.getCamera().getBufferDimensions()),
debugGui(state.renderer.getCamera().getBufferDimensions(), &defs.textures().getAtlasTexture()) {
state.renderer.setClearColor(148, 194, 240);
defs.init(world);
world.init();

View File

@ -11,7 +11,7 @@
#include "../entity/hud/GameGui.h"
#include "world/LocalWorld.h"
#include "world/Player.h"
#include "net/ServerConnection.h"
#include "net/ClientNetworkInterpreter.h"
#include "../entity/world/PlayerEntity.h"
#include "../entity/world/WireframeEntity.h"
#include "../entity/world/BlockCrackEntity.h"
@ -30,7 +30,7 @@ public:
glm::vec3 playerPos;
ServerConnection server;
ClientNetworkInterpreter server;
Player player;
LocalWorld world;

View File

@ -4,45 +4,48 @@
#include "MenuScene.h"
MenuScene::MenuScene(ClientState& state) : Scene(state) {
fontTexture = new Texture((char*)"../res/tex/gui/font.png");
MenuScene::MenuScene(ClientState& state) : Scene(state),
fontTexture((char*)"../res/tex/gui/font.png"),
alphaText(&fontTexture),
titleText(&fontTexture),
mainMenuText(&fontTexture) {
auto alphaText = new TextEntity(fontTexture);
alphaText->set("Zeus Alpha 0.01");
alphaText->setScale(3);
alphaText->setPos(glm::vec3(8, 4, 0));
entities.push_back(alphaText);
state.renderer.setClearColor(22, 22, 22);
auto titleText = new TextEntity(fontTexture);
titleText->set("Zeus");
titleText->setScale(12);
titleText->setPos(glm::vec3(490, 120, 0));
entities.push_back(titleText);
alphaText.set("Alpha Software - Do Not Redistribute!\nCreated by Nicole Collings");
alphaText.setScale(2);
alphaText.setPos(glm::vec3(8, 4, 0));
auto mainMenuText = new TextEntity(fontTexture);
mainMenuText->set("MAIN MENU");
mainMenuText->setScale(4);
mainMenuText->setPos(glm::vec3(530, 230, 0));
entities.push_back(mainMenuText);
titleText.set("Zeus");
titleText.setScale(12);
titleText.setPos(glm::vec3(490, 120, 0));
mainMenuText.set("MAIN MENU");
mainMenuText.setScale(4);
mainMenuText.setPos(glm::vec3(530, 230, 0));
}
void MenuScene::update() {
//Nothing
if (state.renderer.resized) {
auto size = state.renderer.getWindow().getSize();
titleText.setPos({size.x / 2 - 180, size.y / 2 - 120, 0});
mainMenuText.setPos({size.x / 2 - 130, size.y / 2, 0});
state.renderer.resized = false;
}
}
void MenuScene::draw() {
state.renderer.beginChunkDeferredCalls();
state.renderer.endDeferredCalls();
state.renderer.beginGUIDrawCalls();
Renderer& renderer = state.renderer;
for (auto &element : entities) {
element->draw(state.renderer);
}
renderer.beginChunkDeferredCalls();
renderer.endDeferredCalls();
renderer.beginGUIDrawCalls();
state.renderer.swapBuffers();
}
alphaText.draw(renderer);
titleText.draw(renderer);
mainMenuText.draw(renderer);
void MenuScene::cleanup() {
fontTexture->clear();
delete fontTexture;
renderer.swapBuffers();
}

View File

@ -16,11 +16,14 @@ public:
void update() override;
void draw() override;
void cleanup() override;
void cleanup() override {};
private:
Texture* fontTexture;
std::vector<Entity*> entities;
Texture fontTexture;
TextEntity alphaText;
TextEntity titleText;
TextEntity mainMenuText;
};

View File

@ -0,0 +1,131 @@
//
// Created by aurailus on 11/01/19.
//
#include "ClientNetworkInterpreter.h"
ClientNetworkInterpreter::ClientNetworkInterpreter(Address address, LocalDefs& defs) :
address(std::move(address)),
entities(new DrawableGroup()),
playerFrontTex(defs.textures().getTextureRef("player_front")),
playerBackTex(defs.textures().getTextureRef("player_back")),
shadowTex(defs.textures().getTextureRef("player_shadow")) {}
void ClientNetworkInterpreter::init(std::vector<Drawable *> &entities, LocalWorld *world) {
entities.push_back(this->entities);
this->world = world;
handler = NetHandler(address, 3, 3000);
if (handler.getState() != NetState::CLIENT) {
exit(EXIT_FAILURE);
}
}
void ClientNetworkInterpreter::update(Player &player) {
recvPackets = 0;
ENetEvent event;
while (handler.update(&event)) {
recvPackets++;
switch (event.type) {
case ENET_EVENT_TYPE_CONNECT: {
std::cout << Log::info << "Connected to server "
<< event.peer->address.host << ":" << event.peer->address.port << "." << Log::endl;
break;
}
case ENET_EVENT_TYPE_RECEIVE: {
Packet p(event.packet);
switch (p.type) {
case PacketType::PLAYER: {
id = Serializer::decodeInt(&p.data[0]);
auto playerPos = Serializer::decodeFloatVec3(&p.data[4]);
player.setPos(playerPos);
break;
}
case PacketType::ENTITY_INFO: {
int peer_id = Serializer::decodeInt(&p.data[0]);
if (peer_id == id) break;
auto playerPos = Serializer::decodeFloatVec3(&p.data[4]);
auto playerAngle = Serializer::decodeFloat(&p.data[16]);
bool found = false;
for (auto ent : entities->getChildren()) {
auto playerEntity = (PlayerEntity*)ent;
if (playerEntity->peer_id == peer_id) {
playerEntity->setPos(playerPos);
playerEntity->setAngle(-playerAngle);
found = true;
break;
}
}
if (!found) {
entities->addDrawable(new PlayerEntity(playerPos, peer_id, playerFrontTex, playerBackTex, shadowTex));
}
break;
}
case PacketType::BLOCK_SET: {
auto pos = Serializer::decodeIntVec3(&p.data[0]);
auto block = Serializer::decodeInt(&p.data[12]);
world->setBlock(pos, block);
break;
}
case PacketType::CHUNK: {
chunkPackets.push_back(std::move(p));
break;
}
case PacketType::SERVER_INFO: {
serverSideChunkGens = Serializer::decodeInt(&p.data[0]);
break;
}
default:
break;
}
enet_packet_destroy(event.packet);
break;
}
case ENET_EVENT_TYPE_DISCONNECT: {
std::cout << Log::info << "Disconnected from server "
<< event.peer->address.host << ":" << event.peer->address.port << "." << Log::endl;
break;
}
default:
break;
}
}
//Send Player Position
Packet p(PacketType::PLAYER);
Serializer::encodeFloat(p.data, player.getPos().x);
Serializer::encodeFloat(p.data, player.getPos().y - Player::EYE_HEIGHT);
Serializer::encodeFloat(p.data, player.getPos().z);
Serializer::encodeFloat(p.data, player.getYaw());
p.sendTo(handler.getPeer(), PacketChannel::PLAYER);
}
void ClientNetworkInterpreter::cleanup() {
handler.disconnect();
connected = false;
}
ClientNetworkInterpreter::~ClientNetworkInterpreter() {
cleanup();
}
void ClientNetworkInterpreter::setBlock(glm::vec3 pos, int block) {
Packet p(PacketType::BLOCK_SET);
Serializer::encodeIntVec3(p.data, pos);
Serializer::encodeInt(p.data, block);
p.sendTo(handler.getPeer(), PacketChannel::BLOCK);
}

View File

@ -0,0 +1,50 @@
//
// Created by aurailus on 11/01/19.
//
#ifndef ZEUS_CLIENTNETWORKINTERPRETER_H
#define ZEUS_CLIENTNETWORKINTERPRETER_H
#include <string>
#include <iostream>
#include <glm/vec3.hpp>
#include "../../../util/Timer.h"
#include "../../../util/net/Packet.h"
#include "../../../util/net/NetHandler.h"
#include "../../entity/world/PlayerEntity.h"
#include "../../graph/drawable/DrawableGroup.h"
#include "../world/Player.h"
#include "../world/LocalWorld.h"
#include "../../../util/net/Address.h"
class ClientNetworkInterpreter {
public:
ClientNetworkInterpreter(Address address, LocalDefs& defs);
void init(std::vector<Drawable*> &entities, LocalWorld* world);
void update(Player &player);
void cleanup();
void setBlock(glm::vec3 pos, int block);
~ClientNetworkInterpreter();
std::vector<Packet> chunkPackets;
int serverSideChunkGens = 0;
int recvPackets = 0;
private:
std::shared_ptr<AtlasRef> playerFrontTex, playerBackTex, shadowTex;
bool connected = false;
int id = 0;
DrawableGroup* entities;
LocalWorld* world;
NetHandler handler;
Address address;
};
#endif //ZEUS_CLIENTNETWORKINTERPRETER_H

View File

@ -1,131 +1,99 @@
//
// Created by aurailus on 11/01/19.
// Created by aurailus on 21/07/19.
//
#include <thread>
#include "ServerConnection.h"
#include "../../../util/Log.h"
#include "../../../util/net/NetHandler.h"
ServerConnection::ServerConnection(Address address, LocalDefs& defs) :
address(std::move(address)),
entities(new DrawableGroup()),
playerFrontTex(defs.textures().getTextureRef("player_front")),
playerBackTex(defs.textures().getTextureRef("player_back")),
shadowTex(defs.textures().getTextureRef("player_shadow")) {}
void ServerConnection::init(std::vector<Drawable *> &entities, LocalWorld *world) {
entities.push_back(this->entities);
this->world = world;
handler = NetHandler(address, 3, 3000);
if (handler.getState() != NetState::CLIENT) {
exit(EXIT_FAILURE);
void ServerConnection::attemptConnect(Address addr) {
if (state != State::UNCONNECTED) {
disconnect();
}
if (enet_initialize() != 0) {
std::cout << Log::err << "Failed to Initialize ENet." << Log::endl;
state = State::ENET_ERROR;
return;
}
host = enet_host_create(nullptr, 1, NetHandler::PACKET_CHANNELS, 0, 0);
if (host == nullptr) {
std::cout << Log::err << "Failed to create ENet client." << Log::endl;
state = State::ENET_ERROR;
return;
}
ENetAddress eNetAddr;
enet_address_set_host(&eNetAddr, addr.host.c_str());
eNetAddr.port = addr.port;
peer = enet_host_connect(host, &eNetAddr, NetHandler::PACKET_CHANNELS, 0);
if (peer == nullptr) {
std::cout << Log::err << "Failed to initialize ENet peer." << Log::endl;
state = State::ENET_ERROR;
return;
}
connectionTime = std::chrono::high_resolution_clock::now();
state = State::ATTEMPTING_CONNECT;
}
void ServerConnection::update(Player &player) {
recvPackets = 0;
void ServerConnection::processConnecting() {
if (state == State::ATTEMPTING_CONNECT) {
ENetEvent event;
ENetEvent event;
while (handler.update(&event)) {
recvPackets++;
auto time = std::chrono::high_resolution_clock::now();
long elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(time - connectionTime).count();
switch (event.type) {
case ENET_EVENT_TYPE_CONNECT: {
std::cout << Log::info << "Connected to server "
if (elapsedMs < timeout) {
if (enet_host_service(host, &event, 0) > 0 && event.type == ENET_EVENT_TYPE_CONNECT) {
std::cout << Log::info << "Connected to "
<< event.peer->address.host << ":" << event.peer->address.port << "." << Log::endl;
break;
state = State::CONNECTED;
}
case ENET_EVENT_TYPE_RECEIVE: {
Packet p(event.packet);
switch (p.type) {
case PacketType::PLAYER_INFO: {
id = Serializer::decodeInt(&p.data[0]);
auto playerPos = Serializer::decodeFloatVec3(&p.data[4]);
player.setPos(playerPos);
break;
}
case PacketType::ENTITY_INFO: {
int peer_id = Serializer::decodeInt(&p.data[0]);
if (peer_id == id) break;
auto playerPos = Serializer::decodeFloatVec3(&p.data[4]);
auto playerAngle = Serializer::decodeFloat(&p.data[16]);
bool found = false;
for (auto ent : entities->getChildren()) {
auto playerEntity = (PlayerEntity*)ent;
if (playerEntity->peer_id == peer_id) {
playerEntity->setPos(playerPos);
playerEntity->setAngle(-playerAngle);
found = true;
break;
}
}
if (!found) {
entities->addDrawable(new PlayerEntity(playerPos, peer_id, playerFrontTex, playerBackTex, shadowTex));
}
break;
}
case PacketType::BLOCK_SET: {
auto pos = Serializer::decodeIntVec3(&p.data[0]);
auto block = Serializer::decodeInt(&p.data[12]);
world->setBlock(pos, block);
break;
}
case PacketType::CHUNK_INFO: {
chunkPackets.push_back(std::move(p));
break;
}
case PacketType::SERVER_INFO: {
serverSideChunkGens = Serializer::decodeInt(&p.data[0]);
break;
}
default:
break;
}
enet_packet_destroy(event.packet);
break;
}
else {
enet_peer_reset(peer);
if (attempt < attempts) {
std::cout << Log::info << "Failed to connect to server, retrying." << Log::endl;
connectionTime = std::chrono::high_resolution_clock::now();
attempt ++;
}
case ENET_EVENT_TYPE_DISCONNECT: {
std::cout << Log::info << "Disconnected from server "
<< event.peer->address.host << ":" << event.peer->address.port << "." << Log::endl;
break;
else {
std::cout << Log::err << "Failed to connect to server." << Log::endl;
state = State::FAILED_CONNECT;
}
default:
break;
}
}
//Send Player Position
Packet p(PacketType::PLAYER_INFO);
Serializer::encodeFloat(p.data, player.getPos().x);
Serializer::encodeFloat(p.data, player.getPos().y - Player::EYE_HEIGHT);
Serializer::encodeFloat(p.data, player.getPos().z);
Serializer::encodeFloat(p.data, player.getYaw());
p.sendTo(handler.getPeer(), PacketChannel::PLAYER_INFO);
}
void ServerConnection::cleanup() {
handler.disconnect();
connected = false;
ServerConnection::State ServerConnection::getConnectionStatus() {
return state;
}
void ServerConnection::disconnect() {
std::cout << Log::info << "Disconnecting from server." << Log::endl;
enet_peer_disconnect(peer, 0);
enet_host_flush(host);
//TODO: Make sure the client is *actually* disconnected.. get clarification from the docs
state = State::DISCONNECTED;
}
bool ServerConnection::pollEvents(ENetEvent *event) {
return enet_host_service(host, event, 0) > 0;
}
ENetPeer *ServerConnection::getPeer() {
return peer;
}
ServerConnection::~ServerConnection() {
cleanup();
disconnect();
delete host;
delete peer;
}
void ServerConnection::setBlock(glm::vec3 pos, int block) {
Packet p(PacketType::BLOCK_SET);
Serializer::encodeIntVec3(p.data, pos);
Serializer::encodeInt(p.data, block);
p.sendTo(handler.getPeer(), PacketChannel::BLOCK_UPDATES);
}

View File

@ -1,49 +1,49 @@
//
// Created by aurailus on 11/01/19.
// Created by aurailus on 21/07/19.
//
#ifndef ZEUS_SERVERCONNECTION_H
#define ZEUS_SERVERCONNECTION_H
#include <string>
#include <iostream>
#include <glm/vec3.hpp>
#include "../../../util/Timer.h"
#include "../../../util/net/Packet.h"
#include "../../../util/net/NetHandler.h"
#include "../../entity/world/PlayerEntity.h"
#include "../../graph/drawable/DrawableGroup.h"
#include "../world/Player.h"
#include "../world/LocalWorld.h"
#include <enet/enet.h>
#include <chrono>
#include "../../../util/net/Address.h"
class ServerConnection {
public:
ServerConnection(Address address, LocalDefs& defs);
enum class State {
UNCONNECTED,
ATTEMPTING_CONNECT,
CONNECTED,
FAILED_CONNECT,
DISCONNECTED,
ENET_ERROR
};
void init(std::vector<Drawable*> &entities, LocalWorld* world);
void update(Player &player);
void cleanup();
ServerConnection() = default;
void setBlock(glm::vec3 pos, int block);
void attemptConnect(Address addr);
State getConnectionStatus();
void disconnect();
void processConnecting();
bool pollEvents(ENetEvent* event);
ENetPeer* getPeer();
~ServerConnection();
std::vector<Packet> chunkPackets;
int serverSideChunkGens = 0;
int recvPackets = 0;
private:
std::shared_ptr<AtlasRef> playerFrontTex, playerBackTex, shadowTex;
bool connected = false;
int id = 0;
unsigned long timeout = 1000;
unsigned int attempts = 3;
DrawableGroup* entities;
LocalWorld* world;
ENetHost* host = nullptr;
ENetPeer* peer = nullptr;
NetHandler handler;
Address address;
State state = State::UNCONNECTED;
unsigned int attempt = 0;
std::chrono::time_point<std::chrono::high_resolution_clock> connectionTime;
};

View File

@ -6,9 +6,9 @@
#pragma clang diagnostic ignored "-Wmissing-noreturn"
#include "LocalWorld.h"
#include "../net/ServerConnection.h"
#include "../net/ClientNetworkInterpreter.h"
LocalWorld::LocalWorld(LocalDefs& defs, glm::vec3* playerPos, ServerConnection* server) :
LocalWorld::LocalWorld(LocalDefs& defs, glm::vec3* playerPos, ClientNetworkInterpreter* server) :
playerPos(playerPos),
dimension(&playerChunkPos),
meshGenStream(defs, dimension),

View File

@ -28,11 +28,11 @@
#include "WorldInterpolationStream.h"
#include "MeshGenStream.h"
class ServerConnection;
class ClientNetworkInterpreter;
class LocalWorld {
public:
LocalWorld(LocalDefs& defs, glm::vec3* playerPos, ServerConnection* server);
LocalWorld(LocalDefs& defs, glm::vec3* playerPos, ClientNetworkInterpreter* server);
void init();
void update(double delta);
@ -60,7 +60,7 @@ public:
//Called by the Client
void localSetBlock(glm::vec3 pos, int block);
//Called form ServerConnection
//Called form ClientNetworkInterpreter
void setBlock(glm::vec3 pos, int block);
bool solidAt(glm::vec3 pos);
@ -71,7 +71,7 @@ private:
glm::vec3* playerPos;
glm::vec3 playerChunkPos {};
ServerConnection* server;
ClientNetworkInterpreter* server;
WorldInterpolationStream* worldGenStream;
Dimension dimension;

View File

@ -44,13 +44,15 @@ void Server::update() {
case ENET_EVENT_TYPE_RECEIVE: {
Packet p(event.packet);
ServerClient *client = (ServerClient *) event.peer->data;
ServerClient* client = static_cast<ServerClient*>(event.peer->data);
if (client->hasPlayer()) {
if (client->hasPlayer())
handlePlayerPacket(*client, p);
}
else {
config.handlePacket(*client, p);
bool done = config.handlePacket(*client, p);
if (done) {
clientList.createPlayer(*client);
}
}
break;
@ -68,7 +70,7 @@ void Server::update() {
}
void Server::handlePlayerPacket(ServerClient &client, Packet& p) {
//Client *does* have a player, this is ensured in update().
//Client *does* have a player, this is ensured in processConnecting().
ServerPlayer& player = client.getPlayer();
switch (p.type) {
@ -77,7 +79,7 @@ void Server::handlePlayerPacket(ServerClient &client, Packet& p) {
break;
}
case PacketType::PLAYER_INFO: {
case PacketType::PLAYER: {
player.setPos(Serializer::decodeFloatVec3(&p.data[0]));
player.setAngle(Serializer::decodeFloat(&p.data[12]));
@ -90,7 +92,7 @@ void Server::handlePlayerPacket(ServerClient &client, Packet& p) {
for (auto& iter : clientList.clients) {
if (iter.getConnectID() != client.getConnectID()) {
r.sendTo(iter.getPeer(), PacketChannel::ENTITY_INFO);
r.sendTo(iter.getPeer(), PacketChannel::ENTITY);
}
}

View File

@ -16,8 +16,11 @@ void ServerConfig::init() {
}
}
void ServerConfig::handlePacket(ServerClient &client, Packet &r) {
if (r.type == PacketType::IDENTIFIER_LIST) {
bool ServerConfig::handlePacket(ServerClient &client, Packet &r) {
if (r.type == PacketType::CONNECT_DATA_RECVD) {
return true;
}
else if (r.type == PacketType::IDENTIFIER_LIST) {
Packet p(PacketType::IDENTIFIER_LIST);
@ -27,6 +30,7 @@ void ServerConfig::handlePacket(ServerClient &client, Packet &r) {
Serializer::encodeString(p.data, str);
}
p.sendTo(client.getPeer(), PacketChannel::CONNECT_DATA);
p.sendTo(client.getPeer(), PacketChannel::CONNECT);
}
return false;
}

View File

@ -15,7 +15,8 @@ public:
void init();
void handlePacket(ServerClient &client, Packet& p);
//Bool: Create player
bool handlePacket(ServerClient &client, Packet& p);
private:
ServerDefs& defs;
std::vector<std::string> identifierList {};

View File

@ -13,14 +13,8 @@ void ServerClients::handleConnect(ENetEvent e) {
clients.emplace_back(peer, addr);
ServerClient& client = clients.back();
client.initPlayer();
//TODO: Create this later
peer->data = &client;
Packet p(PacketType::PLAYER_INFO);
Serializer::encodeInt(p.data, client.getConnectID());
Serializer::encodeFloatVec3(p.data, client.getPlayer().getPos());
p.sendTo(peer, PacketChannel::PLAYER_INFO);
}
void ServerClients::handleDisconnect(ENetEvent e) {
@ -43,4 +37,13 @@ void ServerClients::handleDisconnect(ENetEvent e) {
}
if (!found) std::cout << Log::err << "Tried to disconnect nonexistent client!" << Log::endl;
}
}
void ServerClients::createPlayer(ServerClient &c) {
c.initPlayer();
Packet p(PacketType::PLAYER);
Serializer::encodeInt(p.data, c.getConnectID());
Serializer::encodeFloatVec3(p.data, c.getPlayer().getPos());
p.sendTo(c.getPeer(), PacketChannel::PLAYER);
}

View File

@ -17,6 +17,8 @@ public:
void handleConnect(ENetEvent e);
void handleDisconnect(ENetEvent e);
void createPlayer(ServerClient& c);
std::vector<ServerClient> clients;
};

View File

@ -101,7 +101,7 @@ void ServerWorld::update() {
for (auto& client : clientList.clients) {
if (client.hasPlayer()) {
r.sendTo(client.getPeer(), PacketChannel::SERVER_INFO);
r.sendTo(client.getPeer(), PacketChannel::SERVER);
if (client.getPlayer().changedChunks) changedChunks(client);
}
@ -112,12 +112,12 @@ void ServerWorld::sendChunk(glm::vec3 pos, ServerClient &peer) {
auto chunk = dimension.getChunk(pos);
auto serialized = chunk->serialize();
Packet r(PacketType::CHUNK_INFO);
Packet r(PacketType::CHUNK);
Serializer::encodeIntVec3(r.data, pos);
Serializer::encodeString(r.data, serialized);
r.sendTo(peer.getPeer(), PacketChannel::CHUNKS);
r.sendTo(peer.getPeer(), PacketChannel::CHUNK);
}
void ServerWorld::setBlock(glm::vec3 pos, int block) {
@ -149,7 +149,7 @@ void ServerWorld::setBlock(glm::vec3 pos, int block) {
auto bounds = client.getPlayer().getChunkBounds();
if (isInBounds(chunkPos, bounds)) {
b.sendTo(client.getPeer(), PacketChannel::BLOCK_UPDATES);
b.sendTo(client.getPeer(), PacketChannel::BLOCK);
}
}
}

View File

@ -76,7 +76,8 @@ void NetHandler::initClient(Address hostAddress, int attempts, int timeout) {
<< event.peer->address.host << ":" << event.peer->address.port << "." << Log::endl;
state = NetState::CLIENT;
break;
} else {
}
else {
enet_peer_reset(peer);
if (attempt < attempts) {
std::cout << Log::info << "Failed to connect to peer, retrying." << Log::endl;

View File

@ -16,10 +16,11 @@
class NetHandler {
public:
NetHandler() = default;
NetHandler(unsigned short port, short max_clients);
NetHandler(Address hostAddress);
explicit NetHandler(Address hostAddress);
NetHandler(Address hostAddress, int connection_attempts, int connection_timeout);
NetHandler(unsigned short port, short max_clients);
void disconnect();
NetState getState();
@ -27,6 +28,8 @@ public:
bool update(ENetEvent* event);
~NetHandler();
const static int PACKET_CHANNELS = 12;
private:
void initServer(unsigned short port, short max_clients);
void initClient(Address hostAddress, int connection_attempts, int connection_timeout);
@ -38,8 +41,6 @@ private:
ENetHost* host = nullptr;
ENetAddress address {};
const static int PACKET_CHANNELS = 12;
};
#endif //ZEUS_NETHANDLER_H

View File

@ -7,14 +7,13 @@
enum class PacketChannel {
UNDEFINED = -1,
KEEP_ALIVE,
AUTHENTICATE,
CONNECT_DATA,
PLAYER_INFO,
ENTITY_INFO,
CHUNKS,
SERVER_INFO,
BLOCK_UPDATES,
AUTH,
CONNECT,
SERVER,
PLAYER,
ENTITY,
CHUNK,
BLOCK,
};

View File

@ -5,15 +5,19 @@
#ifndef ZEUS_PACKETTYPE_H
#define ZEUS_PACKETTYPE_H
enum class PacketType {
UNDEFINED = 0,
HANDSHAKE,
AUTHENTICATE,
CONNECT,
AUTH,
//Information Request Types
IDENTIFIER_LIST,
PLAYER_INFO,
CONNECT_DATA_RECVD,
//Ingame Data Types
PLAYER,
CHUNK,
ENTITY_INFO,
CHUNK_INFO,
SERVER_INFO,
BLOCK_SET,
};

View File

@ -49,7 +49,7 @@ Dimension::~Dimension() {
}
void Dimension::update() {
//TODO: Figure out why there are NULL CHUNKS in the map
//TODO: Figure out why there are NULL CHUNK in the map
for (auto it = blockChunks.begin(); it != blockChunks.end();) {
auto chunk = it->second;
auto pos = it->first;