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 .kdev4
assets-orig assets-orig
build build
build-*
*.fossil *.fossil
*.project *.project
*.kdev4 *.kdev4
*.user
TODO.txt TODO.txt
diggler.cfg diggler.cfg
.kdev_include_paths .kdev_include_paths
_*

3
.gitmodules vendored
View File

@ -10,3 +10,6 @@
[submodule "ext/StackTracePlus"] [submodule "ext/StackTracePlus"]
path = ext/StackTracePlus path = ext/StackTracePlus
url = https://github.com/ignacio/StackTracePlus.git 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) 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 ### 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}) file(RELATIVE_PATH REL_BUILD_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${PROJECT_BINARY_DIR})
string(FIND "${REL_BUILD_PATH}" ".." RBP_2DOTPOS) string(FIND "${REL_BUILD_PATH}" ".." RBP_2DOTPOS)
@ -43,13 +59,13 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
find_package(CXX14) find_package(CXX14)
if (NOT CXX14_FOUND) if (NOT CXX14_FOUND)
message(FATAL_ERROR "C++14 feature support unavailable. message(FATAL_ERROR "C++14 feature support unavailable.\
Please use the latest version of your compiler. Please use the latest version of your compiler.\
\
Here are the minimum requirements: Here are the minimum requirements:\
- GCC version 5 (on Debian Jessie, enable Stretch/testing repos and get GCC from there) - GCC version 5 (on Debian Jessie, enable Stretch/testing repos and get GCC from there)\
- clang version 3.4 - clang version 3.4\
- MSVC: wait until Microsoft goes bankrupt, and use another compiler in the meantime - 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") - ICC: ICC 17.0 Beta doesn't yet support all required C++14 features")
endif() endif()
set(CMAKE_CXX_FLAGS "${CXX14_FLAGS} ${CMAKE_CXX_FLAGS}") set(CMAKE_CXX_FLAGS "${CXX14_FLAGS} ${CMAKE_CXX_FLAGS}")
@ -71,6 +87,8 @@ endif()
pkg_search_module(EPOXY REQUIRED epoxy) pkg_search_module(EPOXY REQUIRED epoxy)
pkg_search_module(GLFW REQUIRED glfw3) pkg_search_module(GLFW REQUIRED glfw3)
pkg_search_module(SQLITE3 REQUIRED sqlite3)
pkg_search_module(LIBSODIUM REQUIRED libsodium)
include_directories( include_directories(
${ETC_INCLUDE_DIRS} ${ETC_INCLUDE_DIRS}
${LUA_INCLUDE_DIR} ${LUA_INCLUDE_DIR}
@ -78,6 +96,8 @@ include_directories(
${ENET_INCLUDE_DIRS} ${ENET_INCLUDE_DIRS}
${EPOXY_INCLUDE_DIRS} ${EPOXY_INCLUDE_DIRS}
${GLFW_INCLUDE_DIRS} ${GLFW_INCLUDE_DIRS}
${LIBSODIUM_INCLUDE_DIRS}
${SQLITE3_INCLUDE_DIRS}
${OPENAL_INCLUDE_DIR} ${OPENAL_INCLUDE_DIR}
${MSGPACK_INCLUDE_DIR} ${MSGPACK_INCLUDE_DIR}
) )
@ -94,6 +114,8 @@ target_link_libraries(diggler
${ENET_LIBRARIES} ${ENET_LIBRARIES}
${EPOXY_LIBRARIES} ${EPOXY_LIBRARIES}
${GLFW_LIBRARIES} ${GLFW_LIBRARIES}
${LIBSODIUM_LIBRARIES}
${SQLITE3_LIBRARIES}
${OPENAL_LIBRARY} ${OPENAL_LIBRARY}
pthread) 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` 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` 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) include(FindPackageHandleStandardArgs)
set(CXX14_FLAG_CANDIDATES set(CXX14_FLAG_CANDIDATES
#Gnu and Intel Linux # GCC 6+ and everything that automatically accepts C++14
"-std=c++14"
#Microsoft Visual Studio, and everything that automatically accepts C++14
" " " "
#Intel windows # GCC < 6 and Intel Linux
"-std=c++14"
# Intel Windows
"/Qstd=c++14" "/Qstd=c++14"
) )
@ -24,6 +24,9 @@ set(CXX14_TEST_SOURCE
" "
[[deprecated]] void unused() {} [[deprecated]] void unused() {}
template<typename T>
constexpr T pi = T(3.1415926535897932385);
constexpr int numberwang(int n) { constexpr int numberwang(int n) {
if (n < 0) { if (n < 0) {
return 0b1'1001'0101; return 0b1'1001'0101;
@ -31,7 +34,7 @@ constexpr int numberwang(int n) {
return n - 1; 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) { auto square(int n) {
return lambda(n, n) * numberwang(2); return lambda(n, n) * numberwang(2);
@ -39,6 +42,7 @@ auto square(int n) {
int main() { int main() {
int s = square(3); int s = square(3);
double pie = pi<double>;
return 0; return 0;
} }
") ")
@ -47,7 +51,7 @@ foreach(FLAG ${CXX14_FLAG_CANDIDATES})
set(SAFE_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") set(SAFE_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
set(CMAKE_REQUIRED_FLAGS "${FLAG}") set(CMAKE_REQUIRED_FLAGS "${FLAG}")
unset(CXX14_FLAG_DETECTED CACHE) 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) check_cxx_source_compiles("${CXX14_TEST_SOURCE}" CXX14_FLAG_DETECTED)
set(CMAKE_REQUIRED_FLAGS "${SAFE_CMAKE_REQUIRED_FLAGS}") set(CMAKE_REQUIRED_FLAGS "${SAFE_CMAKE_REQUIRED_FLAGS}")
if(CXX14_FLAG_DETECTED) if(CXX14_FLAG_DETECTED)

1
ext/Optional Submodule

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,8 @@
#include "Game.hpp" #include "Game.hpp"
#include "Audio.hpp" #include "Audio.hpp"
#include "content/AssetManager.hpp"
#include "content/ModManager.hpp"
#include "content/Registry.hpp" #include "content/Registry.hpp"
#include "GlobalProperties.hpp" #include "GlobalProperties.hpp"
#include "KeyBinds.hpp" #include "KeyBinds.hpp"
@ -20,42 +22,67 @@ Game::Game() :
void Game::init() { void Game::init() {
CR = new Content::Registry; CR = new Content::Registry;
AM = std::make_unique<Content::AssetManager>(this);
MM = std::make_unique<Content::ModManager>(this);
LS = new Scripting::Lua::State(this); LS = new Scripting::Lua::State(this);
if (GlobalProperties::IsClient) { if (GlobalProperties::IsClient) {
PM = new ProgramManager(*this); initClient();
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;
} }
if (GlobalProperties::IsServer) { if (GlobalProperties::IsServer) {
initServer();
} }
} }
Game::~Game() { void Game::initClient() {
delete CR; 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) { if (GlobalProperties::IsClient) {
delete KB; finalizeClient();
delete A;
delete R;
delete RP;
delete LP;
delete PM;
} }
if (GlobalProperties::IsServer) { 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) { void Game::updateTime(double time) {
Time = time; Time = time;
TimeMs = (int64)(time * 1000); TimeMs = static_cast<int64>(time * 1000);
} }
} }

View File

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

View File

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

View File

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

View File

@ -116,7 +116,7 @@ GameWindow::GameWindow(Game *G) : G(G) {
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); 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_SAMPLES, 0); // Gimme aliasing everywhere
//glfwWindowHint(GLFW_STENCIL_BITS, 8); //glfwWindowHint(GLFW_STENCIL_BITS, 8);
@ -190,6 +190,8 @@ GameWindow::GameWindow(Game *G) : G(G) {
} }
GameWindow::~GameWindow() { GameWindow::~GameWindow() {
m_currentState.reset();
m_nextState.reset();
delete UIM; delete UIM;
glfwDestroyWindow(m_window); glfwDestroyWindow(m_window);
@ -243,13 +245,13 @@ void GameWindow::cbResize(int w, int h) {
m_currentState->onResize(w, h); m_currentState->onResize(w, h);
} }
void GameWindow::setNextState(const shared_ptr<State> next) { void GameWindow::setNextState(std::unique_ptr<State> &&next) {
m_nextState = next; m_nextState = std::move(next);
} }
void GameWindow::run() { void GameWindow::run() {
while (m_nextState != nullptr && !glfwWindowShouldClose(m_window)) { while (m_nextState != nullptr && !glfwWindowShouldClose(m_window)) {
m_currentState = m_nextState; m_currentState = std::move(m_nextState);
m_nextState = nullptr; m_nextState = nullptr;
UIM->clear(); UIM->clear();
m_currentState->run(); m_currentState->run();
@ -257,7 +259,7 @@ void GameWindow::run() {
} }
void GameWindow::showMessage(const std::string &msg, const std::string &submsg) { 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 "Platform.hpp"
#include "ui/Manager.hpp" #include "ui/Manager.hpp"
using std::shared_ptr;
namespace Diggler { namespace Diggler {
class Game; class Game;
@ -22,7 +20,7 @@ private:
GLFWwindow *m_window; GLFWwindow *m_window;
int m_w, m_h; int m_w, m_h;
shared_ptr<State> m_currentState, m_nextState; std::unique_ptr<State> m_currentState, m_nextState;
public: public:
UI::Manager *UIM; UI::Manager *UIM;
@ -52,7 +50,7 @@ public:
void updateViewport(); void updateViewport();
void setNextState(const shared_ptr<State> next); void setNextState(std::unique_ptr<State> &&next);
void run(); void run();
void showMessage(const std::string &msg, const std::string &submsg = ""); void showMessage(const std::string &msg, const std::string &submsg = "");

View File

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

View File

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

View File

@ -8,11 +8,14 @@
namespace Diggler { namespace Diggler {
Player::Renderer Player::R = {0}; Player::Renderer Player::R = {};
Player::Player(Game *G) : Player::Player(Game *G) :
G(G), position(0), velocity(0), accel(0), angle(0), toolUseTime(0), G(G),
isAlive(true) { angle(0),
toolUseTime(0),
isAlive(true),
peer(nullptr) {
if (GlobalProperties::IsClient) { if (GlobalProperties::IsClient) {
if (R.prog == nullptr) { if (R.prog == nullptr) {
R.prog = G->PM->getProgram(PM_3D | PM_FOG); R.prog = G->PM->getProgram(PM_3D | PM_FOG);
@ -31,34 +34,12 @@ Player::Player(Game *G) :
-sz, .0f, 0.0f, -sz, .0f, 0.0f,
sz, szH, 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); 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) { void Player::setPosVel(const glm::vec3 &pos, const glm::vec3 &vel, const glm::vec3 &acc) {
lastPosition = m_predictPos; lastPosition = m_predictPos;
position = m_predictPos = pos; position = m_predictPos = pos;

View File

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

View File

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

View File

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

View File

@ -50,7 +50,7 @@ public:
bool isPlayerOnline(const std::string &playername) const; bool isPlayerOnline(const std::string &playername) const;
bool isIPOnline(const std::string &ip) const; bool isIPOnline(const std::string &ip) const;
Player* getPlayerById(uint32 id); Player* getPlayerBySessId(uint32 id);
Player* getPlayerByPeer(const Net::Peer &peer); Player* getPlayerByPeer(const Net::Peer &peer);
Player* getPlayerByName(const std::string &name); Player* getPlayerByName(const std::string &name);
void kick(Player &p, Net::QuitReason r = Net::QuitReason::Kicked, const std::string& message = ""); 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) { static GLenum getWrapGlConstant(Texture::Wrapping wrap) {
switch (wrap) { switch (wrap) {
case Texture::Wrapping::Clamp: case Texture::Wrapping::ClampEdge:
return GL_CLAMP; return GL_CLAMP_TO_EDGE;
case Texture::Wrapping::ClampBorder:
return GL_CLAMP_TO_BORDER;
case Texture::Wrapping::Repeat: case Texture::Wrapping::Repeat:
return GL_REPEAT; return GL_REPEAT;
case Texture::Wrapping::MirroredRepeat:
return GL_MIRRORED_REPEAT;
} }
return 0; return 0;
} }

View File

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

View File

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

View File

@ -1,5 +1,6 @@
#ifndef WORLD_GENERATOR_HPP #ifndef DIGGLER_WORLD_GENERATOR_HPP
#define WORLD_GENERATOR_HPP #define DIGGLER_WORLD_GENERATOR_HPP
#include <glm/vec3.hpp> #include <glm/vec3.hpp>
namespace Diggler { 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));/*/ /*/GW.setNextState(std::make_shared<UITestState>(&GW));/*/
if (networkSuccess) if (networkSuccess)
GW.setNextState(std::make_shared<GameState>(&GW, host, port)); GW.setNextState(std::move(std::make_unique<GameState>(&GW, host, port)));
else else
GW.showMessage("Network init failed!"); GW.showMessage("Network init failed!");
/**/ /**/
GW.run(); GW.run();
G->finalizeClient();
} }
G.reset(); G.reset();
} }

View File

@ -6,6 +6,7 @@
#include "msgtypes/BlockUpdate.hpp" #include "msgtypes/BlockUpdate.hpp"
#include "msgtypes/Chat.hpp" #include "msgtypes/Chat.hpp"
#include "msgtypes/ChunkTransfer.hpp" #include "msgtypes/ChunkTransfer.hpp"
#include "msgtypes/PlayerUpdate.hpp"
namespace Diggler { namespace Diggler {
namespace Net { namespace Net {
@ -65,7 +66,7 @@ bool ClientMessageHandler::handleMessage(InMessage &msg) {
if (cpt.msg.type == msgpack::type::STR) { if (cpt.msg.type == msgpack::type::STR) {
std::string playerName; std::string playerName;
if (cpt.player.display.type == msgpack::type::NIL) { 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) { if (blabbermouth != nullptr) {
playerName = blabbermouth->name + "> "; playerName = blabbermouth->name + "> ";
} else { } else {
@ -81,14 +82,14 @@ bool ClientMessageHandler::handleMessage(InMessage &msg) {
} break; } break;
case MessageType::PlayerJoin: { case MessageType::PlayerJoin: {
Player &plr = GS.G->players.add(); Player &plr = GS.G->players.add();
plr.id = msg.readU32(); plr.sessId = msg.readU32();
plr.name = msg.readString(); 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; } break;
case MessageType::PlayerQuit: { case MessageType::PlayerQuit: {
uint32 id = msg.readU32(); uint32 id = msg.readU32();
try { try {
Player *plr = GS.G->players.getByGameId(id); Player *plr = GS.G->players.getBySessId(id);
if (plr != nullptr) { if (plr != nullptr) {
getOutputStream() << plr->name << " is gone :(" << std::endl; getOutputStream() << plr->name << " is gone :(" << std::endl;
GS.G->players.remove(*plr); GS.G->players.remove(*plr);
@ -98,30 +99,51 @@ bool ClientMessageHandler::handleMessage(InMessage &msg) {
} }
} break; } break;
case MessageType::PlayerUpdate: { case MessageType::PlayerUpdate: {
uint32 id = msg.readU32(); using S = PlayerUpdateSubtype;
try { switch (static_cast<S>(msg.getSubtype())) {
Player *plr = GS.G->players.getByGameId(id); case S::Move: {
if (plr != nullptr) { PlayerUpdateMove pum;
switch (msg.getSubtype()) { pum.readFromMsg(msg);
case PlayerUpdateType::Move: { if (!pum.plrSessId) {
glm::vec3 pos = msg.readVec3(), getOutputStream() << "PlayerUpdateMove without player session ID" << std::endl;
vel = msg.readVec3(), return true;
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;
} }
} Player *plr = GS.G->players.getBySessId(*pum.plrSessId);
} catch (const std::out_of_range &e) { if (!plr) {
getOutputStream() << "Invalid player update: #" << id << " is not on server" << std::endl; 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; } break;
case MessageType::BlockUpdate: { 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) { void Broadcast(Game &G, const OutMessage &msg, Tfer tfer, Channels chan) {
for (Player &p : G.players) { 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; OutMessage msg;
cs.writeToMsg(msg); cs.writeToMsg(msg);
G->H.send(G->NS, msg, Tfer::Unseq); 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);
} }

View File

@ -20,10 +20,8 @@ void MakeEvent(Net::OutMessage&, Net::EventType, const Player&);
void SendEvent(Game*, Net::EventType); void SendEvent(Game*, Net::EventType);
void SendChat(Game*, const std::string&); 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 "Network.hpp"
#include <enet/enet.h>
#include <chrono>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <sstream> #include <sstream>
#include <memory> #include <memory>
#include <enet/enet.h>
#include "../crypto/Random.hpp"
#include "msgtypes/ConnectionParam.hpp"
#include <iomanip> #include <iomanip>
namespace Diggler { namespace Diggler {
@ -53,8 +59,7 @@ Message::Message(MessageType t, uint8 s) :
InMessage::InMessage() : InMessage::InMessage() :
Message(MessageType::Null, 0), Message(MessageType::Null, 0),
m_chan(Channels::Base), m_chan(Channels::Base) {
m_packet(nullptr) {
} }
InMessage::~InMessage() { InMessage::~InMessage() {
@ -79,36 +84,17 @@ void InMessage::fromData(const void *data, SizeT len, Channels chan) {
m_length = len; m_length = len;
m_type = static_cast<MessageType>(bytes[0]); m_type = static_cast<MessageType>(bytes[0]);
m_subtype = bytes[1]; m_subtype = bytes[1];
m_data = static_cast<uint8*>(std::malloc(len-HeaderSize)); // m_data/bytes is guaranteed never to be written to, so we can const_cast it
std::memcpy(m_data, &(bytes[HeaderSize]), len-HeaderSize); m_data = const_cast<uint8*>(bytes) + 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]);
} }
void InMessage::free() { void InMessage::free() {
if (m_packet != nullptr) { if (m_data != nullptr) {
enet_packet_destroy(static_cast<ENetPacket*>(m_packet)); delete[] (m_data - HeaderSize);
} else {
std::free(m_data);
} }
m_type = MessageType::Null; m_type = MessageType::Null;
m_subtype = m_length = m_cursor = 0; 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; 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 { bool Peer::operator==(const Peer &other) const {
return peer == other.peer; return peer == other.peer;
} }
@ -168,13 +162,13 @@ bool Peer::operator!=(const Peer &other) const {
return !(*this == other); return !(*this == other);
} }
void Peer::disconnect() { void Peer::disconnect(uint32 data) {
ENetPeer *const peer = static_cast<ENetPeer*>(this->peer); ENetPeer *const peer = reinterpret_cast<ENetPeer*>(this->peer);
enet_peer_disconnect(peer, 0); enet_peer_disconnect(peer, data);
} }
std::string Peer::getHost() { std::string Peer::peerHost() {
const ENetPeer *const peer = static_cast<const ENetPeer*>(this->peer); const ENetPeer *const peer = reinterpret_cast<const ENetPeer*>(this->peer);
std::ostringstream oss; std::ostringstream oss;
char *chars = new char[512]; char *chars = new char[512];
enet_address_get_host_ip(&peer->host->address, chars, 512); enet_address_get_host_ip(&peer->host->address, chars, 512);
@ -184,8 +178,8 @@ std::string Peer::getHost() {
return oss.str(); return oss.str();
} }
std::string Peer::getIp() { std::string Peer::peerIP() {
const ENetPeer *const peer = static_cast<const ENetPeer*>(this->peer); const ENetPeer *const peer = reinterpret_cast<const ENetPeer*>(this->peer);
char *chars = new char[512]; char *chars = new char[512];
enet_address_get_host_ip(&peer->host->address, chars, 512); enet_address_get_host_ip(&peer->host->address, chars, 512);
std::string str(chars); std::string str(chars);
@ -193,8 +187,8 @@ std::string Peer::getIp() {
return str; return str;
} }
Port Peer::getPort() { Port Peer::peerPort() {
const ENetPeer *const peer = static_cast<const ENetPeer*>(this->peer); const ENetPeer *const peer = reinterpret_cast<const ENetPeer*>(this->peer);
return peer->host->address.port; return peer->host->address.port;
} }
@ -206,6 +200,11 @@ Host::Host() :
txBytes(0) { txBytes(0) {
} }
Host::~Host() {
ENetHost *const host = reinterpret_cast<ENetHost*>(this->host);
enet_host_destroy(host);
}
void Host::create(Port port, uint maxconn) { void Host::create(Port port, uint maxconn) {
if (port == 0) { // Client if (port == 0) { // Client
host = enet_host_create(nullptr, 1, static_cast<size_t>(Channels::MAX), 0, 0); 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) { Peer& Host::connect(const std::string &hostAddr, Port port, Timeout timeout) {
ENetHost *const host = static_cast<ENetHost*>(this->host); ENetHost *const host = reinterpret_cast<ENetHost*>(this->host);
ENetAddress address; ENetAddress address;
ENetEvent event; ENetEvent event;
ENetPeer *peer; 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 && if (enet_host_service(host, &event, timeout) > 0 &&
event.type == ENET_EVENT_TYPE_CONNECT) { event.type == ENET_EVENT_TYPE_CONNECT) {
Peer p; p.peer = peer; Peer *p = new Peer(*this, peer);
return p; sendKeyExchange(*p);
return *p;
} }
enet_peer_reset(peer); enet_peer_reset(peer);
throw Exception(); throw Exception();
} }
Host::~Host() { void Host::processPeersToDelete() {
ENetHost *const host = static_cast<ENetHost*>(this->host); for (Peer *peer : m_peersToDelete) {
enet_host_destroy(host); 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); std::cout << in << ": " << std::setiosflags(std::ios::internal);
for (int i=0; i < len; ++i) { for (int i=0; i < len; ++i) {
std::cout << std::setfill('0') << std::setw(2) << std::hex << (int)buf[i] << ' '; std::cout << std::setfill('0') << std::setw(2) << std::hex << (int)buf[i] << ' ';
} }
std::cout << std::dec << std::endl; 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) { bool Host::recv(InMessage &msg, Peer **peer, Timeout timeout) {
ENetHost *const host = static_cast<ENetHost*>(this->host); ENetHost *const host = reinterpret_cast<ENetHost*>(this->host);
processPeersToDelete();
auto start = std::chrono::steady_clock::now();
ENetEvent event; ENetEvent event;
if (enet_host_service(host, &event, timeout) >= 0){ while (true) {
switch (event.type) { auto now = std::chrono::steady_clock::now();
case ENET_EVENT_TYPE_NONE: 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; 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(); throw Exception();
} }
void Host::send(Peer &peer, const OutMessage &msg, Tfer mode, Channels chan) { 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] = { const byte header[Message::HeaderSize] = {
static_cast<uint8>(msg.m_type), static_cast<byte>(msg.m_type),
msg.m_subtype 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) { if (msg.m_actualData != nullptr) {
std::memcpy(msg.m_actualData, header, Message::HeaderSize); std::memcpy(msg.m_actualData, header, Message::HeaderSize);
packet = enet_packet_create(msg.m_actualData, if (encrypt) {
Message::HeaderSize + msg.m_length, TferToFlags(mode)); // TODO: don't memcpy, encrypt!
txBytes += Message::HeaderSize + msg.m_length; std::memcpy(pktData, msg.m_actualData, pktLen);
} else {
std::memcpy(pktData, msg.m_actualData, pktLen);
}
} else { } else {
packet = enet_packet_create(header, if (encrypt) {
Message::HeaderSize, TferToFlags(mode)); // TODO: don't memcpy, encrypt!
txBytes += Message::HeaderSize; std::memcpy(pktData, header, pktLen);
} else {
std::memcpy(pktData, header, pktLen);
}
} }
//hexDump('S', packet->data, 2+msg.m_length); hexDump('S', pktData, pktLen);
enet_peer_send(static_cast<ENetPeer*>(peer.peer), static_cast<uint8>(chan), packet); enet_peer_send(reinterpret_cast<ENetPeer*>(peer.peer), static_cast<uint8>(chan), packet);
enet_host_flush(host); enet_host_flush(host);
} }

View File

@ -1,10 +1,15 @@
#ifndef NETWORK_HPP #ifndef NETWORK_HPP
#define NETWORK_HPP #define NETWORK_HPP
#include "../Platform.hpp"
#include "../io/MemoryStream.hpp"
#include <glm/vec3.hpp>
#include <exception> #include <exception>
#include <glm/vec3.hpp>
#include "../Platform.hpp"
#include "../platform/PreprocUtils.hpp"
#include "../crypto/DiffieHellman.hpp"
#include "../io/MemoryStream.hpp"
namespace Diggler { namespace Diggler {
namespace Net { namespace Net {
@ -20,6 +25,8 @@ enum class Tfer {
enum class Channels : uint8 { enum class Channels : uint8 {
Base = 0, Base = 0,
ConnectionMeta,
ConnectionMetaPlain,
Chat, Chat,
Life, Life,
Movement, Movement,
@ -35,6 +42,8 @@ enum class MessageType : uint8 {
ServerInfo = 220, ServerInfo = 220,
ConnectionParam = 200,
PlayerJoin = 1, PlayerJoin = 1,
PlayerUpdate, PlayerUpdate,
PlayerQuit, PlayerQuit,
@ -46,16 +55,6 @@ enum class MessageType : uint8 {
NetDisconnect NetDisconnect
}; };
enum PlayerUpdateType : uint8 {
Move,
ChangeTool,
ChangeClass,
ChangeTeam,
Die,
Respawn,
ToolUse
};
enum QuitReason : uint8 { enum QuitReason : uint8 {
Quit, Quit,
Timeout, Timeout,
@ -82,6 +81,8 @@ protected:
public: public:
static constexpr uint HeaderSize = 2; static constexpr uint HeaderSize = 2;
virtual ~Message() {}
inline MessageType getType() const { return m_type; } inline MessageType getType() const { return m_type; }
inline uint8 getSubtype() const { return m_subtype; } inline uint8 getSubtype() const { return m_subtype; }
@ -94,10 +95,8 @@ class InMessage : public Message, public InMemoryStream {
protected: protected:
friend class Host; friend class Host;
Channels m_chan; Channels m_chan;
void *m_packet;
void setType(MessageType type); void setType(MessageType type);
void fromData(const void *data, SizeT len, Channels chan = Channels::Base); void fromData(const void *data, SizeT, Channels);
void fromPacket(void *packet, Channels chan = Channels::Base);
void free(); void free();
public: public:
@ -166,20 +165,43 @@ class Exception : public std::exception {
using Port = uint16; using Port = uint16;
class Host;
struct Peer { 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;
bool operator!=(const Peer&) const; bool operator!=(const Peer&) const;
void disconnect(); /**
std::string getHost(); * @brief Disconnects the peer.
std::string getIp(); * @param data
Port getPort(); * 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 { class Host {
private: private:
std::vector<Peer*> m_peersToDelete;
void processPeersToDelete();
void *host; void *host;
uint64 rxBytes, txBytes; uint64 rxBytes, txBytes;
@ -187,17 +209,27 @@ private:
Host& operator=(Host&) = delete; Host& operator=(Host&) = delete;
Host& operator=(const Host&) = delete; Host& operator=(const Host&) = delete;
void sendKeyExchange(Peer&);
public: public:
using Timeout = uint32; using Timeout = uint32;
public:
Host(); Host();
~Host(); ~Host();
void create(Port port = 0, uint maxconn = 64); 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); 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 { inline uint64 getRxBytes() const {
return rxBytes; 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 #ifndef DIGGLER_PLATFORM_TYPES_HPP
#define DIGGLER_PLATFORM_TYPES_HPP #define DIGGLER_PLATFORM_TYPES_HPP
#include <cstdint>
#include <string>
namespace Diggler { namespace Diggler {
using int32 = int32_t; using uint = std::uint32_t;
using uint = uint32_t; using uint32 = std::uint32_t;
using uint32 = uint32_t; using uint64 = std::uint64_t;
using uint64 = uint64_t; using uint16 = std::uint16_t;
using uint16 = uint16_t; using uint8 = std::uint8_t;
using uint8 = uint8_t; using int64 = std::int64_t;
using int64 = int64_t; using int32 = std::int32_t;
using int16 = int16_t; using int16 = std::int16_t;
using int8 = int8_t; using int8 = std::int8_t;
using byte = uint8_t; using byte = std::uint8_t;
using char32 = char32_t; using char32 = char32_t;
using char16 = char16_t; using char16 = char16_t;

View File

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

View File

@ -1,5 +1,6 @@
#include "FBO.hpp" #include "FBO.hpp"
#include "FeatureSupport.hpp"
#include "Util.hpp" #include "Util.hpp"
#ifdef IN_IDE_PARSER #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 // Set up renderbuffer to which depth/stencil will be written to
glGenRenderbuffers(1, &rboId); glGenRenderbuffers(1, &rboId);
glBindRenderbuffer(GL_RENDERBUFFER, rboId); glBindRenderbuffer(GL_RENDERBUFFER, rboId);
if (stencil) if (stencil) {
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, w, h); glRenderbufferStorage(GL_RENDERBUFFER, FeatureSupport::FBO_ARB ? GL_DEPTH24_STENCIL8 :
else GL_DEPTH24_STENCIL8_OES, w, h);
} else {
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, w, h); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, w, h);
}
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *tex, 0); 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(); glCheck();
} }

View File

@ -1,5 +1,7 @@
#include "FeatureSupport.hpp" #include "FeatureSupport.hpp"
#include <sstream>
namespace Diggler { namespace Diggler {
namespace Render { namespace Render {
namespace gl { namespace gl {
@ -11,17 +13,32 @@ bool
F::DSA_ARB, F::DSA_ARB,
F::DSA_EXT, F::DSA_EXT,
F::DSA, F::DSA,
F::shader_image_load_store; F::shader_image_load_store,
F::FBO_ARB;
void F::probe() { void F::probe() {
VAO = epoxy_has_gl_extension("GL_ARB_vertex_array_object") or VAO = epoxy_has_gl_extension("GL_ARB_vertex_array_object") or
epoxy_has_gl_extension("GL_OES_vertex_array_object"); epoxy_has_gl_extension("GL_OES_vertex_array_object");
DSA_ARB = epoxy_has_gl_extension("ARB_direct_state_access"); DSA_ARB = epoxy_has_gl_extension("GL_ARB_direct_state_access");
DSA_EXT = epoxy_has_gl_extension("EXT_direct_state_access"); DSA_EXT = epoxy_has_gl_extension("GL_EXT_direct_state_access");
DSA = DSA_ARB or DSA_EXT; 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_ARB /* Direct State Access, ARB version */,
DSA_EXT /* Direct State Access, EXT version */, DSA_EXT /* Direct State Access, EXT version */,
DSA /* Direct State Access, one or move of above */, 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 void probe();
static std::string supported();
}; };
} }

View File

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

View File

@ -25,7 +25,11 @@ public:
m_id(0), m_id(0),
m_size(0), m_size(0),
m_usage(GL_STATIC_DRAW) { m_usage(GL_STATIC_DRAW) {
glGenBuffers(1, &m_id); if (FeatureSupport::DSA_ARB) {
glCreateBuffers(1, &m_id);
} else {
glGenBuffers(1, &m_id);
}
} }
~VBO() { ~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; #define eraseCurChar() elements -= 6;
@ -121,16 +121,16 @@ int Font::updateVBO(Render::gl::VBO &vbo, const std::string &text, GLenum usage)
return elements; 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_coord);
glEnableVertexAttribArray(R.att_texcoord); glEnableVertexAttribArray(R.att_texcoord);
glEnableVertexAttribArray(R.att_color); glEnableVertexAttribArray(R.att_color);
R.prog->bind();
m_texture->bind(); m_texture->bind();
vbo.bind(); vbo.bind();
glUniformMatrix4fv(R.uni_mvp, 1, GL_FALSE, glm::value_ptr(matrix)); 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_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)); glVertexAttribPointer(R.att_color, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, r));
glDrawArrays(GL_TRIANGLES, 0, count); glDrawArrays(GL_TRIANGLES, 0, count);