Asset & Mod management base; PlayerUpdate->MsgTypes; add basic crypto

Fix rendering on compliant GL ES 2.0 implementations.
master
Dorian Wouters 2016-08-28 10:51:39 +02:00
parent dd04f4a968
commit 42ea79d259
No known key found for this signature in database
GPG Key ID: 6E9DA8063322434B
56 changed files with 1081 additions and 398 deletions

5
.gitignore vendored
View File

@ -1,9 +1,12 @@
.kdev4
assets-orig
build
build-*
*.fossil
*.project
*.kdev4
*.user
TODO.txt
diggler.cfg
.kdev_include_paths
.kdev_include_paths
_*

3
.gitmodules vendored
View File

@ -10,3 +10,6 @@
[submodule "ext/StackTracePlus"]
path = ext/StackTracePlus
url = https://github.com/ignacio/StackTracePlus.git
[submodule "ext/Optional"]
path = ext/Optional
url = https://github.com/akrzemi1/Optional.git

View File

@ -2,6 +2,22 @@ cmake_minimum_required(VERSION 2.8)
project(Diggler C CXX)
set(CMAKE_LEGACY_CYGWIN_WIN32 0)
if("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}")
# Forbid in-tree builds. With CMake, doing an in-tree build breaks out-of-tree ones
# when generating from .in files into the source directory, overriding the path of out-of-tree
# generated ones.
# TL;DR: in-tree build = BAD IDEA.
file(REMOVE_RECURSE CMakeFiles CMakeCache.txt)
message(FATAL_ERROR
"You are doing an in-tree build (i.e. the source and binary directories are the same).\
In-tree builds aren't supported and will *never* be.\
Make a \"build\" directory and run cmake here.
\
Don't forget to remove CMakeFiles and CMakeCache.txt.")
endif()
### Find path to build dir, relative if possible, to symlink resources directories
file(RELATIVE_PATH REL_BUILD_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${PROJECT_BINARY_DIR})
string(FIND "${REL_BUILD_PATH}" ".." RBP_2DOTPOS)
@ -43,13 +59,13 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
find_package(CXX14)
if (NOT CXX14_FOUND)
message(FATAL_ERROR "C++14 feature support unavailable.
Please use the latest version of your compiler.
Here are the minimum requirements:
- GCC version 5 (on Debian Jessie, enable Stretch/testing repos and get GCC from there)
- clang version 3.4
- MSVC: wait until Microsoft goes bankrupt, and use another compiler in the meantime
message(FATAL_ERROR "C++14 feature support unavailable.\
Please use the latest version of your compiler.\
\
Here are the minimum requirements:\
- GCC version 5 (on Debian Jessie, enable Stretch/testing repos and get GCC from there)\
- clang version 3.4\
- MSVC: wait until Microsoft goes bankrupt, and use another compiler in the meantime\
- ICC: ICC 17.0 Beta doesn't yet support all required C++14 features")
endif()
set(CMAKE_CXX_FLAGS "${CXX14_FLAGS} ${CMAKE_CXX_FLAGS}")
@ -71,6 +87,8 @@ endif()
pkg_search_module(EPOXY REQUIRED epoxy)
pkg_search_module(GLFW REQUIRED glfw3)
pkg_search_module(SQLITE3 REQUIRED sqlite3)
pkg_search_module(LIBSODIUM REQUIRED libsodium)
include_directories(
${ETC_INCLUDE_DIRS}
${LUA_INCLUDE_DIR}
@ -78,6 +96,8 @@ include_directories(
${ENET_INCLUDE_DIRS}
${EPOXY_INCLUDE_DIRS}
${GLFW_INCLUDE_DIRS}
${LIBSODIUM_INCLUDE_DIRS}
${SQLITE3_INCLUDE_DIRS}
${OPENAL_INCLUDE_DIR}
${MSGPACK_INCLUDE_DIR}
)
@ -94,6 +114,8 @@ target_link_libraries(diggler
${ENET_LIBRARIES}
${EPOXY_LIBRARIES}
${GLFW_LIBRARIES}
${LIBSODIUM_LIBRARIES}
${SQLITE3_LIBRARIES}
${OPENAL_LIBRARY}
pthread)

View File

@ -26,3 +26,5 @@ You should already have OpenGL available thanks to Mesa or proprietary drivers.
Arch: `pacman -S glm openal libepoxy glfw luajit`
Debian (Jessie **w/ testing**, or up) & derivatives: `apt-get install libglm-dev libopenal-dev libepoxy-dev libglfw3-dev libx{i,randr}-dev libluajit-5.1-dev`
Fedora (tested on F24): `dnf install glm-devel openal-soft-devel libepoxy-devel glfw-devel luajit-devel`

View File

@ -12,11 +12,11 @@ include(CheckCXXSourceCompiles)
include(FindPackageHandleStandardArgs)
set(CXX14_FLAG_CANDIDATES
#Gnu and Intel Linux
"-std=c++14"
#Microsoft Visual Studio, and everything that automatically accepts C++14
# GCC 6+ and everything that automatically accepts C++14
" "
#Intel windows
# GCC < 6 and Intel Linux
"-std=c++14"
# Intel Windows
"/Qstd=c++14"
)
@ -24,6 +24,9 @@ set(CXX14_TEST_SOURCE
"
[[deprecated]] void unused() {}
template<typename T>
constexpr T pi = T(3.1415926535897932385);
constexpr int numberwang(int n) {
if (n < 0) {
return 0b1'1001'0101;
@ -31,7 +34,7 @@ constexpr int numberwang(int n) {
return n - 1;
}
auto lambda = [](auto a, auto b) { return a * b; };
auto lambda = [v = 0](auto a, auto b) { return v + a * b; };
auto square(int n) {
return lambda(n, n) * numberwang(2);
@ -39,6 +42,7 @@ auto square(int n) {
int main() {
int s = square(3);
double pie = pi<double>;
return 0;
}
")
@ -47,7 +51,7 @@ foreach(FLAG ${CXX14_FLAG_CANDIDATES})
set(SAFE_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
set(CMAKE_REQUIRED_FLAGS "${FLAG}")
unset(CXX14_FLAG_DETECTED CACHE)
message(STATUS "Try C++14 flag = [${FLAG}]")
message(STATUS "Trying C++14 flag '${FLAG}'")
check_cxx_source_compiles("${CXX14_TEST_SOURCE}" CXX14_FLAG_DETECTED)
set(CMAKE_REQUIRED_FLAGS "${SAFE_CMAKE_REQUIRED_FLAGS}")
if(CXX14_FLAG_DETECTED)

1
ext/Optional Submodule

@ -0,0 +1 @@
Subproject commit 3922965396fc455c6b1770374b9b4111799588a9

View File

@ -5,7 +5,7 @@ local grassBlock = {
variabilty = {'static'},
textures = {
grass = {
path = 'tex/grass.png',
path = 'self:/tex/grass.png',
['repeat'] = {
xdiv = 8,
ydiv = 8

View File

@ -16,6 +16,8 @@ set(SRCS
${CSD}/Chunk.cpp
${CSD}/Clouds.cpp
${CSD}/Config.cpp
${CSD}/content/AssetManager.cpp
${CSD}/content/ModManager.cpp
${CSD}/content/Registry.cpp
${CSD}/EscMenu.cpp
${CSD}/Frustum.cpp
@ -34,6 +36,8 @@ set(SRCS
${CSD}/network/msgtypes/BlockUpdate.cpp
${CSD}/network/msgtypes/Chat.cpp
${CSD}/network/msgtypes/ChunkTransfer.cpp
${CSD}/network/msgtypes/ConnectionParam.cpp
${CSD}/network/msgtypes/PlayerUpdate.cpp
${CSD}/network/msgtypes/ServerInfo.cpp
${CSD}/network/ClientMessageHandler.cpp
${CSD}/network/NetHelper.cpp

View File

@ -92,7 +92,7 @@ Chunk::Chunk(Game *G, WorldRef W, int X, int Y, int Z) :
calcMemUsage();
if (GlobalProperties::IsClient) {
G->R->WR->registerChunk(this);
G->R->renderers.world->registerChunk(this);
}
}
@ -155,7 +155,7 @@ Chunk::~Chunk() {
std::free(imcData);
#endif
if (GlobalProperties::IsClient) {
G->R->WR->unregisterChunk(this);
G->R->renderers.world->unregisterChunk(this);
}
// getDebugStream() << W->id << '.' << wcx << ',' << wcy << ',' << wcz << " destruct" << std::endl;
}
@ -442,7 +442,7 @@ void Chunk::updateClient() {
}
}
G->R->WR->updateChunk(this, vertex, v, idxOpaque, io, idxTransp, it);
G->R->renderers.world->updateChunk(this, vertex, v, idxOpaque, io, idxTransp, it);
dirty = false;
mut.unlock();
}

View File

@ -1,6 +1,8 @@
#include "Game.hpp"
#include "Audio.hpp"
#include "content/AssetManager.hpp"
#include "content/ModManager.hpp"
#include "content/Registry.hpp"
#include "GlobalProperties.hpp"
#include "KeyBinds.hpp"
@ -20,42 +22,67 @@ Game::Game() :
void Game::init() {
CR = new Content::Registry;
AM = std::make_unique<Content::AssetManager>(this);
MM = std::make_unique<Content::ModManager>(this);
LS = new Scripting::Lua::State(this);
if (GlobalProperties::IsClient) {
PM = new ProgramManager(*this);
LP = new LocalPlayer(this);
RP = new RenderProperties; { // TODO move somewhere else?
RP->bloom = true;
RP->wavingLiquids = !true;
RP->fogStart = 16;
RP->fogEnd = 24;
}
R = new Render::gl::GLRenderer(this);
A = new Audio(*this);
KB = new KeyBinds;
PlayerPosUpdateFreq = 4;
initClient();
}
if (GlobalProperties::IsServer) {
initServer();
}
}
Game::~Game() {
delete CR;
void Game::initClient() {
PM = new ProgramManager(*this);
LP = new LocalPlayer(this);
RP = new RenderProperties; { // TODO move somewhere else?
RP->bloom = true;
RP->wavingLiquids = !true;
RP->fogStart = 16;
RP->fogEnd = 24;
}
R = new Render::gl::GLRenderer(this);
A = new Audio(*this);
KB = new KeyBinds;
PlayerPosUpdateFreq = 4;
}
void Game::initServer() {
}
void Game::finalize() {
if (GlobalProperties::IsClient) {
delete KB;
delete A;
delete R;
delete RP;
delete LP;
delete PM;
finalizeClient();
}
if (GlobalProperties::IsServer) {
finalizeServer();
}
delete LS; LS = nullptr;
MM.reset();
AM.reset();
delete CR; CR = nullptr;
}
void Game::finalizeClient() {
delete KB; KB = nullptr;
delete A; A = nullptr;
delete R; R = nullptr;
delete RP; RP = nullptr;
delete LP; LP = nullptr;
delete PM; PM = nullptr;
}
void Game::finalizeServer() {
}
Game::~Game() {
finalize();
}
void Game::updateTime(double time) {
Time = time;
TimeMs = (int64)(time * 1000);
TimeMs = static_cast<int64>(time * 1000);
}
}

View File

@ -1,6 +1,8 @@
#ifndef GAME_HPP
#define GAME_HPP
#ifndef DIGGLER_GAME_HPP
#define DIGGLER_GAME_HPP
#include <memory>
#include "ui/FontManager.hpp"
#include "Universe.hpp"
#include "PlayerList.hpp"
@ -12,6 +14,8 @@ using std::shared_ptr;
namespace Diggler {
namespace Content {
class AssetManager;
class ModManager;
class Registry;
}
@ -35,7 +39,11 @@ class GameWindow;
class KeyBinds;
class Server;
class Game {
class Game final {
private:
template<typename T>
using ptr = std::unique_ptr<T>;
public:
// Shared
double Time; uint64 TimeMs;
@ -43,6 +51,8 @@ public:
Universe *U;
PlayerList players;
Content::Registry *CR;
ptr<Content::AssetManager> AM;
ptr<Content::ModManager> MM;
Scripting::Lua::State *LS;
// Server
@ -61,16 +71,22 @@ public:
float fogStart, fogEnd;
} *RP;
Audio *A;
Net::Peer NS;
Net::Peer *NS;
KeyBinds *KB;
int PlayerPosUpdateFreq;
Game();
void init();
void initClient();
void initServer();
void finalize();
void finalizeClient();
void finalizeServer();
void updateTime(double time);
~Game();
};
}
#endif
#endif /* DIGGLER_GAME_HPP */

View File

@ -26,6 +26,7 @@
#include "network/NetHelper.hpp"
#include "Particles.hpp"
#include "network/msgtypes/PlayerUpdate.hpp"
#include "network/msgtypes/BlockUpdate.hpp"
#include "content/Registry.hpp"
@ -95,6 +96,10 @@ GameState::GameState(GameWindow *GW, const std::string &servHost, int servPort)
m_highlightBox.att_coord = m_highlightBox.program->att("coord");
m_highlightBox.uni_unicolor = m_highlightBox.program->uni("unicolor");
m_highlightBox.uni_mvp = m_highlightBox.program->uni("mvp");
{ Render::gl::VAO::Config cfg = m_highlightBox.vao.configure();
cfg.vertexAttrib(m_highlightBox.vbo, m_highlightBox.att_coord, 3, GL_FLOAT, 0);
cfg.commit();
}
m_3dFbo = new Render::gl::FBO(w, h, Texture::PixelFormat::RGB, true);
m_3dRenderVBO = new Render::gl::VBO();
@ -388,7 +393,7 @@ void GameState::updateViewport() {
}
void GameState::sendMsg(Net::OutMessage &msg, Net::Tfer mode, Net::Channels chan) {
G->H.send(G->NS, msg, mode, chan);
G->H.send(*G->NS, msg, mode, chan);
}
void GameState::run() {
@ -402,13 +407,15 @@ bool GameState::connectLoop() {
std::string &serverHost = m_serverHost;
int serverPort = m_serverPort;
bool finished = false, success = false; Game *G = this->G;
m_networkThread = std::thread([G, &success, &finished, &serverHost, serverPort]() {
std::string failureStr;
m_networkThread = std::thread([G, &success, &finished, &serverHost, serverPort, &failureStr]() {
try {
G->H.create();
G->NS = G->H.connect(serverHost, serverPort, 5000);
G->NS = &G->H.connect(serverHost, serverPort, 5000);
success = true;
} catch (const Net::Exception &e) {
success = false;
failureStr = e.what();
}
finished = true;
});
@ -447,9 +454,7 @@ bool GameState::connectLoop() {
if (GW->shouldClose())
return true;
if (!success) {
std::ostringstream oss;
oss << serverHost << ':' << serverPort << " did not respond";
GW->showMessage("Could not connect to server", oss.str());
GW->showMessage("Could not connect to server", failureStr);
return true;
}
@ -469,7 +474,7 @@ bool GameState::connectLoop() {
switch (m_msg.getType()) {
case Net::MessageType::PlayerJoin: {
G->U = new Universe(G, true);
LP.id = m_msg.readU32();
LP.sessId = m_msg.readU32();
LP.W = G->U->createWorld(m_msg.readI16());
} break;
case Net::MessageType::PlayerQuit: {
@ -488,7 +493,7 @@ bool GameState::connectLoop() {
G->LS->setGameLuaRuntimePath(gameLuaRuntimePath);
G->LS->dofile(gameLuaRuntimePath + "/Diggler.lua");
getDebugStream() << "Joined as " << LP.name << '/' << LP.id << std::endl;
getDebugStream() << "Joined as " << LP.name << '/' << LP.sessId << std::endl;
return false;
}
@ -520,11 +525,14 @@ void GameState::gameLoop() {
if (G->LP->isAlive) {
if (T > nextNetUpdate) {
Net::OutMessage msg(Net::MessageType::PlayerUpdate, Net::PlayerUpdateType::Move);
msg.writeVec3(LP->position);
msg.writeVec3(LP->velocity);
msg.writeVec3(LP->accel);
msg.writeFloat(LP->angle);
Net::MsgTypes::PlayerUpdateMove pum;
pum.position = LP->position;
if (LP->velocity != glm::vec3()) {
pum.velocity = LP->velocity;
pum.accel = LP->accel;
}
pum.angle = LP->angle;
Net::OutMessage msg; pum.writeToMsg(msg);
sendMsg(msg, Net::Tfer::Unrel, Net::Channels::Movement);
nextNetUpdate = T+1.0/G->PlayerPosUpdateFreq;
}
@ -560,7 +568,7 @@ void GameState::gameLoop() {
rp.world = WR.get();
rp.transform = m_transform;
rp.frustum = G->LP->camera.frustum;
G->R->WR->render(rp);
G->R->renderers.world->render(rp);
for (Player &p : G->players) {
p.update(deltaT);
if (G->LP->camera.frustum.sphereInFrustum(p.position, 2))
@ -591,16 +599,14 @@ void GameState::gameLoop() {
// TODO: replace harcoded 32 viewdistance
if (G->LP->raytracePointed(32, &m_pointedBlock, &m_pointedFacing)) {
m_highlightBox.program->bind();
glEnableVertexAttribArray(m_highlightBox.att_coord);
m_highlightBox.vbo.bind();
glVertexAttribPointer(m_highlightBox.att_coord, 3, GL_FLOAT, GL_FALSE, 0, 0);
m_highlightBox.vao.bind();
glUniform4f(m_highlightBox.uni_unicolor, 1.f, 1.f, 1.f, .1f);
glUniformMatrix4fv(m_highlightBox.uni_mvp, 1, GL_FALSE, glm::value_ptr(
glm::scale(glm::translate(m_transform, glm::vec3(m_pointedBlock)+glm::vec3(.5f)), glm::vec3(0.5f*1.03f))));
glDrawArrays(GL_TRIANGLES, 0, 6*2*3);
glDisableVertexAttribArray(m_highlightBox.att_coord);
m_highlightBox.vao.unbind();
}
glDisable(GL_CULL_FACE);
@ -622,7 +628,7 @@ void GameState::gameLoop() {
glEnableVertexAttribArray(bloom.extractor.att_texcoord);
m_3dRenderVBO->bind();
glUniformMatrix4fv(bloom.extractor.uni_mvp, 1, GL_FALSE, glm::value_ptr(*G->UIM->PM1));
glVertexAttribPointer(bloom.extractor.att_coord, 2, GL_INT, GL_FALSE, sizeof(Coord2DTex), 0);
glVertexAttribPointer(bloom.extractor.att_coord, 2, GL_SHORT, GL_FALSE, sizeof(Coord2DTex), 0);
glVertexAttribPointer(bloom.extractor.att_texcoord, 2, GL_BYTE, GL_FALSE, sizeof(Coord2DTex), (GLvoid*)offsetof(Coord2DTex, u));
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(bloom.extractor.att_texcoord);
@ -639,7 +645,7 @@ void GameState::gameLoop() {
m_3dRenderVBO->bind();
glUniformMatrix4fv(bloom.renderer.uni_mvp, 1, GL_FALSE, glm::value_ptr(*G->UIM->PM1));
glUniform2f(bloom.renderer.uni_pixshift, 1.f/(GW->getW()/bloom.scale), 1.f/(GW->getH()/bloom.scale));
glVertexAttribPointer(bloom.renderer.att_coord, 2, GL_INT, GL_FALSE, sizeof(Coord2DTex), 0);
glVertexAttribPointer(bloom.renderer.att_coord, 2, GL_SHORT, GL_FALSE, sizeof(Coord2DTex), 0);
glVertexAttribPointer(bloom.renderer.att_texcoord, 2, GL_BYTE, GL_FALSE, sizeof(Coord2DTex), (GLvoid*)offsetof(Coord2DTex, u));
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(bloom.renderer.att_texcoord);
@ -656,7 +662,7 @@ void GameState::gameLoop() {
glEnableVertexAttribArray(bloom.renderer.att_texcoord);
m_3dRenderVBO->bind();
glUniformMatrix4fv(bloom.renderer.uni_mvp, 1, GL_FALSE, glm::value_ptr(*G->UIM->PM1));
glVertexAttribPointer(bloom.renderer.att_coord, 2, GL_INT, GL_FALSE, sizeof(Coord2DTex), 0);
glVertexAttribPointer(bloom.renderer.att_coord, 2, GL_SHORT, GL_FALSE, sizeof(Coord2DTex), 0);
glVertexAttribPointer(bloom.renderer.att_texcoord, 2, GL_BYTE, GL_FALSE, sizeof(Coord2DTex), (GLvoid*)offsetof(Coord2DTex, u));
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(bloom.renderer.att_texcoord);
@ -675,8 +681,9 @@ void GameState::gameLoop() {
}
if (!G->LP->deathSent) {
G->LP->deathSent = true;
Net::OutMessage out(Net::MessageType::PlayerUpdate, Net::PlayerUpdateType::Die);
out.writeU8((uint8)G->LP->deathReason);
Net::MsgTypes::PlayerUpdateDie pud;
pud.reason = G->LP->deathReason;
Net::OutMessage out; pud.writeToMsg(out);
sendMsg(out, Net::Tfer::Rel, Net::Channels::Life);
}
renderDeathScreen();

View File

@ -13,6 +13,7 @@
#include "GameWindow.hpp"
#include "render/gl/FBO.hpp"
#include "render/gl/VBO.hpp"
#include "render/gl/VAO.hpp"
#include "content/Content.hpp"
#include "network/Network.hpp"
#include "network/ClientMessageHandler.hpp"
@ -69,7 +70,7 @@ private:
} bloom;
Render::gl::VBO *m_3dRenderVBO;
struct Coord2DTex { int x, y; uint8 u, v; };
struct Coord2DTex { int16 x, y; uint8 u, v; };
Clouds *m_clouds;
Skybox *m_sky;
@ -80,6 +81,7 @@ private:
struct {
Render::gl::VBO vbo;
Render::gl::VAO vao;
const Program *program;
GLuint att_coord, uni_unicolor, uni_mvp;
} m_highlightBox;

View File

@ -116,7 +116,7 @@ GameWindow::GameWindow(Game *G) : G(G) {
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
//glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
glfwWindowHint(GLFW_SAMPLES, 0); // Gimme aliasing everywhere
//glfwWindowHint(GLFW_STENCIL_BITS, 8);
@ -190,6 +190,8 @@ GameWindow::GameWindow(Game *G) : G(G) {
}
GameWindow::~GameWindow() {
m_currentState.reset();
m_nextState.reset();
delete UIM;
glfwDestroyWindow(m_window);
@ -243,13 +245,13 @@ void GameWindow::cbResize(int w, int h) {
m_currentState->onResize(w, h);
}
void GameWindow::setNextState(const shared_ptr<State> next) {
m_nextState = next;
void GameWindow::setNextState(std::unique_ptr<State> &&next) {
m_nextState = std::move(next);
}
void GameWindow::run() {
while (m_nextState != nullptr && !glfwWindowShouldClose(m_window)) {
m_currentState = m_nextState;
m_currentState = std::move(m_nextState);
m_nextState = nullptr;
UIM->clear();
m_currentState->run();
@ -257,7 +259,7 @@ void GameWindow::run() {
}
void GameWindow::showMessage(const std::string &msg, const std::string &submsg) {
setNextState(std::make_shared<MessageState>(this, msg, submsg));
setNextState(std::move(std::make_unique<MessageState>(this, msg, submsg)));
}
}

View File

@ -8,8 +8,6 @@
#include "Platform.hpp"
#include "ui/Manager.hpp"
using std::shared_ptr;
namespace Diggler {
class Game;
@ -22,7 +20,7 @@ private:
GLFWwindow *m_window;
int m_w, m_h;
shared_ptr<State> m_currentState, m_nextState;
std::unique_ptr<State> m_currentState, m_nextState;
public:
UI::Manager *UIM;
@ -52,7 +50,7 @@ public:
void updateViewport();
void setNextState(const shared_ptr<State> next);
void setNextState(std::unique_ptr<State> &&next);
void run();
void showMessage(const std::string &msg, const std::string &submsg = "");

View File

@ -12,6 +12,7 @@
#include "Audio.hpp"
#include "Game.hpp"
#include "network/NetHelper.hpp"
#include "render/gl/VAO.hpp"
namespace Diggler {
@ -174,14 +175,11 @@ void LocalPlayer::update(float delta) {
}
void LocalPlayer::render(const glm::mat4 &transform) const {
const Program *P = G->PM->getProgram(PM_3D | PM_COLORED);
P->bind();
glEnableVertexAttribArray(P->att("coord"));
glEnableVertexAttribArray(P->att("color"));
glUniformMatrix4fv(P->uni("mvp"), 1, GL_FALSE, glm::value_ptr(transform));
static Render::gl::VBO vbo;
const glm::ivec3 &min = aabbmin, &max = aabbmax;
struct Coord { int x, y, z; uint8 r, g, b; } pts[] = {
static Render::gl::VAO vao;
static bool vaoConfigured = false;
const glm::f32vec3 min = aabbmin, max = aabbmax;
struct Coord { float x, y, z; uint8 r, g, b; } pts[] = {
{ min.x, min.y, min.z, 0, 1, 0 },
{ max.x, min.y, min.z, 0, 1, 0 },
{ min.x, min.y, min.z, 0, 1, 0 },
@ -209,12 +207,19 @@ void LocalPlayer::render(const glm::mat4 &transform) const {
{ min.x, min.y, max.z, 0, 1, 0 },
};
vbo.setDataKeepSize(pts, sizeof(pts)/sizeof(Coord), GL_STREAM_DRAW);
vbo.bind();
glVertexAttribPointer(P->att("coord"), 3, GL_INT, GL_FALSE, sizeof(Coord), 0);
glVertexAttribPointer(P->att("color"), 3, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(Coord), (GLvoid*)(offsetof(Coord, r)));
const Program &P = *G->PM->getProgram(PM_3D | PM_COLORED);
if (!vaoConfigured) {
vaoConfigured = true;
Render::gl::VAO::Config cfg = vao.configure();
cfg.vertexAttrib(vbo, P.att("coord"), 3, GL_FLOAT, sizeof(Coord), 0);
cfg.vertexAttrib(vbo, P.att("color"), 3, GL_UNSIGNED_BYTE, sizeof(Coord), offsetof(Coord, r));
cfg.commit();
}
P.bind();
glUniformMatrix4fv(P.uni("mvp"), 1, GL_FALSE, glm::value_ptr(transform));
vao.bind();
glDrawArrays(GL_LINES, 0, sizeof(pts)/sizeof(Coord));
glDisableVertexAttribArray(P->att("color"));
glDisableVertexAttribArray(P->att("coord"));
vao.unbind();
}
void LocalPlayer::forceCameraUpdate() {

View File

@ -8,11 +8,11 @@ namespace Diggler {
ParticleEmitter::ParticleEmitter(Game *G) :
G(G) {
G->R->PR->registerEmitter(this);
G->R->renderers.particles->registerEmitter(this);
}
ParticleEmitter::~ParticleEmitter() {
G->R->PR->unregisterEmitter(this);
G->R->renderers.particles->unregisterEmitter(this);
}
void ParticleEmitter::setMaxCount(uint count) {
@ -35,7 +35,7 @@ void ParticleEmitter::emit(Particle &p) {
void ParticleEmitter::update(double delta) {
ParticleRenderData *data = new ParticleRenderData[maxCount];
float deltaF = delta;
for (int i=0; i < maxCount; ++i) {
for (uint i = 0; i < maxCount; ++i) {
Particle &p = particles[i];
p.vel += p.accel * deltaF;
p.pos += p.vel * deltaF;
@ -44,7 +44,7 @@ void ParticleEmitter::update(double delta) {
emit(p);
data[i] = { p.pos.x, p.pos.y, p.pos.z, p.color.r, p.color.g, p.color.b, p.color.a, p.size };
}
G->R->PR->updateParticleData(this, data, maxCount);
G->R->renderers.particles->updateParticleData(this, data, maxCount);
delete[] data;
}

View File

@ -8,11 +8,14 @@
namespace Diggler {
Player::Renderer Player::R = {0};
Player::Renderer Player::R = {};
Player::Player(Game *G) :
G(G), position(0), velocity(0), accel(0), angle(0), toolUseTime(0),
isAlive(true) {
G(G),
angle(0),
toolUseTime(0),
isAlive(true),
peer(nullptr) {
if (GlobalProperties::IsClient) {
if (R.prog == nullptr) {
R.prog = G->PM->getProgram(PM_3D | PM_FOG);
@ -31,34 +34,12 @@ Player::Player(Game *G) :
-sz, .0f, 0.0f,
sz, szH, 0.0f,
};
R.vbo = new Render::gl::VBO;
R.vbo = std::make_unique<Render::gl::VBO>();
R.vbo->setData(coords, 6*3);
}
}
}
using std::swap;
Player::Player(Player &&p) {
*this = std::move(p);
}
Player& Player::operator=(Player &&p) {
swap(direction, p.direction);
swap(G, p.G);
swap(position, p.position);
swap(velocity, p.velocity);
swap(accel, p.accel);
swap(name, p.name);
swap(id, p.id);
swap(P, p.P);
swap(isAlive, p.isAlive);
return *this;
}
Player::~Player() {
delete R.vbo;
}
void Player::setPosVel(const glm::vec3 &pos, const glm::vec3 &vel, const glm::vec3 &acc) {
lastPosition = m_predictPos;
position = m_predictPos = pos;

View File

@ -2,11 +2,14 @@
#define PLAYER_HPP
#include "Platform.hpp"
#include <functional>
#include <list>
#include <memory>
#include <glm/glm.hpp>
#include <epoxy/gl.h>
#include "platform/PreprocUtils.hpp"
#include "network/Network.hpp"
#include "World.hpp"
@ -14,6 +17,7 @@ namespace Diggler {
class Program;
namespace Render {
class PlayerRenderer;
namespace gl {
class VBO;
}
@ -25,6 +29,9 @@ using PlayerGameID = uint32;
class Player {
protected:
friend class Render::PlayerRenderer;
uintptr_t rendererData;
static struct Renderer {
const Program *prog;
GLint att_coord,
@ -32,13 +39,10 @@ protected:
uni_unicolor,
uni_fogStart,
uni_fogEnd;
Render::gl::VBO *vbo;
std::unique_ptr<Render::gl::VBO> vbo;
} R;
double m_lastPosTime;
glm::vec3 m_predictPos;
Player(const Player&) = delete;
Player& operator=(const Player&) = delete;
public:
enum class Direction : uint8 {
@ -60,15 +64,15 @@ public:
glm::vec3 position, lastPosition, velocity, accel;
float angle; double toolUseTime;
std::string name;
uint32 id;
using SessionID = uint32;
SessionID sessId;
bool isAlive;
Net::Peer P;
Net::Peer *peer;
std::list<ChunkRef> pendingChunks;
Player(Game *G = nullptr);
Player(Player&&);
Player& operator=(Player&&);
~Player();
nocopy(Player);
defaultmove(Player);
void setPosVel(const glm::vec3 &pos, const glm::vec3 &vel, const glm::vec3 &acc = glm::vec3());
void update(const float &delta);

View File

@ -31,12 +31,12 @@ void PlayerList::remove(const Player &plr) {
throw std::out_of_range("Can't remove player: not in list");
}
Player* PlayerList::getByGameId(uint32 id) {
if (G->LP && id == G->LP->id)
Player* PlayerList::getBySessId(Player::SessionID sid) {
if (G->LP && sid == G->LP->sessId)
return G->LP;
for (auto it = begin();
it != end(); ++it) {
if (it->id == id) {
if (it->sessId == sid) {
return &*it;
}
}
@ -58,7 +58,7 @@ Player* PlayerList::getByName(const std::string &name) {
Player* PlayerList::getByPeer(const Net::Peer &peer) {
for (auto it = begin();
it != end(); ++it) {
if (it->P == peer) {
if (*it->peer == peer) {
return &*it;
}
}

View File

@ -30,7 +30,7 @@ public:
* @brief Gets a Player using its game session ID
* @return Pointer to Player, may be nullptr if not found
*/
Player* getByGameId(uint32);
Player* getBySessId(Player::SessionID);
/**
* @brief Gets a Player using its name

View File

@ -11,6 +11,7 @@
#include "network/msgtypes/BlockUpdate.hpp"
#include "network/msgtypes/Chat.hpp"
#include "network/msgtypes/ChunkTransfer.hpp"
#include "network/msgtypes/PlayerUpdate.hpp"
#include "network/Network.hpp"
#include "network/NetHelper.hpp"
#include "scripting/lua/State.hpp"
@ -27,8 +28,8 @@ namespace Diggler {
inline Player* Server::getPlayerByPeer(const Peer &peer) {
return G.players.getByPeer(peer);
}
inline Player* Server::getPlayerById(uint32 id) {
return G.players.getByGameId(id);
inline Player *Server::getPlayerBySessId(uint32 id) {
return G.players.getBySessId(id);
}
inline Player* Server::getPlayerByName(const std::string &name) {
return G.players.getByName(name);
@ -36,7 +37,7 @@ inline Player* Server::getPlayerByName(const std::string &name) {
void Server::handlePlayerJoin(InMessage &msg, Peer &peer) {
std::string name = msg.readString();
getOutputStream() << peer.getHost() << " is joining as " << name << std::endl;
getOutputStream() << peer.peerHost() << " is joining as " << name << std::endl;
// TODO: ban list
Player *possible = getPlayerByName(name);
@ -45,42 +46,42 @@ void Server::handlePlayerJoin(InMessage &msg, Peer &peer) {
OutMessage kick(MessageType::PlayerQuit, QuitReason::UsernameAlreadyUsed);
kick.writeString("You are \faalready\f0 playing on this server");
H.send(peer, kick, Tfer::Rel);
getOutputStream() << peer.getHost() << " tried to connect as " << name << ": name is taken" << endl;
getOutputStream() << peer.peerHost() << " tried to connect as " << name << ": name is taken" << endl;
return;
}
Player &plr = G.players.add();
plr.name = name;
plr.id = FastRand();
plr.P = peer;
plr.sessId = FastRand();
plr.peer = &peer;
plr.W = G.U->getLoadWorld(0);
// Confirm successful join
OutMessage join(MessageType::PlayerJoin);
join.writeU32(plr.id);
join.writeU32(plr.sessId);
join.writeI16(plr.W->id);
H.send(peer, join, Tfer::Rel);
// Send the player list
for (Player &p : G.players) {
if (p.id == plr.id)
if (p.sessId == plr.sessId)
continue; // ok, he knows he's here
OutMessage playerMsg(MessageType::PlayerJoin);
playerMsg.writeU32(p.id);
playerMsg.writeU32(p.sessId);
playerMsg.writeString(p.name);
H.send(peer, playerMsg, Tfer::Rel);
}
// Broadcast player's join
OutMessage broadcast(MessageType::PlayerJoin);
broadcast.writeU32(plr.id);
broadcast.writeU32(plr.sessId);
broadcast.writeString(plr.name);
for (Player &p : G.players) {
if (p.id == plr.id)
if (p.sessId == plr.sessId)
continue; // don't send broadcast to the player
H.send(p.P, broadcast, Tfer::Rel);
H.send(*p.peer, broadcast, Tfer::Rel);
}
getOutputStream() << plr.name << " joined from " << peer.getHost() << endl;
getOutputStream() << plr.name << " joined from " << peer.peerHost() << endl;
for (int x = -2; x < 2; ++x)
for (int y = -2; y < 2; ++y)
for (int z = -2; z < 2; ++z)
@ -93,16 +94,16 @@ void Server::handlePlayerQuit(Peer &peer, QuitReason reason) {
Player &plr = *plrPtr;
// Broadcast disconnection
OutMessage broadcast(MessageType::PlayerQuit, reason);
broadcast.writeU32(plr.id);
broadcast.writeU32(plr.sessId);
for (Player &p : G.players) {
if (p.id == plr.id)
if (p.sessId == plr.sessId)
continue; // dont send broadcast to the player
H.send(p.P, broadcast, Tfer::Rel);
H.send(*p.peer, broadcast, Tfer::Rel);
}
getOutputStream() << plr.name << " disconnected" << endl;
G.players.remove(plr);
} else {
getOutputStream() << peer.getHost() << " disconnected" << endl;
getOutputStream() << peer.peerHost() << " disconnected" << endl;
}
}
@ -119,7 +120,7 @@ void Server::handleChat(InMessage &msg, Player *plr) {
cs.readFromMsg(msg);
ChatPlayerTalk cpt;
cpt.player.id = plr->id;
cpt.player.id = plr->sessId;
cpt.msg = cs.msg;
OutMessage omsg;
cpt.writeToMsg(omsg);
@ -137,28 +138,23 @@ void Server::handleCommand(Player *plr, const std::string &command, const std::v
}
void Server::handlePlayerUpdate(InMessage &msg, Player &plr) {
switch (msg.getSubtype()) {
case PlayerUpdateType::Move: {
using namespace Net::MsgTypes;
using S = PlayerUpdateSubtype;
switch (static_cast<S>(msg.getSubtype())) {
case S::Move: {
PlayerUpdateMove pum;
pum.readFromMsg(msg);
pum.plrSessId = plr.sessId;
// Broadcast movement
OutMessage bcast(MessageType::PlayerUpdate, PlayerUpdateType::Move);
bcast.writeU32(plr.id);
glm::vec3 pos = msg.readVec3(),
vel = msg.readVec3(),
acc = msg.readVec3();
plr.setPosVel(pos, vel, acc);
plr.angle = msg.readFloat();
bcast.writeVec3(pos);
bcast.writeVec3(vel);
bcast.writeVec3(acc);
bcast.writeFloat(plr.angle);
OutMessage bcast; pum.writeToMsg(bcast);
for (Player &p : G.players) {
if (p.id == plr.id)
if (p.sessId == plr.sessId)
continue; // dont send broadcast to the player
// TODO: confirm position to player
H.send(p.P, bcast, Tfer::Unrel);
H.send(*p.peer, bcast, Tfer::Unrel);
}
} break;
case PlayerUpdateType::Die:
case S::Die:
handlePlayerDeath(msg, plr);
break;
default:
@ -188,7 +184,7 @@ void Server::sendChunks(const std::list<ChunkRef> &cs, Player &P) {
}
OutMessage msg;
ctr.writeToMsg(msg);
H.send(P.P, msg, Tfer::Rel, Channels::MapTransfer);
H.send(*P.peer, msg, Tfer::Rel, Channels::MapTransfer);
}
void Server::handlePlayerChunkRequest(InMessage &msg, Player &plr) {
@ -263,26 +259,27 @@ void Server::handlePlayerMapUpdate(InMessage &msg, Player &plr) {
}
void Server::handlePlayerDeath(InMessage &msg, Player &plr) {
uint8 drb = msg.readU8();
Player::DeathReason dr = (Player::DeathReason)drb;
plr.setDead(false, dr);
OutMessage out(MessageType::PlayerUpdate, PlayerUpdateType::Die);
out.writeU32(plr.id);
out.writeU8(drb);
using namespace Net::MsgTypes;
PlayerUpdateDie pud;
pud.readFromMsg(msg);
pud.plrSessId = plr.sessId;
plr.setDead(false, pud.reason);
OutMessage out; pud.writeToMsg(out);
for (Player &p : G.players) {
if (p.id != plr.id)
H.send(p.P, out, Tfer::Rel, Channels::Life);
if (p.sessId != plr.sessId)
H.send(*p.peer, out, Tfer::Rel, Channels::Life);
}
// Respawn player later
Game *G = &this->G; uint32 id = plr.id;
std::thread respawn([G, id] {
Game *G = &this->G; Player::SessionID sid = plr.sessId;
std::thread respawn([G, sid] {
std::this_thread::sleep_for(std::chrono::seconds(2));
Player *plr = G->S->getPlayerById(id);
Player *plr = G->S->getPlayerBySessId(sid);
if (plr) {
plr->setDead(false);
OutMessage out(MessageType::PlayerUpdate, PlayerUpdateType::Respawn);
out.writeU32(id);
PlayerUpdateRespawn pur;
pur.plrSessId = sid;
OutMessage out; pur.writeToMsg(out);
NetHelper::Broadcast(G, out, Tfer::Rel, Channels::Life);
}
});
@ -380,12 +377,13 @@ void Server::chunkUpdater(WorldRef WR, bool &continueUpdate) {
void Server::run() {
InMessage msg;
Peer peer;
Peer *peerPtr;
bool continueUpdate = true;
std::thread upd(&Server::chunkUpdater, this, G.U->getWorld(0), std::ref(continueUpdate));
Player *plr;
while (true) {
if (H.recv(msg, peer, 100)) {
if (H.recv(msg, &peerPtr, 100)) {
Peer &peer = *peerPtr;
plr = getPlayerByPeer(peer);
if (plr != nullptr) {
switch (msg.getType()) {
@ -408,7 +406,7 @@ void Server::run() {
}
switch (msg.getType()) {
case MessageType::NetConnect:
getOutputStream() << peer.getHost() << " NEWCONN" << std::endl;
getOutputStream() << peer.peerHost() << " NEWCONN" << std::endl;
break;
case MessageType::NetDisconnect:
handleDisconnect(peer);
@ -441,10 +439,10 @@ bool Server::isPlayerOnline(const std::string &playername) const {
void Server::kick(Player &p, Net::QuitReason r, const std::string &message) {
OutMessage msg(MessageType::PlayerQuit, r);
msg.writeU32(p.id);
msg.writeU32(p.sessId);
msg.writeString(message);
H.send(p.P, msg, Tfer::Rel);
p.P.disconnect();
H.send(*p.peer, msg, Tfer::Rel);
p.peer->disconnect();
}
Server::~Server() {

View File

@ -50,7 +50,7 @@ public:
bool isPlayerOnline(const std::string &playername) const;
bool isIPOnline(const std::string &ip) const;
Player* getPlayerById(uint32 id);
Player* getPlayerBySessId(uint32 id);
Player* getPlayerByPeer(const Net::Peer &peer);
Player* getPlayerByName(const std::string &name);
void kick(Player &p, Net::QuitReason r = Net::QuitReason::Kicked, const std::string& message = "");

View File

@ -102,10 +102,14 @@ void Texture::setFiltering(Filter min, Filter mag) {
static GLenum getWrapGlConstant(Texture::Wrapping wrap) {
switch (wrap) {
case Texture::Wrapping::Clamp:
return GL_CLAMP;
case Texture::Wrapping::ClampEdge:
return GL_CLAMP_TO_EDGE;
case Texture::Wrapping::ClampBorder:
return GL_CLAMP_TO_BORDER;
case Texture::Wrapping::Repeat:
return GL_REPEAT;
case Texture::Wrapping::MirroredRepeat:
return GL_MIRRORED_REPEAT;
}
return 0;
}

View File

@ -16,8 +16,10 @@ public:
Linear
};
enum class Wrapping {
ClampEdge,
ClampBorder,
Repeat,
Clamp
MirroredRepeat
};
private:
GLuint m_id;
@ -54,7 +56,9 @@ public:
void setSubTexture(int x, int y, uint w, uint h, const uint8_t *data, PixelFormat format = PixelFormat::RGB);
void setFiltering(Filter min, Filter mag);
void setWrapping(Wrapping s, Wrapping t);
inline void setWrapping(Wrapping w) {
setWrapping(w, w);
}
void bind() const {
glBindTexture(GL_TEXTURE_2D, m_id);

View File

@ -1,5 +1,5 @@
#ifndef VERSION_INFO_HPP
#define VERSION_INFO_HPP
#ifndef DIGGLER_VERSION_INFO_HPP
#define DIGGLER_VERSION_INFO_HPP
namespace Diggler {
const char* VersionString = "0.1.0";
@ -8,4 +8,4 @@ namespace Diggler {
int VersionRevision = 0;
}
#endif
#endif /* DIGGLER_VERSION_INFO_HPP */

View File

@ -1,5 +1,6 @@
#ifndef WORLD_GENERATOR_HPP
#define WORLD_GENERATOR_HPP
#ifndef DIGGLER_WORLD_GENERATOR_HPP
#define DIGGLER_WORLD_GENERATOR_HPP
#include <glm/vec3.hpp>
namespace Diggler {
@ -13,4 +14,4 @@ public:
}
#endif
#endif /* DIGGLER_WORLD_GENERATOR_HPP */

44
src/content/Asset.hpp Normal file
View File

@ -0,0 +1,44 @@
#ifndef DIGGLER_CONTENT_ASSET_HPP
#define DIGGLER_CONTENT_ASSET_HPP
#include <msgpack.hpp>
#include "../crypto/SHA256.hpp"
namespace Diggler {
namespace Content {
class Asset {
public:
enum class Type {
Texture,
Sound,
Music,
Schematic,
Model,
VoxelModel
};
protected:
Crypto::SHA256::Digest m_hash;
Type m_type;
msgpack::object m_info;
public:
const Crypto::SHA256::Digest& hash() const {
return m_hash;
}
Type type() const {
return m_type;
}
const msgpack::object& info() const {
return m_info;
}
};
}
}
#endif /* DIGGLER_CONTENT_ASSET_HPP */

View File

@ -0,0 +1,13 @@
#include "AssetManager.hpp"
#include "../Game.hpp"
namespace Diggler {
namespace Content {
AssetManager::AssetManager(Game *G) :
G(G) {
}
}
}

View File

@ -0,0 +1,26 @@
#ifndef DIGGLER_CONTENT_ASSET_MANAGER_HPP
#define DIGGLER_CONTENT_ASSET_MANAGER_HPP
#include "Asset.hpp"
#include "Mod.hpp"
namespace Diggler {
class Game;
namespace Content {
class AssetManager final {
private:
Game *G;
public:
AssetManager(Game*);
};
}
}
#endif /* DIGGLER_CONTENT_ASSET_MANAGER_HPP */

22
src/content/Mod.hpp Normal file
View File

@ -0,0 +1,22 @@
#ifndef DIGGLER_CONTENT_MOD_HPP
#define DIGGLER_CONTENT_MOD_HPP
#include <string>
#include "../Platform.hpp"
namespace Diggler {
namespace Content {
using ModId = byte[32];
class Mod {
public:
ModId id;
std::string name, fsPath;
};
}
}
#endif /* DIGGLER_CONTENT_MOD_HPP */

View File

@ -0,0 +1,13 @@
#include "ModManager.hpp"
#include "../Game.hpp"
namespace Diggler {
namespace Content {
ModManager::ModManager(Game *G) :
G(G) {
}
}
}

View File

@ -0,0 +1,57 @@
#ifndef DIGGLER_CONTENT_MOD_MANAGER_HPP
#define DIGGLER_CONTENT_MOD_MANAGER_HPP
#include "Mod.hpp"
namespace Diggler {
class Game;
namespace Content {
class ModManager final {
private:
Game *G;
public:
ModManager(Game*);
/**
* @brief Resolves a mod-relative or absolute path into a filesystem path
* Accepted schemes: builtin, mod:*, self
* @param mod Mod context
* @param path Mod-relative or absolute path
* @return Resolved filesystem path
*/
std::string filesystemPath(const Mod &mod, const std::string &path);
/**
* @brief Resolves an absolute path into a filesystem path
* Accepted schemes: builtin, mod:*
* @param path Absolute path
* @return Resolved filesystem path
*/
std::string filesystemPath(const std::string &path);
/**
* @brief Determines if the path is absolute or mod-relative (i.e. requires a mod context to be
* resolved)
* @param path Path to check
* @return true if path is absolute, false otherwise
*/
static bool isAbsolutePath(const std::string &path);
/**
* @brief Resolves a mod-relative path into an absolute path
* Accepted schemes: builtin, mod:*, self
* @param path Mod-relative path
* @return Resolved filesystem path
*/
std::string absolutePath(const Mod &mod, const std::string &path);
};
}
}
#endif /* DIGGLER_CONTENT_MOD_MANAGER_HPP */

70
src/crypto/CryptoData.hpp Normal file
View File

@ -0,0 +1,70 @@
#ifndef DIGGLER_CRYPTO_CRYPTODATA_HPP
#define DIGGLER_CRYPTO_CRYPTODATA_HPP
#include <cstring>
#include <string>
#include <sodium.h>
namespace Diggler {
namespace Crypto {
template<size_t B>
struct CryptoData {
constexpr static size_t Length = B;
union {
unsigned char data[Length], bytes[Length];
};
bool operator==(const CryptoData<B> &o) const {
return sodium_memcmp(data, o.data, Length);
}
bool operator!=(const CryptoData<B> &o) const {
return !operator==(o);
}
unsigned char& operator[](size_t idx) {
return data[idx];
}
unsigned char operator[](size_t idx) const {
return data[idx];
}
void zerofill() {
memset(data, 0, Length);
}
std::string hex(bool caps = false) const {
std::string hex(Length * 2, '\0');
const char *hextab = caps ? "0123456789ABCDEF" : "0123456789abcdef";
for (size_t i = 0; i < Length; ++i) {
hex[i * 2 + 0] = hextab[data[i] >> 4];
hex[i * 2 + 1] = hextab[data[i] & 0xF];
}
return hex;
}
};
template<size_t B>
struct MlockedCryptoData : CryptoData<B> {
MlockedCryptoData() {
sodium_mlock(this->data, this->Length);
}
MlockedCryptoData(MlockedCryptoData<B> &o) {
sodium_mlock(this->data, this->Length);
memcpy(this->data, o.data, this->Length);
}
~MlockedCryptoData() {
sodium_munlock(this->data, this->Length);
}
};
}
}
#endif /* DIGGLER_CRYPTO_CRYPTODATA_HPP */

View File

@ -0,0 +1,37 @@
#ifndef DIGGLER_CRYPTO_DIFFIE_HELLMAN_HPP
#define DIGGLER_CRYPTO_DIFFIE_HELLMAN_HPP
#include <sodium.h>
#include "CryptoData.hpp"
namespace Diggler {
namespace Crypto {
namespace DiffieHellman {
constexpr static size_t ScalarBytes = crypto_scalarmult_SCALARBYTES;
constexpr static size_t Bytes = crypto_scalarmult_BYTES;
struct SecretKey : MlockedCryptoData<ScalarBytes> {
};
struct PublicKey : CryptoData<Bytes> {
};
struct SharedSecret : MlockedCryptoData<Bytes> {
};
inline void scalarmultBase(const SecretKey &sk, PublicKey &pk) {
crypto_scalarmult_base(pk.bytes, sk.bytes);
}
[[gnu::warn_unused_result]]
inline bool scalarmult(const SecretKey &sk, const PublicKey &pk, SharedSecret &ss) {
return crypto_scalarmult(ss.bytes, sk.bytes, pk.bytes);
}
}
}
}
#endif /* DIGGLER_CRYPTO_DIFFIE_HELLMAN_HPP */

38
src/crypto/Random.hpp Normal file
View File

@ -0,0 +1,38 @@
#ifndef DIGGLER_CRYPTO_RANDOM_HPP
#define DIGGLER_CRYPTO_RANDOM_HPP
#include <sodium.h>
#include "CryptoData.hpp"
#include "../platform/Types.hpp"
namespace Diggler {
namespace Crypto {
namespace Random {
uint32 random() {
return randombytes_random();
}
uint32 uniform(const uint32 upperBound) {
return randombytes_uniform(upperBound);
}
void buf(void *const buf, const size_t size) {
randombytes_buf(buf, size);
}
template<size_t B>
void randomData(CryptoData<B> &cd) {
randombytes_buf(cd.bytes, cd.Length);
}
void stir() {
randombytes_stir();
}
}
}
}
#endif /* DIGGLER_CRYPTO_RANDOM_HPP */

42
src/crypto/SHA256.hpp Normal file
View File

@ -0,0 +1,42 @@
#ifndef DIGGLER_CRYPTO_SHA256_HPP
#define DIGGLER_CRYPTO_SHA256_HPP
#include <sodium.h>
#include "CryptoData.hpp"
namespace Diggler {
namespace Crypto {
struct SHA256 {
constexpr static size_t DigestBytes = crypto_hash_sha256_BYTES;
struct Digest : CryptoData<SHA256::DigestBytes> {
};
crypto_hash_sha256_state state;
SHA256() {
crypto_hash_sha256_init(&state);
}
template<typename T>
void update(const T *data, size_t len) {
crypto_hash_sha256_update(&state, data, len);
}
void finalize(unsigned char *digest) {
crypto_hash_sha256_final(&state, digest);
}
Digest finalize() {
Digest digest;
crypto_hash_sha256_final(&state, digest.bytes);
return digest;
}
};
}
}
#endif /* DIGGLER_CRYPTO_SHA256_HPP */

41
src/crypto/Sign.hpp Normal file
View File

@ -0,0 +1,41 @@
#ifndef DIGGLER_CRYPTO_SIGN_HPP
#define DIGGLER_CRYPTO_SIGN_HPP
#include <sodium.h>
#include "CryptoData.hpp"
namespace Diggler {
namespace Crypto {
namespace Sign {
constexpr size_t PublicKeyBytes = crypto_sign_PUBLICKEYBYTES;
constexpr size_t SecretKeyBytes = crypto_sign_SECRETKEYBYTES;
constexpr size_t SignatureBytes = crypto_sign_BYTES;
struct PublicKey : CryptoData<PublicKeyBytes> {
};
struct SecretKey : MlockedCryptoData<SecretKeyBytes> {
};
struct Signature : CryptoData<SignatureBytes> {
};
void keypair(PublicKey &pk, SecretKey &sk) {
crypto_sign_keypair(pk.bytes, sk.bytes);
}
void sign(const unsigned char *m, unsigned long long mlen, const SecretKey &sk, Signature &sig) {
crypto_sign_detached(sig.bytes, nullptr, m, mlen, sk.bytes);
}
bool verify(const unsigned char *m, unsigned long long mlen, Signature &sig, const PublicKey &pk) {
return crypto_sign_verify_detached(sig.bytes, m, mlen, pk.bytes);
}
}
}
}
#endif /* DIGGLER_CRYPTO_SIGN_HPP */

15
src/crypto/Sodium.hpp Normal file
View File

@ -0,0 +1,15 @@
#ifndef DIGGLER_CRYPTO_SODIUM_HPP
#define DIGGLER_CRYPTO_SODIUM_HPP
namespace Diggler {
namespace Crypto {
class Sodium {
public:
};
}
}
#endif /* DIGGLER_CRYPTO_SODIUM_HPP */

View File

@ -134,12 +134,13 @@ int main(int argc, char **argv) {
/*/GW.setNextState(std::make_shared<UITestState>(&GW));/*/
if (networkSuccess)
GW.setNextState(std::make_shared<GameState>(&GW, host, port));
GW.setNextState(std::move(std::make_unique<GameState>(&GW, host, port)));
else
GW.showMessage("Network init failed!");
/**/
GW.run();
G->finalizeClient();
}
G.reset();
}

View File

@ -6,6 +6,7 @@
#include "msgtypes/BlockUpdate.hpp"
#include "msgtypes/Chat.hpp"
#include "msgtypes/ChunkTransfer.hpp"
#include "msgtypes/PlayerUpdate.hpp"
namespace Diggler {
namespace Net {
@ -65,7 +66,7 @@ bool ClientMessageHandler::handleMessage(InMessage &msg) {
if (cpt.msg.type == msgpack::type::STR) {
std::string playerName;
if (cpt.player.display.type == msgpack::type::NIL) {
const Player *blabbermouth = GS.G->players.getByGameId(cpt.player.id);
const Player *blabbermouth = GS.G->players.getBySessId(cpt.player.id);
if (blabbermouth != nullptr) {
playerName = blabbermouth->name + "> ";
} else {
@ -81,14 +82,14 @@ bool ClientMessageHandler::handleMessage(InMessage &msg) {
} break;
case MessageType::PlayerJoin: {
Player &plr = GS.G->players.add();
plr.id = msg.readU32();
plr.sessId = msg.readU32();
plr.name = msg.readString();
getDebugStream() << "Player " << plr.name << '(' << plr.id << ") joined the party!" << std::endl;
getDebugStream() << "Player " << plr.name << '(' << plr.sessId << ") joined the party!" << std::endl;
} break;
case MessageType::PlayerQuit: {
uint32 id = msg.readU32();
try {
Player *plr = GS.G->players.getByGameId(id);
Player *plr = GS.G->players.getBySessId(id);
if (plr != nullptr) {
getOutputStream() << plr->name << " is gone :(" << std::endl;
GS.G->players.remove(*plr);
@ -98,30 +99,51 @@ bool ClientMessageHandler::handleMessage(InMessage &msg) {
}
} break;
case MessageType::PlayerUpdate: {
uint32 id = msg.readU32();
try {
Player *plr = GS.G->players.getByGameId(id);
if (plr != nullptr) {
switch (msg.getSubtype()) {
case PlayerUpdateType::Move: {
glm::vec3 pos = msg.readVec3(),
vel = msg.readVec3(),
acc = msg.readVec3();
plr->setPosVel(pos, vel, acc);
plr->angle = msg.readFloat();
} break;
case PlayerUpdateType::Die:
plr->setDead(false, (Player::DeathReason)msg.readU8());
break;
case PlayerUpdateType::Respawn:
plr->setDead(false);
break;
default:
break;
using S = PlayerUpdateSubtype;
switch (static_cast<S>(msg.getSubtype())) {
case S::Move: {
PlayerUpdateMove pum;
pum.readFromMsg(msg);
if (!pum.plrSessId) {
getOutputStream() << "PlayerUpdateMove without player session ID" << std::endl;
return true;
}
}
} catch (const std::out_of_range &e) {
getOutputStream() << "Invalid player update: #" << id << " is not on server" << std::endl;
Player *plr = GS.G->players.getBySessId(*pum.plrSessId);
if (!plr) {
getOutputStream() << "PlayerUpdateMove: sess#" << *pum.plrSessId <<
" is not on server" << std::endl;
return true;
}
glm::vec3 pos = pum.position ? *pum.position : plr->position,
vel = pum.velocity ? *pum.velocity : plr->velocity,
acc = pum.accel ? *pum.accel : plr->accel;
plr->setPosVel(pos, vel, acc);
plr->angle = pum.angle;
} break;
case S::Die: {
PlayerUpdateDie pud;
pud.readFromMsg(msg);
Player *plr = GS.G->players.getBySessId(pud.plrSessId);
if (!plr) {
getOutputStream() << "PlayerUpdateDie: sess#" << pud.plrSessId <<
" is not on server" << std::endl;
return true;
}
plr->setDead(false, pud.reason);
} break;
case S::Respawn: {
PlayerUpdateRespawn pur;
pur.readFromMsg(msg);
Player *plr = GS.G->players.getBySessId(pur.plrSessId);
if (!plr) {
getOutputStream() << "PlayerUpdateRespawn: sess#" << pur.plrSessId <<
" is not on server" << std::endl;
return true;
}
plr->setDead(false);
} break;
default:
break;
}
} break;
case MessageType::BlockUpdate: {

View File

@ -17,7 +17,7 @@ void Broadcast(Game *G, const OutMessage &msg, Tfer tfer, Channels chan) {
void Broadcast(Game &G, const OutMessage &msg, Tfer tfer, Channels chan) {
for (Player &p : G.players) {
G.S->H.send(p.P, msg, tfer, chan);
G.S->H.send(*p.peer, msg, tfer, chan);
}
}
@ -27,20 +27,7 @@ void SendChat(Game *G, const std::string &str) {
OutMessage msg;
cs.writeToMsg(msg);
G->H.send(G->NS, msg, Tfer::Unseq);
}
void SendToolUse(Game *G, int x, int y, int z) {
OutMessage msg(MessageType::PlayerUpdate, PlayerUpdateType::ToolUse);
msg.writeBool(true);
msg.writeIVec3(x, y, z);
G->H.send(G->NS, msg, Tfer::Rel, Channels::PlayerInteract);
}
void SendToolUse(Game *G) {
OutMessage msg(MessageType::PlayerUpdate, PlayerUpdateType::ToolUse);
msg.writeBool(false);
G->H.send(G->NS, msg, Tfer::Rel, Channels::PlayerInteract);
G->H.send(*G->NS, msg, Tfer::Unseq);
}

View File

@ -20,10 +20,8 @@ void MakeEvent(Net::OutMessage&, Net::EventType, const Player&);
void SendEvent(Game*, Net::EventType);
void SendChat(Game*, const std::string&);
void SendToolUse(Game*);
void SendToolUse(Game*, int x, int y, int z);
}
}
#endif
#endif

View File

@ -1,10 +1,16 @@
#include "Network.hpp"
#include <enet/enet.h>
#include <chrono>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <memory>
#include <enet/enet.h>
#include "../crypto/Random.hpp"
#include "msgtypes/ConnectionParam.hpp"
#include <iomanip>
namespace Diggler {
@ -53,8 +59,7 @@ Message::Message(MessageType t, uint8 s) :
InMessage::InMessage() :
Message(MessageType::Null, 0),
m_chan(Channels::Base),
m_packet(nullptr) {
m_chan(Channels::Base) {
}
InMessage::~InMessage() {
@ -79,36 +84,17 @@ void InMessage::fromData(const void *data, SizeT len, Channels chan) {
m_length = len;
m_type = static_cast<MessageType>(bytes[0]);
m_subtype = bytes[1];
m_data = static_cast<uint8*>(std::malloc(len-HeaderSize));
std::memcpy(m_data, &(bytes[HeaderSize]), len-HeaderSize);
}
void InMessage::fromPacket(void *packet, Channels chan) {
ENetPacket *enpkt = static_cast<ENetPacket*>(packet);
SizeT len = enpkt->dataLength;
if (len < HeaderSize) {
throw std::invalid_argument("Message length is smaller than message header");
}
uint8 *const bytes = static_cast<uint8*>(enpkt->data);
free();
m_packet = packet;
m_chan = chan;
m_cursor = 0;
m_length = len;
m_type = static_cast<MessageType>(bytes[0]);
m_subtype = bytes[1];
m_data = &(bytes[HeaderSize]);
// m_data/bytes is guaranteed never to be written to, so we can const_cast it
m_data = const_cast<uint8*>(bytes) + HeaderSize;
}
void InMessage::free() {
if (m_packet != nullptr) {
enet_packet_destroy(static_cast<ENetPacket*>(m_packet));
} else {
std::free(m_data);
if (m_data != nullptr) {
delete[] (m_data - HeaderSize);
}
m_type = MessageType::Null;
m_subtype = m_length = m_cursor = 0;
m_packet = m_data = nullptr;
m_data = nullptr;
}
@ -160,6 +146,14 @@ Channels InMessage::getChannel() const {
return m_chan;
}
Peer::Peer(Host &host, void *peer) :
host(host),
peer(peer) {
reinterpret_cast<ENetPeer*>(this->peer)->data = this;
Crypto::Random::randomData(connectionPk);
Crypto::DiffieHellman::scalarmultBase(connectionSk, connectionPk);
}
bool Peer::operator==(const Peer &other) const {
return peer == other.peer;
}
@ -168,13 +162,13 @@ bool Peer::operator!=(const Peer &other) const {
return !(*this == other);
}
void Peer::disconnect() {
ENetPeer *const peer = static_cast<ENetPeer*>(this->peer);
enet_peer_disconnect(peer, 0);
void Peer::disconnect(uint32 data) {
ENetPeer *const peer = reinterpret_cast<ENetPeer*>(this->peer);
enet_peer_disconnect(peer, data);
}
std::string Peer::getHost() {
const ENetPeer *const peer = static_cast<const ENetPeer*>(this->peer);
std::string Peer::peerHost() {
const ENetPeer *const peer = reinterpret_cast<const ENetPeer*>(this->peer);
std::ostringstream oss;
char *chars = new char[512];
enet_address_get_host_ip(&peer->host->address, chars, 512);
@ -184,8 +178,8 @@ std::string Peer::getHost() {
return oss.str();
}
std::string Peer::getIp() {
const ENetPeer *const peer = static_cast<const ENetPeer*>(this->peer);
std::string Peer::peerIP() {
const ENetPeer *const peer = reinterpret_cast<const ENetPeer*>(this->peer);
char *chars = new char[512];
enet_address_get_host_ip(&peer->host->address, chars, 512);
std::string str(chars);
@ -193,8 +187,8 @@ std::string Peer::getIp() {
return str;
}
Port Peer::getPort() {
const ENetPeer *const peer = static_cast<const ENetPeer*>(this->peer);
Port Peer::peerPort() {
const ENetPeer *const peer = reinterpret_cast<const ENetPeer*>(this->peer);
return peer->host->address.port;
}
@ -206,6 +200,11 @@ Host::Host() :
txBytes(0) {
}
Host::~Host() {
ENetHost *const host = reinterpret_cast<ENetHost*>(this->host);
enet_host_destroy(host);
}
void Host::create(Port port, uint maxconn) {
if (port == 0) { // Client
host = enet_host_create(nullptr, 1, static_cast<size_t>(Channels::MAX), 0, 0);
@ -220,8 +219,8 @@ void Host::create(Port port, uint maxconn) {
}
}
Peer Host::connect(const std::string &hostAddr, Port port, Timeout timeout) {
ENetHost *const host = static_cast<ENetHost*>(this->host);
Peer& Host::connect(const std::string &hostAddr, Port port, Timeout timeout) {
ENetHost *const host = reinterpret_cast<ENetHost*>(this->host);
ENetAddress address;
ENetEvent event;
ENetPeer *peer;
@ -236,102 +235,140 @@ Peer Host::connect(const std::string &hostAddr, Port port, Timeout timeout) {
if (enet_host_service(host, &event, timeout) > 0 &&
event.type == ENET_EVENT_TYPE_CONNECT) {
Peer p; p.peer = peer;
return p;
Peer *p = new Peer(*this, peer);
sendKeyExchange(*p);
return *p;
}
enet_peer_reset(peer);
throw Exception();
}
Host::~Host() {
ENetHost *const host = static_cast<ENetHost*>(this->host);
enet_host_destroy(host);
void Host::processPeersToDelete() {
for (Peer *peer : m_peersToDelete) {
delete peer;
}
m_peersToDelete.clear();
}
/*static void hexDump(char in, uint8 *buf, int len) {
void Host::sendKeyExchange(Peer &p) {
MsgTypes::ConnectionParamDHKeyExchange dhke;
dhke.pk = p.connectionPk;
OutMessage keMsg;
dhke.writeToMsg(keMsg);
send(p, keMsg);
}
static void hexDump(char in, uint8 *buf, int len) {
std::cout << in << ": " << std::setiosflags(std::ios::internal);
for (int i=0; i < len; ++i) {
std::cout << std::setfill('0') << std::setw(2) << std::hex << (int)buf[i] << ' ';
}
std::cout << std::dec << std::endl;
}*/
bool Host::recv(InMessage &msg, Peer &peer, Timeout timeout) {
ENetHost *const host = static_cast<ENetHost*>(this->host);
ENetEvent event;
if (enet_host_service(host, &event, timeout) >= 0){
switch (event.type) {
case ENET_EVENT_TYPE_NONE:
return false;
case ENET_EVENT_TYPE_CONNECT:
peer.peer = event.peer;
msg.setType(MessageType::NetConnect);
break;
case ENET_EVENT_TYPE_RECEIVE:
peer.peer = event.peer;
//hexDump('R', event.packet->data, event.packet->dataLength);
// Packet "ownership" is transferred to msg
msg.fromPacket(event.packet, static_cast<Channels>(event.channelID));
rxBytes += event.packet->dataLength;
break;
case ENET_EVENT_TYPE_DISCONNECT:
peer.peer = event.peer;
msg.setType(MessageType::NetDisconnect);
enet_peer_reset(event.peer);
}
return true;
}
throw Exception();
}
bool Host::recv(InMessage &msg, Timeout timeout) {
ENetHost *const host = static_cast<ENetHost*>(this->host);
bool Host::recv(InMessage &msg, Peer **peer, Timeout timeout) {
ENetHost *const host = reinterpret_cast<ENetHost*>(this->host);
processPeersToDelete();
auto start = std::chrono::steady_clock::now();
ENetEvent event;
if (enet_host_service(host, &event, timeout) >= 0){
switch (event.type) {
case ENET_EVENT_TYPE_NONE:
while (true) {
auto now = std::chrono::steady_clock::now();
enet_uint32 elapsed = static_cast<enet_uint32>(
std::chrono::duration_cast<std::chrono::milliseconds>(now - start).count());
if (enet_host_service(host, &event, timeout - elapsed) > 0) {
Peer *peerPtr = event.peer == nullptr ? nullptr :
reinterpret_cast<Peer*>(event.peer->data);
switch (event.type) {
case ENET_EVENT_TYPE_NONE:
break;
case ENET_EVENT_TYPE_CONNECT:
peerPtr = new Peer(*this, event.peer);
*peer = peerPtr;
sendKeyExchange(*peerPtr);
msg.setType(MessageType::NetConnect);
return true;
case ENET_EVENT_TYPE_RECEIVE: {
if (peer) {
*peer = peerPtr;
}
const Message::SizeT pktLen = event.packet->dataLength;
const Channels pktChannel = static_cast<Channels>(event.channelID);
const bool decrypt = (pktChannel == Channels::ConnectionMetaPlain);
byte *rcvData = new uint8[pktLen];
if (decrypt) {
// TODO: decryption
std::memcpy(rcvData, event.packet->data, pktLen);
} else {
std::memcpy(rcvData, event.packet->data, pktLen);
}
// pktData's ownership is transferred to msg
msg.fromData(rcvData, pktLen, pktChannel);
rxBytes += event.packet->dataLength;
if (msg.getType() == MessageType::ConnectionParam &&
msg.getSubtype() == static_cast<int>(MsgTypes::ConnectionParamSubtype::DHKeyExchange)) {
MsgTypes::ConnectionParamDHKeyExchange dhke; dhke.readFromMsg(msg);
peerPtr->remotePk = dhke.pk;
if (Crypto::DiffieHellman::scalarmult(peerPtr->connectionSk, peerPtr->remotePk,
peerPtr->sharedSecret) != 0) {
// TODO: properly handle key exchange failure
throw std::runtime_error("DH key exchange failed");
}
getDebugStream() << "hello DH! " << peerPtr->sharedSecret.hex() << std::endl;
} else {
return true;
}
} break;
case ENET_EVENT_TYPE_DISCONNECT:
if (peer) {
*peer = peerPtr;
}
msg.setType(MessageType::NetDisconnect);
m_peersToDelete.emplace_back(peerPtr);
return true;
}
} else {
return false;
case ENET_EVENT_TYPE_CONNECT:
msg.setType(MessageType::NetConnect);
break;
case ENET_EVENT_TYPE_RECEIVE:
//hexDump('R', event.packet->data, event.packet->dataLength);
// Packet "ownership" is transferred to msg
msg.fromPacket(event.packet, static_cast<Channels>(event.channelID));
rxBytes += event.packet->dataLength;
break;
case ENET_EVENT_TYPE_DISCONNECT:
msg.setType(MessageType::NetDisconnect);
enet_peer_reset(event.peer);
}
return true;
}
throw Exception();
}
void Host::send(Peer &peer, const OutMessage &msg, Tfer mode, Channels chan) {
ENetHost *const host = static_cast<ENetHost*>(this->host);
ENetHost *const host = reinterpret_cast<ENetHost*>(this->host);
const bool encrypt = (chan == Channels::ConnectionMetaPlain);
const uint8 header[Message::HeaderSize] = {
static_cast<uint8>(msg.m_type),
const byte header[Message::HeaderSize] = {
static_cast<byte>(msg.m_type),
msg.m_subtype
};
ENetPacket *packet;
size_t pktLen = Message::HeaderSize + (msg.m_actualData == nullptr ? 0 : msg.m_length);
ENetPacket *packet = enet_packet_create(nullptr, pktLen, TferToFlags(mode));
byte *pktData = packet->data;
txBytes += pktLen;
if (msg.m_actualData != nullptr) {
std::memcpy(msg.m_actualData, header, Message::HeaderSize);
packet = enet_packet_create(msg.m_actualData,
Message::HeaderSize + msg.m_length, TferToFlags(mode));
txBytes += Message::HeaderSize + msg.m_length;
if (encrypt) {
// TODO: don't memcpy, encrypt!
std::memcpy(pktData, msg.m_actualData, pktLen);
} else {
std::memcpy(pktData, msg.m_actualData, pktLen);
}
} else {
packet = enet_packet_create(header,
Message::HeaderSize, TferToFlags(mode));
txBytes += Message::HeaderSize;
if (encrypt) {
// TODO: don't memcpy, encrypt!
std::memcpy(pktData, header, pktLen);
} else {
std::memcpy(pktData, header, pktLen);
}
}
//hexDump('S', packet->data, 2+msg.m_length);
enet_peer_send(static_cast<ENetPeer*>(peer.peer), static_cast<uint8>(chan), packet);
hexDump('S', pktData, pktLen);
enet_peer_send(reinterpret_cast<ENetPeer*>(peer.peer), static_cast<uint8>(chan), packet);
enet_host_flush(host);
}

View File

@ -1,10 +1,15 @@
#ifndef NETWORK_HPP
#define NETWORK_HPP
#include "../Platform.hpp"
#include "../io/MemoryStream.hpp"
#include <glm/vec3.hpp>
#include <exception>
#include <glm/vec3.hpp>
#include "../Platform.hpp"
#include "../platform/PreprocUtils.hpp"
#include "../crypto/DiffieHellman.hpp"
#include "../io/MemoryStream.hpp"
namespace Diggler {
namespace Net {
@ -20,6 +25,8 @@ enum class Tfer {
enum class Channels : uint8 {
Base = 0,
ConnectionMeta,
ConnectionMetaPlain,
Chat,
Life,
Movement,
@ -35,6 +42,8 @@ enum class MessageType : uint8 {
ServerInfo = 220,
ConnectionParam = 200,
PlayerJoin = 1,
PlayerUpdate,
PlayerQuit,
@ -46,16 +55,6 @@ enum class MessageType : uint8 {
NetDisconnect
};
enum PlayerUpdateType : uint8 {
Move,
ChangeTool,
ChangeClass,
ChangeTeam,
Die,
Respawn,
ToolUse
};
enum QuitReason : uint8 {
Quit,
Timeout,
@ -82,6 +81,8 @@ protected:
public:
static constexpr uint HeaderSize = 2;
virtual ~Message() {}
inline MessageType getType() const { return m_type; }
inline uint8 getSubtype() const { return m_subtype; }
@ -94,10 +95,8 @@ class InMessage : public Message, public InMemoryStream {
protected:
friend class Host;
Channels m_chan;
void *m_packet;
void setType(MessageType type);
void fromData(const void *data, SizeT len, Channels chan = Channels::Base);
void fromPacket(void *packet, Channels chan = Channels::Base);
void fromData(const void *data, SizeT, Channels);
void free();
public:
@ -166,20 +165,43 @@ class Exception : public std::exception {
using Port = uint16;
class Host;
struct Peer {
void *peer;
Crypto::DiffieHellman::SecretKey connectionSk;
Crypto::DiffieHellman::PublicKey connectionPk;
Crypto::DiffieHellman::PublicKey remotePk;
Crypto::DiffieHellman::SharedSecret sharedSecret;
Host &host;
void *const peer;
Peer(Host&, void*);
nocopy(Peer);
nomove(Peer);
bool operator==(const Peer&) const;
bool operator!=(const Peer&) const;
void disconnect();
std::string getHost();
std::string getIp();
Port getPort();
/**
* @brief Disconnects the peer.
* @param data
* Adds the peer for pending disconnection. A NetDisconnect event will be generated once the
* peer has successfully disconnected, and the current Peer object will be deallocated as per
* Host::recv's rules.
*/
void disconnect(uint32 data = 0);
std::string peerHost();
std::string peerIP();
Port peerPort();
};
class Host {
private:
std::vector<Peer*> m_peersToDelete;
void processPeersToDelete();
void *host;
uint64 rxBytes, txBytes;
@ -187,17 +209,27 @@ private:
Host& operator=(Host&) = delete;
Host& operator=(const Host&) = delete;
void sendKeyExchange(Peer&);
public:
using Timeout = uint32;
public:
Host();
~Host();
void create(Port port = 0, uint maxconn = 64);
Peer connect(const std::string &hostAddr, Port port, Timeout timeout);
Peer& connect(const std::string &hostAddr, Port port, Timeout timeout);
void send(Peer &peer, const OutMessage &msg, Tfer mode = Tfer::Rel, Channels chan = Channels::Base);
bool recv(InMessage &msg, Peer &peer, Timeout timeout);
bool recv(InMessage &msg, Timeout timeout = 0);
// Returns true if a message is available, and put it in msg.
// msg may be modified even if recv returns false.
// If the msg is a NetDisconnect, returned peer object is put on a deletion list and will be
// freed upon the next call to recv.
bool recv(InMessage &msg, Peer **peer, Timeout timeout);
inline bool recv(InMessage &msg, Timeout timeout) {
return recv(msg, nullptr, timeout);
}
inline uint64 getRxBytes() const {
return rxBytes;

View File

@ -0,0 +1,19 @@
#include "ConnectionParam.hpp"
namespace Diggler {
namespace Net {
namespace MsgTypes {
void ConnectionParamDHKeyExchange::writeToMsg(OutMessage &msg) const {
msg.setType(MessageType::ConnectionParam, ConnectionParamSubtype::DHKeyExchange);
msg.writeData(reinterpret_cast<const char*>(&pk.bytes), pk.Length);
}
void ConnectionParamDHKeyExchange::readFromMsg(InMessage &msg) {
msg.readData(&pk.bytes, pk.Length);
}
}
}
}

View File

@ -0,0 +1,27 @@
#ifndef DIGGLER_NET_MSGTYPES_CONNECTIONPARAM_HPP
#define DIGGLER_NET_MSGTYPES_CONNECTIONPARAM_HPP
#include "MsgType.hpp"
#include "../../crypto/DiffieHellman.hpp"
namespace Diggler {
namespace Net {
namespace MsgTypes {
enum class ConnectionParamSubtype : uint8 {
DHKeyExchange
};
struct ConnectionParamDHKeyExchange : public MsgType {
Crypto::DiffieHellman::PublicKey pk;
void writeToMsg(OutMessage&) const override;
void readFromMsg(InMessage&) override;
};
}
}
}
#endif /* DIGGLER_NET_MSGTYPES_CONNECTIONPARAM_HPP */

View File

@ -0,0 +1,12 @@
#ifndef DIGGLER_PLATFORM_PREPROC_UTILS_HPP
#define DIGGLER_PLATFORM_PREPROC_UTILS_HPP
#define nocopy(c) c(const c&)=delete;c& operator=(const c&)=delete
#define nomove(c) c(c&&)=delete;c& operator=(c&&)=delete
#define nocopymove(c) nocopy(c);nomove(c)
#define defaultcopy(c) c(const c&)=default;c& operator=(const c&)=default
#define defaultmove(c) c(c&&)=default;c& operator=(c&&)=default
#define defaultcopymove(c) defaultcopy(c);defaultmove(c)
#endif /* DIGGLER_PLATFORM_PREPROC_UTILS_HPP */

View File

@ -1,18 +1,21 @@
#ifndef DIGGLER_PLATFORM_TYPES_HPP
#define DIGGLER_PLATFORM_TYPES_HPP
#include <cstdint>
#include <string>
namespace Diggler {
using int32 = int32_t;
using uint = uint32_t;
using uint32 = uint32_t;
using uint64 = uint64_t;
using uint16 = uint16_t;
using uint8 = uint8_t;
using int64 = int64_t;
using int16 = int16_t;
using int8 = int8_t;
using byte = uint8_t;
using uint = std::uint32_t;
using uint32 = std::uint32_t;
using uint64 = std::uint64_t;
using uint16 = std::uint16_t;
using uint8 = std::uint8_t;
using int64 = std::int64_t;
using int32 = std::int32_t;
using int16 = std::int16_t;
using int8 = std::int8_t;
using byte = std::uint8_t;
using char32 = char32_t;
using char16 = char16_t;

View File

@ -21,8 +21,10 @@ protected:
public:
virtual ~Renderer() = 0;
ParticlesRenderer *PR;
WorldRenderer *WR;
struct Renderers {
ParticlesRenderer *particles;
WorldRenderer *world;
} renderers;
};
inline Renderer::~Renderer() {}

View File

@ -1,5 +1,6 @@
#include "FBO.hpp"
#include "FeatureSupport.hpp"
#include "Util.hpp"
#ifdef IN_IDE_PARSER
@ -32,13 +33,25 @@ FBO::FBO(int w, int h, Texture::PixelFormat format, bool stencil) : m_hasStencil
// Set up renderbuffer to which depth/stencil will be written to
glGenRenderbuffers(1, &rboId);
glBindRenderbuffer(GL_RENDERBUFFER, rboId);
if (stencil)
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, w, h);
else
if (stencil) {
glRenderbufferStorage(GL_RENDERBUFFER, FeatureSupport::FBO_ARB ? GL_DEPTH24_STENCIL8 :
GL_DEPTH24_STENCIL8_OES, w, h);
} else {
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, w, h);
}
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *tex, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, stencil ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboId);
if (stencil) {
if (FeatureSupport::FBO_ARB) {
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
rboId);
} else {
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboId);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rboId);
}
} else {
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboId);
}
glCheck();
}

View File

@ -1,5 +1,7 @@
#include "FeatureSupport.hpp"
#include <sstream>
namespace Diggler {
namespace Render {
namespace gl {
@ -11,17 +13,32 @@ bool
F::DSA_ARB,
F::DSA_EXT,
F::DSA,
F::shader_image_load_store;
F::shader_image_load_store,
F::FBO_ARB;
void F::probe() {
VAO = epoxy_has_gl_extension("GL_ARB_vertex_array_object") or
epoxy_has_gl_extension("GL_OES_vertex_array_object");
DSA_ARB = epoxy_has_gl_extension("ARB_direct_state_access");
DSA_EXT = epoxy_has_gl_extension("EXT_direct_state_access");
DSA_ARB = epoxy_has_gl_extension("GL_ARB_direct_state_access");
DSA_EXT = epoxy_has_gl_extension("GL_EXT_direct_state_access");
DSA = DSA_ARB or DSA_EXT;
shader_image_load_store = epoxy_has_gl_extension("ARB_shader_image_load_store");
shader_image_load_store = epoxy_has_gl_extension("GL_ARB_shader_image_load_store");
FBO_ARB = epoxy_has_gl_extension("GL_ARB_framebuffer_object");
}
#define feature(x) if(x){oss<<#x<<std::endl;}
std::string F::supported() {
std::ostringstream oss;
feature(VAO);
feature(DSA_ARB);
feature(DSA_EXT);
feature(DSA);
feature(shader_image_load_store);
feature(FBO_ARB);
return oss.str();
}
#undef feature
}
}
}

View File

@ -18,9 +18,11 @@ public:
DSA_ARB /* Direct State Access, ARB version */,
DSA_EXT /* Direct State Access, EXT version */,
DSA /* Direct State Access, one or move of above */,
shader_image_load_store;
shader_image_load_store,
FBO_ARB /* FrameBuffer Obects, ARB version */;
static void probe();
static std::string supported();
};
}

View File

@ -16,8 +16,9 @@ public:
GLRenderer(Game *G) :
Renderer(G) {
FeatureSupport::probe();
PR = new GLParticlesRenderer(G);
WR = new GLWorldRenderer(G);
getDebugStream() << "GLRenderer, using features: " << FeatureSupport::supported() << std::endl;
renderers.particles = new GLParticlesRenderer(G);
renderers.world = new GLWorldRenderer(G);
}
};

View File

@ -25,7 +25,11 @@ public:
m_id(0),
m_size(0),
m_usage(GL_STATIC_DRAW) {
glGenBuffers(1, &m_id);
if (FeatureSupport::DSA_ARB) {
glCreateBuffers(1, &m_id);
} else {
glGenBuffers(1, &m_id);
}
}
~VBO() {

View File

@ -64,7 +64,7 @@ Font::Font(Game *G, const std::string& path) : G(G) {
}
}
struct Vertex { int x, y; float tx, ty; float r, g, b ,a; };
struct Vertex { int16 x, y; float tx, ty; float r, g, b ,a; };
#define eraseCurChar() elements -= 6;
@ -121,16 +121,16 @@ int Font::updateVBO(Render::gl::VBO &vbo, const std::string &text, GLenum usage)
return elements;
}
void Font::draw(const Render::gl::VBO &vbo, int count, const glm::mat4& matrix) const {
void Font::draw(const Render::gl::VBO &vbo, int count, const glm::mat4 &matrix) const {
R.prog->bind();
glEnableVertexAttribArray(R.att_coord);
glEnableVertexAttribArray(R.att_texcoord);
glEnableVertexAttribArray(R.att_color);
R.prog->bind();
m_texture->bind();
vbo.bind();
glUniformMatrix4fv(R.uni_mvp, 1, GL_FALSE, glm::value_ptr(matrix));
glVertexAttribPointer(R.att_coord, 2, GL_INT, GL_FALSE, sizeof(Vertex), 0);
glVertexAttribPointer(R.att_coord, 2, GL_SHORT, GL_FALSE, sizeof(Vertex), 0);
glVertexAttribPointer(R.att_texcoord, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, tx));
glVertexAttribPointer(R.att_color, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, r));
glDrawArrays(GL_TRIANGLES, 0, count);