diff --git a/.gitmodules b/.gitmodules index 448ee53..14d6f25 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,9 +7,6 @@ [submodule "ext/enet"] path = ext/enet url = https://github.com/freeminer/enet.git -[submodule "ext/goodform"] - path = ext/goodform - url = https://github.com/ElementW/goodform.git [submodule "ext/torch7"] path = ext/torch7 url = https://github.com/torch/torch7.git @@ -25,3 +22,6 @@ [submodule "assets/lua/modules/lds"] path = assets/lua/modules/lds url = https://github.com/neomantra/lds.git +[submodule "ext/meiose"] + path = ext/meiose + url = https://github.com/ElementW/meiose.git diff --git a/CMakeLists.txt b/CMakeLists.txt index d3be058..2c25f81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,6 +69,12 @@ find_package(OpenGL REQUIRED) find_package(PkgConfig REQUIRED) find_package(LuaJIT REQUIRED) +find_package(meiose REQUIRED) +if(NOT MPACK_FOUND) + message(FATAL_ERROR "Bundled meiose not found. Have you checked out submodules? +git submodule update --init") +endif() + find_package(Optional REQUIRED) pkg_search_module(GLFW REQUIRED glfw3) @@ -77,6 +83,7 @@ pkg_search_module(LIBSODIUM REQUIRED libsodium) include_directories(BEFORE "${CMAKE_CURRENT_SOURCE_DIR}/include" ${ETC_INCLUDE_DIRS} + ${MEIOSE_INCLUDE_DIR} ${LUA_INCLUDE_DIR} ${LZFX_INCLUDE_DIRS} ${ENET_INCLUDE_DIRS} @@ -87,10 +94,6 @@ include_directories(BEFORE ${OPTIONAL_INCLUDE_DIR} ) -# Glob all source files so they show up in Qt Creator -#file(GLOB_RECURSE FILELIST "*.h" "*.hpp" "*.cpp") -#add_custom_target(files SOURCES ${FILELIST}) - ### Allow subdirs to add params to the `diggler` target # Sources set_property(GLOBAL PROPERTY DIGGLER_SOURCE_FILES "") @@ -146,6 +149,7 @@ get_property(LIBS GLOBAL PROPERTY DIGGLER_LINK_LIBRARIES) target_link_libraries(diggler ${LIBS} ${ETC_LIBRARIES} + ${MEIOSE_LIBRARY} ${LUA_LIBRARY} ${LZFX_LIBRARIES} ${ENET_LIBRARIES} diff --git a/cmake/FindJemalloc.cmake b/cmake/FindJemalloc.cmake new file mode 100644 index 0000000..70da50b --- /dev/null +++ b/cmake/FindJemalloc.cmake @@ -0,0 +1,55 @@ +# +# Find the JEMALLOC client includes and library +# + +# This module defines +# JEMALLOC_INCLUDE_DIR, where to find jemalloc.h +# JEMALLOC_LIBRARIES, the libraries to link against +# JEMALLOC_FOUND, if false, you cannot build anything that requires JEMALLOC + +# also defined, but not for general use are +# JEMALLOC_LIBRARY, where to find the JEMALLOC library. + +set( JEMALLOC_FOUND 0 ) + +if ( UNIX ) + FIND_PATH( JEMALLOC_INCLUDE_DIR + NAMES + jemalloc/jemalloc.h + PATHS + /usr/include + /usr/include/jemalloc + /usr/local/include + /usr/local/include/jemalloc + $ENV{JEMALLOC_ROOT} + $ENV{JEMALLOC_ROOT}/include + ${CMAKE_SOURCE_DIR}/externals/jemalloc + DOC + "Specify include-directories that might contain jemalloc.h here." + ) + FIND_LIBRARY( JEMALLOC_LIBRARY + NAMES + jemalloc libjemalloc JEMALLOC + PATHS + /usr/lib + /usr/lib/jemalloc + /usr/local/lib + /usr/local/lib/jemalloc + /usr/local/jemalloc/lib + $ENV{JEMALLOC_ROOT}/lib + $ENV{JEMALLOC_ROOT} + DOC "Specify library-locations that might contain the jemalloc library here." + ) + + if ( JEMALLOC_LIBRARY ) + if ( JEMALLOC_INCLUDE_DIR ) + set( JEMALLOC_FOUND 1 ) + message( STATUS "Found JEMALLOC library: ${JEMALLOC_LIBRARY}") + message( STATUS "Found JEMALLOC headers: ${JEMALLOC_INCLUDE_DIR}") + else ( JEMALLOC_INCLUDE_DIR ) + message(FATAL_ERROR "Could not find jemalloc headers! Please install jemalloc libraries and headers") + endif ( JEMALLOC_INCLUDE_DIR ) + endif ( JEMALLOC_LIBRARY ) + + mark_as_advanced( JEMALLOC_FOUND JEMALLOC_LIBRARY JEMALLOC_EXTRA_LIBRARIES JEMALLOC_INCLUDE_DIR ) +endif (UNIX) \ No newline at end of file diff --git a/cmake/Findmeiose.cmake b/cmake/Findmeiose.cmake new file mode 100644 index 0000000..f15d9ad --- /dev/null +++ b/cmake/Findmeiose.cmake @@ -0,0 +1,17 @@ +set(MEIOSE_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ext/meiose") + +set(MEIOSE_INCLUDE_DIR "${MEIOSE_ROOT_DIR}/include/") +if(NOT EXISTS "${MEIOSE_INCLUDE_DIR}") + unset(MEIOSE_INCLUDE_DIR) +endif() + +add_subdirectory("${MEIOSE_ROOT_DIR}") +target_include_directories(meiose-static PRIVATE "${MPACK_INCLUDE_DIR}") + +set(MEIOSE_LIBRARY "meiose-static") + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(MPACK + REQUIRED_VARS MEIOSE_INCLUDE_DIR MEIOSE_LIBRARY) + +mark_as_advanced(MEIOSE_INCLUDE_DIR MEIOSE_LIBRARY) diff --git a/doc/spec.md b/doc/spec.md index 3977286..dd62cab 100644 --- a/doc/spec.md +++ b/doc/spec.md @@ -374,7 +374,8 @@ struct ServerInfoResponse { The client asks for a list of information, and the server simply replies. Different infos are identified by a short string describing both what it is and optional parameters, separated by dot characters (`.`, U+002E). The server may reply to the client with only some of the requested information, and/or information with different parameters, but is expected to do its best effort to send back the most appropriate information. It is up to the client to choose what to do with this data and put it to best use. -Parameters that expresses languages are substituted by `XXX` in the following table, and are expected to be ISO 639-3 alpha-3-*type* codes. Language codes that are not part of ISO 639-3 are considered **valid** and may very well be used for alternative languages, such as `zls` for 1337$P34|< ([leetspeak](https://en.wikipedia.org/wiki/Leet)). +Parameters that expresses languages are substituted by `XXXX` in the following table, and are expected to be ISO 639-3 alpha-3-*like* codes for "real" languages (which can be fictive and constructed, like Klingon). Language codes that are not part of ISO 639-3 are considered **valid**. +For other languages, a code of the form `!ABC` where `ABC` is the language code. For example, for 1337$P34|< ([leetspeak](https://en.wikipedia.org/wiki/Leet)), the code could be `!lts`. When that language specification is shown between parentheses, it is optional and the server is free to return said information in any language if unspecified, whichever is the most appropriate (e.g. according to the server's homeland or client location guessed from its IP address). Info name | Reply type | Reply data diff --git a/ext/goodform b/ext/goodform deleted file mode 160000 index 0791e58..0000000 --- a/ext/goodform +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0791e58e1bf20f486a14c3a86d5ba2f231bb8b8f diff --git a/ext/lzfx/lzfx.c b/ext/lzfx/lzfx.c index aad6d7c..2be5f7c 100644 --- a/ext/lzfx/lzfx.c +++ b/ext/lzfx/lzfx.c @@ -35,6 +35,8 @@ #define LZFX_HSIZE (1 << (LZFX_HLOG)) +#include + /* We need this for memset */ #ifdef __cplusplus # include @@ -105,7 +107,7 @@ int lzfx_compress(const void *const ibuf, const unsigned int ilen, int lit; /* # of bytes in current literal run */ #if defined (WIN32) && defined (_M_X64) - unsigned _int64 off; /* workaround for missing POSIX compliance */ + uint64_t off; /* workaround for missing POSIX compliance */ #else unsigned long off; #endif diff --git a/ext/meiose b/ext/meiose new file mode 160000 index 0000000..f04d826 --- /dev/null +++ b/ext/meiose @@ -0,0 +1 @@ +Subproject commit f04d826bd236c92c4ae492d2503f250ce9f0323a diff --git a/src/Chunk.hpp b/src/Chunk.hpp index 8152e95..4343027 100644 --- a/src/Chunk.hpp +++ b/src/Chunk.hpp @@ -49,13 +49,18 @@ public: const int wcx, wcy, wcz; + /** + * @brief Struct holding the Chunk's block contents. + * @note This structure must be a Plain Old Data struct. + */ struct Data { static constexpr FourCC MagicMarker = MakeFourCC("CKDT"); - FourCC magic; - // Keep me Plain Old Data! - BlockId id[CX*CY*CZ]; - BlockData data[CX*CY*CZ]; - LightData light[CX*CY*CZ]; + FourCC magic; /**< Magic marker. Used for Chunk eviction checking. */ + + BlockId id[CX*CY*CZ]; /**< Block IDs. */ + BlockData data[CX*CY*CZ]; /**< Block data. */ + LightData light[CX*CY*CZ]; /**< Block light info. */ + void clear(); }; diff --git a/src/ConnectingState.cpp b/src/ConnectingState.cpp index a413096..dd93741 100644 --- a/src/ConnectingState.cpp +++ b/src/ConnectingState.cpp @@ -45,115 +45,116 @@ void ConnectingState::setupUI() { void ConnectingState::updateViewport() { } -void ConnectingState::onResize(int w, int h) { - updateViewport(); -} - -void ConnectingState::run() { - std::string &serverHost = m_serverHost; - int serverPort = m_serverPort; - bool finished = false, success = false; +void ConnectingState::onStart() { + finished = success = false; Game *const G = W->G; - std::string failureStr; - std::thread networkThread = std::thread([G, &success, &finished, &serverHost, serverPort, &failureStr]() { + m_networkThread = std::thread([this, G]() { try { G->H.create(); - G->NS = &G->H.connect(serverHost, serverPort, 5000); + G->NS = &G->H.connect(m_serverHost, m_serverPort, 5000); success = true; } catch (const std::exception &e) { success = false; - failureStr = e.what(); + m_infoStr = e.what(); } finished = true; }); glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); +} + +void ConnectingState::onLogicTick() { + Game *const G = W->G; + G->updateTime(runTime()); + + if (finished) { + if (success) { + LocalPlayer &LP = *G->LP; + LP.name = GlobalProperties::PlayerName; + + Net::MsgTypes::PlayerJoinRequest pjr; + pjr.name = G->LP->name; + Net::OutMessage join; pjr.writeToMsg(join); + G->H.send(*G->NS, join, Net::Tfer::Rel, Net::Channels::Base); + + Net::InMessage m_msg; + bool received = G->H.recv(m_msg, 5000); + if (!received) { + W->showMessage("Connected but got no response", "after 5 seconds"); + return; + } + bool msgGood = false; + if (m_msg.getType() == Net::MessageType::PlayerJoin) { + using PJS = Net::MsgTypes::PlayerJoinSubtype; + switch (m_msg.getSubtype()) { + case PJS::Success: + msgGood = true; + G->U = new Universe(G, true); + LP.sessId = m_msg.readU32(); + LP.W = G->U->createWorld(m_msg.readI16()); + break; + case PJS::Failure: { + // TODO be able to display a custom message + W->showMessage("Disconnected", "while joining"); + } return; + default: + break; + } + } + if (!msgGood) { + std::ostringstream sstm; + sstm << "Type: " << static_cast(m_msg.getType()) << + " Subtype: " << static_cast(m_msg.getSubtype()); + W->showMessage("Received unexpected packet", sstm.str()); + return; + } + + // TODO: move elsewhere + G->LS->initialize(); + const std::string gameLuaRuntimePath(getAssetsDirectory() + "/lua"); + G->LS->setGameLuaRuntimePath(gameLuaRuntimePath); + G->LS->dofile(gameLuaRuntimePath + "/Diggler.lua"); + + Log(Info, TAG) << "Joined as " << LP.name << '/' << LP.sessId; + + W->setNextState(std::make_unique(W)); + } else { + W->showMessage("Could not connect to server", m_infoStr); + } + } +} + +void ConnectingState::onFrameTick() { + Game *const G = W->G; glm::mat4 mat; UI::Text::Size sz = txtConnecting->getSize(); const glm::mat4 textMat = glm::scale(glm::translate(*G->UIM->PM, glm::vec3(W->getW()/2-sz.x, W->getH()/2, 0.f)), glm::vec3(2.f, 2.f, 1.f)); - while (!finished && !W->shouldClose()) { // Infinite loop \o/ - const double T = glfwGetTime(); - G->updateTime(T); - G->R->beginFrame(); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + G->R->beginFrame(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - txtConnecting->render(textMat); - for (int i=0; i < 6; ++i) { - const float t = T * 3 + 0.3f * i; - mat = glm::scale(glm::translate(*G->UIM->PM, - glm::vec3(W->getW()/2 - 1 + std::sin(t)*sz.x, W->getH()/2-sz.y, 0.f)), - glm::vec3(2.f, 2.f, 1.f)); - txtDot->render(mat); - } - - G->R->endFrame(); - - glfwSwapBuffers(*W); - glfwPollEvents(); - } - if (W->shouldClose()) - W->setVisible(false); - networkThread.join(); - - if (W->shouldClose()) - return; - if (!success) { - W->showMessage("Could not connect to server", failureStr); - return; + txtConnecting->render(textMat); + for (int i=0; i < 6; ++i) { + const double t = G->Time * 3 + 0.3 * i; + mat = glm::scale(glm::translate(*G->UIM->PM, + glm::vec3(W->getW()/2 - 1 + std::sin(t)*sz.x, W->getH()/2-sz.y, 0.f)), + glm::vec3(2.f, 2.f, 1.f)); + txtDot->render(mat); } - LocalPlayer &LP = *G->LP; - LP.name = GlobalProperties::PlayerName; + G->R->endFrame(); +} - Net::MsgTypes::PlayerJoinRequest pjr; - pjr.name = G->LP->name; - Net::OutMessage join; pjr.writeToMsg(join); - G->H.send(*G->NS, join, Net::Tfer::Rel, Net::Channels::Base); - - Net::InMessage m_msg; - bool received = G->H.recv(m_msg, 5000); - if (!received) { - W->showMessage("Connected but got no response", "after 5 seconds"); - return; - } - bool msgGood = false; - if (m_msg.getType() == Net::MessageType::PlayerJoin) { - using PJS = Net::MsgTypes::PlayerJoinSubtype; - switch (m_msg.getSubtype()) { - case PJS::Success: - msgGood = true; - G->U = new Universe(G, true); - LP.sessId = m_msg.readU32(); - LP.W = G->U->createWorld(m_msg.readI16()); - break; - case PJS::Failure: { - // TODO be able to display a custom message - W->showMessage("Disconnected", "while joining"); - } return; - default: - break; - } - } - if (!msgGood) { - std::ostringstream sstm; - sstm << "Type: " << static_cast(m_msg.getType()) << - " Subtype: " << static_cast(m_msg.getSubtype()); - W->showMessage("Received unexpected packet", sstm.str()); - return; +void ConnectingState::onStop() { + if (m_networkThread.joinable()) { + m_networkThread.join(); } +} - // TODO: move elsewhere - G->LS->initialize(); - const std::string gameLuaRuntimePath(getAssetsDirectory() + "/lua"); - G->LS->setGameLuaRuntimePath(gameLuaRuntimePath); - G->LS->dofile(gameLuaRuntimePath + "/Diggler.lua"); - - Log(Info, TAG) << "Joined as " << LP.name << '/' << LP.sessId; - - W->setNextState(std::make_unique(W)); +void ConnectingState::onResize(int w, int h) { + updateViewport(); } } diff --git a/src/ConnectingState.hpp b/src/ConnectingState.hpp index 33625f2..30f1145 100644 --- a/src/ConnectingState.hpp +++ b/src/ConnectingState.hpp @@ -1,6 +1,10 @@ #ifndef DIGGLER_CONNECTING_STATE_HPP #define DIGGLER_CONNECTING_STATE_HPP +#include +#include +#include + #include "State.hpp" #include "GameWindow.hpp" #include "ui/Text.hpp" @@ -20,16 +24,24 @@ private: std::string m_serverHost; int m_serverPort; + std::thread m_networkThread; + bool finished, success; + std::string m_infoStr; + void setupUI(); public: ConnectingState(GameWindow *W, const std::string &servHost, int servPort); ~ConnectingState(); + void onStart() override; + void onLogicTick() override; + void onFrameTick() override; + void onStop() override; + //void onMouseButton(int key, int action, int mods); //void onCursorPos(double x, double y); void onResize(int w, int h); - void run(); void updateViewport(); }; diff --git a/src/Frustum.hpp b/src/Frustum.hpp index c2ecd2b..31eccb8 100644 --- a/src/Frustum.hpp +++ b/src/Frustum.hpp @@ -5,6 +5,10 @@ #include "platform/types/vec3.hpp" +// The following, courtesy of the Windows developer experience™ +#undef NEAR +#undef FAR + namespace Diggler { class Frustum { diff --git a/src/GameState.cpp b/src/GameState.cpp index 6c6c8c0..46554ef 100644 --- a/src/GameState.cpp +++ b/src/GameState.cpp @@ -413,13 +413,12 @@ void GameState::sendMsg(Net::OutMessage &msg, Net::Tfer mode, Net::Channels chan G->H.send(*G->NS, msg, mode, chan); } -void GameState::run() { +void GameState::onStart() { setupUI(); - gameLoop(); -} -void GameState::gameLoop() { - double lastT, deltaT, T, fpsT = 0; int frames = 0; + fpsCounter = 0; + fpsNextSampling = 1.; + LocalPlayer *LP = G->LP; LP->position = glm::vec3(-2, 2, -2); angles.x = M_PI/4; angles.y = M_PI/4; @@ -430,169 +429,178 @@ void GameState::gameLoop() { LP->forceCameraUpdate(); G->A->update(); LP->setHasNoclip(true); +} - std::chrono::time_point frameStart, frameEnd; - while (!GW->shouldClose()) { - if (!processNetwork()) return; +void GameState::onLogicTick() { + if (!processNetwork()) return; - T = glfwGetTime(); deltaT = T - lastT; - G->updateTime(T); - if (T > fpsT) { - char str[10]; std::snprintf(str, 10, "FPS: %-4d", frames); - UI.FPS->setText(std::string(str)); - fpsT = T+1; - frames = 0; - } - - G->R->beginFrame(); - frameStart = std::chrono::steady_clock::now(); - - if (T > nextNetUpdate) { - 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; - } - - if (bloom.enable) { - m_3dFbo->bind(); - glClearColor(0.0, 0.0, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - - LP->update(deltaT); - - glm::mat4 m_transform = LP->getPVMatrix(); - - /*** 3D PART ***/ - // TODO: multiworld - WorldRef WR = G->U->getWorld(0); - World &W = *WR; - /*glm::mat4 cloudmat = glm::scale(glm::translate(m_transform, glm::vec3(0.f, W.cloudsHeight, 0.f)), glm::vec3(4*CX, 1, 4*CZ)); - m_clouds->render(cloudmat);*/ - - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - - Render::RenderParams rp; - rp.world = WR.get(); - rp.transform = m_transform; - rp.frustum = G->LP->camera.frustum; - G->R->renderers.world->render(rp); - for (Player &p : G->players) { - p.update(deltaT); - if (G->LP->camera.frustum.sphereInFrustum(p.position, 2)) - p.render(m_transform); - } - //W.renderTransparent(m_transform); - - /*static ParticleEmitter pe(G); - pe.posAmpl = glm::vec3(1, 1, 1); - pe.pTemplate.color = glm::vec4(0, 0.4, 0.9, 1); - pe.pTemplate.size = 0.07; - pe.velAmpl = glm::vec3(0, 1, 0); - pe.pTemplate.accel = glm::vec3(0, -.7, 0); - pe.pTemplate.decay = 4; - pe.decayAmpl = 2; - - pe.setMaxCount(4*4*800); - pe.posAmpl = glm::vec3(2*16, 1, 2*16); - pe.pos = glm::vec3(2*16, 4*16+4, 2*16); - pe.pTemplate.vel = glm::vec3(0, -4, 0); - pe.velAmpl = glm::vec3(0, 2, 0); rain - - pe.update(deltaT); - Render::RenderParams rp; - rp.transform = m_transform; - G->R->PR->render(rp);*/ - - // TODO: replace harcoded 32 viewdistance - if (G->LP->raytracePointed(32, &m_pointedBlock, &m_pointedFacing)) { - m_highlightBox.program->bind(); - 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); - - m_highlightBox.vao.unbind(); - } - - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - LP->render(m_transform); - - if (bloom.enable) { - m_3dFbo->unbind(); - G->UIM->drawFullTexV(*m_3dFbo->tex); - - m_3dFbo->tex->setFiltering(Texture::Filter::Linear, Texture::Filter::Linear); - bloom.extractor.fbo->bind(); - glViewport(0, 0, GW->getW()/bloom.scale, GW->getH()/bloom.scale); - glClearColor(0.f, 0.f, 0.f, 0.f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - if (!bloom.vao) { - bloom.vao = std::make_unique(); - Render::gl::VAO::Config cfg = bloom.vao->configure(); - cfg.vertexAttrib(*m_3dRenderVBO, bloom.extractor.att_coord, 2, GL_SHORT, sizeof(Coord2DTex), 0); - cfg.vertexAttrib(*m_3dRenderVBO, bloom.extractor.att_texcoord, 2, GL_BYTE, sizeof(Coord2DTex), offsetof(Coord2DTex, u)); - cfg.commit(); - } - bloom.extractor.prog->bind(); - bloom.vao->bind(); - glUniformMatrix4fv(bloom.extractor.uni_mvp, 1, GL_FALSE, glm::value_ptr(*G->UIM->PM1)); - glDrawArrays(GL_TRIANGLES, 0, 6); - m_3dFbo->tex->setFiltering(Texture::Filter::Nearest, Texture::Filter::Nearest); - - bloom.renderer.fbo->bind(); - glClearColor(0.f, 0.f, 0.f, 0.f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - bloom.extractor.fbo->tex->bind(); - bloom.renderer.prog->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)); - glDrawArrays(GL_TRIANGLES, 0, 6); - bloom.renderer.fbo->unbind(); - - // render to real surface - glViewport(0, 0, GW->getW(), GW->getH()); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - bloom.extractor.fbo->tex->bind(); - bloom.extractor.fbo->tex->setFiltering(Texture::Filter::Linear, Texture::Filter::Linear); - glDrawArrays(GL_TRIANGLES, 0, 6); - bloom.vao->unbind(); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - - /*** 2D PART ***/ - G->UIM->drawFullRect(glm::vec4(1.f, 0.f, 0.f, 1-G->LP->health)); - updateUI(); - drawUI(); - - G->R->endFrame(); - frameEnd = std::chrono::steady_clock::now(); - frameTime = std::chrono::duration_cast>(frameEnd - frameStart).count(); - - glfwSwapBuffers(*GW); - glfwPollEvents(); - - lastT = T; - frames++; + G->updateTime(runTime()); + if (runTime() > fpsNextSampling) { + char str[10]; std::snprintf(str, 10, "FPS: %-4d", fpsCounter); + UI.FPS->setText(std::string(str)); + fpsNextSampling = runTime() + 1; + fpsCounter = 0; } +} + +void GameState::onFrameTick() { + std::chrono::time_point frameStart, frameEnd; + + G->R->beginFrame(); + frameStart = std::chrono::steady_clock::now(); + + LocalPlayer *LP = G->LP; + double T = G->Time; + if (runTime() > nextNetUpdate) { + 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; + } + + if (bloom.enable) { + m_3dFbo->bind(); + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + + double deltaT = deltaTime(); + LP->update(deltaT); + + glm::mat4 m_transform = LP->getPVMatrix(); + + /*** 3D PART ***/ + // TODO: multiworld + WorldRef WR = G->U->getWorld(0); + World &W = *WR; + /*glm::mat4 cloudmat = glm::scale(glm::translate(m_transform, glm::vec3(0.f, W.cloudsHeight, 0.f)), glm::vec3(4*CX, 1, 4*CZ)); + m_clouds->render(cloudmat);*/ + + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + + Render::RenderParams rp; + rp.world = WR.get(); + rp.transform = m_transform; + rp.frustum = G->LP->camera.frustum; + G->R->renderers.world->render(rp); + for (Player &p : G->players) { + p.update(deltaT); + if (G->LP->camera.frustum.sphereInFrustum(p.position, 2)) + p.render(m_transform); + } + //W.renderTransparent(m_transform); + + /*static ParticleEmitter pe(G); + pe.posAmpl = glm::vec3(1, 1, 1); + pe.pTemplate.color = glm::vec4(0, 0.4, 0.9, 1); + pe.pTemplate.size = 0.07; + pe.velAmpl = glm::vec3(0, 1, 0); + pe.pTemplate.accel = glm::vec3(0, -.7, 0); + pe.pTemplate.decay = 4; + pe.decayAmpl = 2; + + pe.setMaxCount(4*4*800); + pe.posAmpl = glm::vec3(2*16, 1, 2*16); + pe.pos = glm::vec3(2*16, 4*16+4, 2*16); + pe.pTemplate.vel = glm::vec3(0, -4, 0); + pe.velAmpl = glm::vec3(0, 2, 0); rain + + pe.update(deltaT); + Render::RenderParams rp; + rp.transform = m_transform; + G->R->PR->render(rp);*/ + + // TODO: replace harcoded 32 viewdistance + if (G->LP->raytracePointed(32, &m_pointedBlock, &m_pointedFacing)) { + m_highlightBox.program->bind(); + 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); + + m_highlightBox.vao.unbind(); + } + + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + G->LP->render(m_transform); + + if (bloom.enable) { + m_3dFbo->unbind(); + G->UIM->drawFullTexV(*m_3dFbo->tex); + + m_3dFbo->tex->setFiltering(Texture::Filter::Linear, Texture::Filter::Linear); + bloom.extractor.fbo->bind(); + glViewport(0, 0, GW->getW()/bloom.scale, GW->getH()/bloom.scale); + glClearColor(0.f, 0.f, 0.f, 0.f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + if (!bloom.vao) { + bloom.vao = std::make_unique(); + Render::gl::VAO::Config cfg = bloom.vao->configure(); + cfg.vertexAttrib(*m_3dRenderVBO, bloom.extractor.att_coord, 2, GL_SHORT, sizeof(Coord2DTex), 0); + cfg.vertexAttrib(*m_3dRenderVBO, bloom.extractor.att_texcoord, 2, GL_BYTE, sizeof(Coord2DTex), offsetof(Coord2DTex, u)); + cfg.commit(); + } + bloom.extractor.prog->bind(); + bloom.vao->bind(); + glUniformMatrix4fv(bloom.extractor.uni_mvp, 1, GL_FALSE, glm::value_ptr(*G->UIM->PM1)); + glDrawArrays(GL_TRIANGLES, 0, 6); + m_3dFbo->tex->setFiltering(Texture::Filter::Nearest, Texture::Filter::Nearest); + + bloom.renderer.fbo->bind(); + glClearColor(0.f, 0.f, 0.f, 0.f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + bloom.extractor.fbo->tex->bind(); + bloom.renderer.prog->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)); + glDrawArrays(GL_TRIANGLES, 0, 6); + bloom.renderer.fbo->unbind(); + + // render to real surface + glViewport(0, 0, GW->getW(), GW->getH()); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + bloom.extractor.fbo->tex->bind(); + bloom.extractor.fbo->tex->setFiltering(Texture::Filter::Linear, Texture::Filter::Linear); + glDrawArrays(GL_TRIANGLES, 0, 6); + bloom.vao->unbind(); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + /*** 2D PART ***/ + G->UIM->drawFullRect(glm::vec4(1.f, 0.f, 0.f, 1-G->LP->health)); + updateUI(); + drawUI(); + + G->R->endFrame(); + frameEnd = std::chrono::steady_clock::now(); + frameTime = std::chrono::duration_cast>(frameEnd - frameStart).count(); + + fpsCounter++; +} + +void GameState::onStop() { Net::OutMessage quit(Net::MessageType::PlayerQuit); sendMsg(quit, Net::Tfer::Rel); G->LS->finalize(); } +void GameState::gameLoop() { + double lastT, deltaT, T, fpsT = 0; int frames = 0; + LocalPlayer *LP = G->LP; +} + void GameState::renderDeathScreen() { double red = std::max(1-(G->Time-G->LP->deathTime), 0.0); glClearColor(red, 0.0, 0.0, 1.0); diff --git a/src/GameState.hpp b/src/GameState.hpp index 4b0cc93..7d147a7 100644 --- a/src/GameState.hpp +++ b/src/GameState.hpp @@ -114,6 +114,8 @@ private: std::shared_ptr EM; } UI; + int fpsCounter; + double fpsNextSampling; uint64 frameTime; void setupUI(); @@ -128,12 +130,17 @@ public: GameState(GameWindow *W); ~GameState(); - void onMouseButton(int key, int action, int mods); - void onCursorPos(double x, double y); - void onMouseScroll(double x, double y); - void onKey(int key, int scancode, int action, int mods); - void onChar(char32 unichar); - void onResize(int w, int h); + void onStart() override; + void onLogicTick() override; + void onFrameTick() override; + void onStop() override; + + void onMouseButton(int key, int action, int mods) override; + void onCursorPos(double x, double y) override; + void onMouseScroll(double x, double y) override; + void onKey(int key, int scancode, int action, int mods) override; + void onChar(char32 unichar) override; + void onResize(int w, int h) override; void run(); void updateViewport(); diff --git a/src/GameWindow.cpp b/src/GameWindow.cpp index 188d72a..417e907 100644 --- a/src/GameWindow.cpp +++ b/src/GameWindow.cpp @@ -211,7 +211,20 @@ void GameWindow::run() { while (m_nextState != nullptr && !glfwWindowShouldClose(m_window)) { m_currentState = std::move(m_nextState); m_nextState = nullptr; - m_currentState->run(); + m_currentState->onCreate(); + m_currentState->onStart(); + m_currentState->m_runTime = glfwGetTime(); + while (m_nextState == nullptr && !glfwWindowShouldClose(m_window)) { + double newTime = glfwGetTime(); + m_currentState->m_deltaTime = newTime - m_currentState->m_runTime; + m_currentState->m_runTime = newTime; + glfwPollEvents(); + m_currentState->onLogicTick(); + m_currentState->onFrameTick(); + glfwSwapBuffers(m_window); + } + m_currentState->onStop(); + m_currentState->onDestroy(); m_currentState.reset(); } } diff --git a/src/GameWindow.hpp b/src/GameWindow.hpp index 3aae81d..5720630 100644 --- a/src/GameWindow.hpp +++ b/src/GameWindow.hpp @@ -11,6 +11,7 @@ #include +#include "StateMachine.hpp" #include "Platform.hpp" namespace Diggler { @@ -22,7 +23,7 @@ namespace UI { class Manager; } -class GameWindow { +class GameWindow : public StateMachine { private: static int InstanceCount; @@ -59,7 +60,7 @@ public: void updateViewport(); - void setNextState(std::unique_ptr &&next); + void setNextState(std::unique_ptr &&next) override; void run(); void showMessage(const std::string &msg, const std::string &submsg = ""); diff --git a/src/MessageState.cpp b/src/MessageState.cpp index 47a0728..cf6cb04 100644 --- a/src/MessageState.cpp +++ b/src/MessageState.cpp @@ -20,10 +20,13 @@ MessageState::MessageState(GameWindow *W, const std::string &msg, const std::str MessageState::~MessageState() { } -void MessageState::setupUI() { +void MessageState::onStart() { txtMsg = W->G->UIM->add(msg, 2, 2); txtSubMsg = W->G->UIM->add(subMsg); updateViewport(); + if (GlobalProperties::IsSoundEnabled) { + W->G->A->playSound("click-quiet"); + } } void MessageState::updateViewport() { @@ -38,23 +41,16 @@ void MessageState::onResize(int w, int h) { updateViewport(); } -void MessageState::run() { - setupUI(); - if (GlobalProperties::IsSoundEnabled) { - W->G->A->playSound("click-quiet"); - } - while (!glfwWindowShouldClose(*W)) { - W->G->R->beginFrame(); - glClearColor(0.0, 0.0, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +void MessageState::onLogicTick() {} - W->G->UIM->render(); +void MessageState::onFrameTick() { + W->G->R->beginFrame(); + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - W->G->R->endFrame(); + W->G->UIM->render(); - glfwSwapBuffers(*W); - glfwPollEvents(); - } + W->G->R->endFrame(); } } diff --git a/src/MessageState.hpp b/src/MessageState.hpp index 6ab9dd1..fbff2f6 100644 --- a/src/MessageState.hpp +++ b/src/MessageState.hpp @@ -16,12 +16,15 @@ private: public: MessageState(GameWindow *W, const std::string &msg, const std::string &submsg = ""); - ~MessageState(); - + ~MessageState() override; + + void onStart() override; + void onLogicTick() override; + void onFrameTick() override; + //void onMouseButton(int key, int action, int mods); //void onCursorPos(double x, double y); - void onResize(int w, int h); - void run(); + void onResize(int w, int h) override; void updateViewport(); }; diff --git a/src/State.hpp b/src/State.hpp index 07e0051..e57e7f6 100644 --- a/src/State.hpp +++ b/src/State.hpp @@ -4,17 +4,42 @@ namespace Diggler { +class GameWindow; + class State { +private: + friend GameWindow; + + double m_runTime, m_deltaTime; + +protected: + inline double runTime() const { + return m_runTime; + } + inline double deltaTime() const { + return m_deltaTime; + } + public: virtual ~State() {} + // Lifecycle + virtual void onCreate() {} + virtual void onStart() {} + // virtual void onResume() {} + virtual void onLogicTick() = 0; + virtual void onFrameTick() = 0; + // virtual void onPause() {} + virtual void onStop() {} + virtual void onDestroy() {} + + // Input virtual void onMouseButton(int key, int action, int mods) {} virtual void onCursorPos(double x, double y) {} virtual void onMouseScroll(double x, double y) {} virtual void onKey(int key, int scancode, int action, int mods) {} virtual void onChar(char32 unichar) {} virtual void onResize(int w, int h) {} - virtual void run() = 0; }; } diff --git a/src/StateMachine.hpp b/src/StateMachine.hpp new file mode 100644 index 0000000..ff9b656 --- /dev/null +++ b/src/StateMachine.hpp @@ -0,0 +1,17 @@ +#ifndef DIGGLER_STATE_MACHINE_HPP +#define DIGGLER_STATE_MACHINE_HPP + +#include + +#include "State.hpp" + +namespace Diggler { + +class StateMachine { +public: + virtual void setNextState(std::unique_ptr &&next) = 0; +}; + +} + +#endif /* DIGGLER_STATE_MACHINE_HPP */ diff --git a/src/Universe.hpp b/src/Universe.hpp index ac1976c..6a314c3 100644 --- a/src/Universe.hpp +++ b/src/Universe.hpp @@ -21,28 +21,28 @@ public: Universe(Game *G, bool remote); ~Universe(); - /// - /// @brief Gets a reference to a world. - /// Gets a world using its ID. If the world doesn't exist, returns an empty reference. - /// @returns Reference to the world. - /// + /** + * @brief Gets a reference to a world. + * Gets a world using its ID. If the world doesn't exist, returns an empty reference. + * @returns Reference to the world. + */ WorldRef getWorld(WorldId id); - /// - /// @brief Gets a reference to a world. - /// Gets a world using its ID. If the world doesn't exist in memory, creates it or - /// *synchronously* loads it. - /// @returns Reference to the world. - /// + /** + * @brief Gets a reference to a world. + * Gets a world using its ID. If the world doesn't exist in memory, creates it or + * *synchronously* loads it. + * @returns Reference to the world. + */ WorldRef getLoadWorld(WorldId id); - /// - /// @brief Creates a world. - /// Creates a world with the specified ID. The World instance is constructed with - /// default parameters. - /// @note If a world with the same ID exists, an empty reference is returned. - /// @returns Reference to the newly created world. - /// + /** + * @brief Creates a world. + * Creates a world with the specified ID. The World instance is constructed with + * default parameters. + * @note If a world with the same ID exists, an empty reference is returned. + * @returns Reference to the newly created world. + */ WorldRef createWorld(WorldId id); /* ============ Serialization ============ */ diff --git a/src/content/Asset.cpp b/src/content/Asset.cpp new file mode 100644 index 0000000..23dc7b4 --- /dev/null +++ b/src/content/Asset.cpp @@ -0,0 +1,17 @@ +#include "Asset.hpp" + +#include + +#include "AssetManager.hpp" + +namespace Diggler { +namespace Content { + +Asset::Asset(const std::shared_ptr &acm) : + m_contentMetadata(acm) { +} + + + +} +} diff --git a/src/content/Asset.hpp b/src/content/Asset.hpp index 6079ac2..4d3e827 100644 --- a/src/content/Asset.hpp +++ b/src/content/Asset.hpp @@ -1,7 +1,7 @@ #ifndef DIGGLER_CONTENT_ASSET_HPP #define DIGGLER_CONTENT_ASSET_HPP -#include +#include #include "../crypto/SHA256.hpp" #include "AssetContentMetadata.hpp" @@ -26,11 +26,10 @@ protected: friend class AssetManager; Crypto::SHA256::Digest m_contentHash; - AssetContentMetadata &m_contentMetadata; + std::shared_ptr m_contentMetadata; Type m_type; - goodform::object m_info; - Asset(AssetContentMetadata&); + Asset(const std::shared_ptr&); public: const Crypto::SHA256::Digest& contentHash() const { @@ -38,16 +37,12 @@ public: } const AssetContentMetadata& contentMetadata() const { - return m_contentMetadata; + return *m_contentMetadata; } Type type() const { return m_type; } - - const goodform::object& info() const { - return m_info; - } }; } diff --git a/src/content/AssetContentMetadata.cpp b/src/content/AssetContentMetadata.cpp new file mode 100644 index 0000000..2235849 --- /dev/null +++ b/src/content/AssetContentMetadata.cpp @@ -0,0 +1,97 @@ +#include "AssetContentMetadata.hpp" + +#include + +#include + +namespace Diggler { +namespace Content { + +AssetContentMetadata::AssetContentMetadata(AssetManager &am) : + m_assetManager(am) { +} + +AssetContentMetadata::~AssetContentMetadata() { +} + +bool AssetContentMetadata::validSchemeVersion(SchemeVersion v) { + return v == 0; +} + +bool AssetContentMetadata::validSerialized(InMemoryStream &ims) { + try { + SchemeVersion schemeVersion = ims.readU32(); + if (not validSchemeVersion(schemeVersion)) { + return false; + } + + const uint64 fileSize = ims.readU64(); + /* if (fileSize > MaxFileSize) { + return false; + } */ + const uint32 blockSize = ims.readU32(); + if (blockSize < MinBlockSize or + blockSize > MaxBlockSize) { + return false; + } + const uint64 blockCount = (fileSize + (blockSize - 1)) / blockSize; + ims.seek(static_cast(blockCount * Crypto::SHA256::Digest::Length), + MemoryStream::Current); + } catch (const std::underflow_error&) { + return false; + } + return true; +} + +bool AssetContentMetadata::validSerializedDB(InMemoryStream &ims) { + if (not validSerialized(ims)) { + return false; + } + /* Enable when useful: + Stream::PosT pos = ims.tell(); + ims.rewind(); + const SchemeVersion schemeVersion = ims.readU32(); + ims.seek(pos); */ + try { + uint8 contentFileStatus = ims.readU8(); + if (contentFileStatus >= static_cast(ContentFileStatus::MAX)) { + return false; + } + } catch (const std::underflow_error&) { + return false; + } + return true; +} + +void AssetContentMetadata::fromSerialized(InMemoryStream &ims) { + m_schemeVersion = ims.readU32(); + m_fileSize = ims.readU64(); + m_blockSize = ims.readU32(); + const size_t blockCount = static_cast((m_fileSize + (m_blockSize - 1)) / m_blockSize); + m_blockHashes = decltype(m_blockHashes)(blockCount); + for (size_t i = 0; i < blockCount; ++i) { + ims.readData(m_blockHashes[i].data, decltype(m_blockHashes)::value_type::Length); + } +} + +void AssetContentMetadata::fromSerializedDB(InMemoryStream &ims) { + fromSerialized(ims); + m_contentFileStatus = static_cast(ims.readU8()); +} + +void AssetContentMetadata::toSerialized(OutMemoryStream &oms) const { + oms.writeU32(m_schemeVersion); + oms.writeU64(m_fileSize); + oms.writeU32(m_blockSize); + for (const Crypto::SHA256::Digest &blockHash : m_blockHashes) { + oms.writeData(blockHash.data, decltype(m_blockHashes)::value_type::Length); + } +} + +void AssetContentMetadata::toSerializedDB(OutMemoryStream &oms) const { + toSerialized(oms); + oms.writeU8(static_cast(m_contentFileStatus)); +} + +} +} diff --git a/src/content/CMakeLists.txt b/src/content/CMakeLists.txt index e445c53..40fa8e5 100644 --- a/src/content/CMakeLists.txt +++ b/src/content/CMakeLists.txt @@ -6,6 +6,8 @@ add_subdirectory("texture") set(CSD ${CMAKE_CURRENT_SOURCE_DIR}) diggler_add_sources( + #${CSD}/Asset.cpp + #${CSD}/AssetContentMetadata.cpp ${CSD}/AssetManager.cpp ${CSD}/ModManager.cpp ${CSD}/Registry.cpp diff --git a/src/main.cpp b/src/main.cpp index d65dfee..f1f356a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include "ConnectingState.hpp" #include "Game.hpp" diff --git a/src/network/NetHelper.cpp b/src/network/NetHelper.cpp index 3f38b83..9b0ae2e 100644 --- a/src/network/NetHelper.cpp +++ b/src/network/NetHelper.cpp @@ -1,5 +1,7 @@ #include "NetHelper.hpp" +#include + #include "msgtypes/Chat.hpp" #include "../Game.hpp" #include "../Player.hpp" @@ -23,7 +25,7 @@ void Broadcast(Game &G, const OutMessage &msg, Tfer tfer, Channels chan) { void SendChat(Game *G, const std::string &str) { Net::MsgTypes::ChatSend cs; - cs.msg = goodform::object { + cs.msg = meiose::variant::map { {"plaintext", str} }; diff --git a/src/network/Network.cpp b/src/network/Network.cpp index de51e34..e4a9c45 100644 --- a/src/network/Network.cpp +++ b/src/network/Network.cpp @@ -8,7 +8,8 @@ #include -#include +#include +#include #include "../crypto/Random.hpp" #include "../util/Log.hpp" @@ -16,6 +17,31 @@ #include +struct membuf : std::streambuf { + membuf(char* begin, char* end) { + setg(begin, begin, end); + } + membuf(void* begin, void* end) : + membuf(reinterpret_cast(begin), reinterpret_cast(end)) {} + membuf(const void* begin, const void* end) : + membuf(const_cast(begin), const_cast(end)) {} +}; +class omsgbuf : public std::streambuf { +protected: + Diggler::Net::OutMessage &omsg; +public: + omsgbuf(Diggler::Net::OutMessage &o) : omsg(o) {} +protected: + std::streamsize xsputn(const char_type* s, std::streamsize n) override { + omsg.writeData(s, n); + return n; + } + int_type overflow(int_type ch) override { + omsg.writeI8(ch); + return 1; + } +}; + namespace Diggler { namespace Net { @@ -105,16 +131,15 @@ void InMessage::free() { m_data = nullptr; } -void InMessage::readMsgpack(goodform::variant &var) { +void InMessage::readMsgpack(meiose::variant &var) { uint32 len = readU32(); if (len > remaining()) { throw std::runtime_error("Not enough bytes available for reported msgpack length"); } - InMemoryStream ims(getCursorPtr(len), len); - goodform::msgpack::deserialize(ims, var); - /*if (var.type() != goodform::variant_type::object) { - throw std::runtime_error("Read msgpack is not an object / map"); - }*/ + const void *start = getCursorPtr(len); + membuf sbuf(start, getCursorPtr()); + std::istream in(&sbuf); + meiose::msgpack::read(in, var); } @@ -149,13 +174,12 @@ void OutMessage::fit(SizeT len) { m_allocated = targetSize; } -void OutMessage::writeMsgpack(const goodform::variant &var) { - /*if (var.type() != goodform::variant_type::object) { - throw std::runtime_error("msgpack to write is not an object / map"); - }*/ +void OutMessage::writeMsgpack(const meiose::variant &var) { PosT pos = tell(); writeU32(0); - goodform::msgpack::serialize(var, *this); + omsgbuf sbuf(*this); + std::ostream out(&sbuf); + meiose::msgpack::write(out, var); PosT posWritten = tell(); seek(pos); writeU32(static_cast(posWritten - (pos + sizeof(uint32)))); diff --git a/src/network/Network.hpp b/src/network/Network.hpp index dbb1c55..40ccba5 100644 --- a/src/network/Network.hpp +++ b/src/network/Network.hpp @@ -11,6 +11,10 @@ #include "../crypto/DiffieHellman.hpp" #include "../io/MemoryStream.hpp" +namespace meiose { +class variant; +} + namespace Diggler { namespace Net { @@ -113,6 +117,7 @@ public: glm::vec3 readVec3(); glm::ivec3 readIVec3(); + void readMsgpack(meiose::variant&); Channels getChannel() const; }; @@ -153,6 +158,7 @@ public: writeI32(vec.y); writeI32(vec.z); } + void writeMsgpack(const meiose::variant&); }; class Exception : public std::exception { diff --git a/src/network/client/ChatHandler.cpp b/src/network/client/ChatHandler.cpp index 933d6ab..73fecac 100644 --- a/src/network/client/ChatHandler.cpp +++ b/src/network/client/ChatHandler.cpp @@ -21,27 +21,27 @@ bool ChatHandler::handle(GameState &GS, InMessage &msg) { ChatAnnouncement ca; ca.readFromMsg(msg); // TODO better formatting abilities - if (ca.msg.is()) { - GS.m_chatBox->addChatEntry(ca.msg["plaintext"].get()); + if (ca.msg.isMap()) { + GS.m_chatBox->addChatEntry(ca.msg["plaintext"].getStr()); } } break; case S::PlayerTalk: { ChatPlayerTalk cpt; cpt.readFromMsg(msg); // TODO better formatting abilities - if (cpt.msg.is()) { + if (cpt.msg.isStr()) { std::string playerName; - if (cpt.player.display.is()) { + if (cpt.player.display.isNil()) { const Player *blabbermouth = GS.G->players.getBySessId(cpt.player.id); if (blabbermouth != nullptr) { playerName = blabbermouth->name + "> "; } else { playerName = "?> "; } - } else if (cpt.player.display.is()) { - cpt.player.display.get(playerName); + } else if (cpt.player.display.isStr()) { + playerName = cpt.player.display.getStr(); } - GS.m_chatBox->addChatEntry(playerName + cpt.msg.get()); + GS.m_chatBox->addChatEntry(playerName + cpt.msg.getStr()); } } break; } diff --git a/src/network/msgtypes/BlockUpdate.hpp b/src/network/msgtypes/BlockUpdate.hpp index 24ba076..3b2aa61 100644 --- a/src/network/msgtypes/BlockUpdate.hpp +++ b/src/network/msgtypes/BlockUpdate.hpp @@ -3,6 +3,8 @@ #include "MsgType.hpp" +#include + #include "../../content/Content.hpp" #include "../../World.hpp" @@ -26,7 +28,7 @@ struct BlockUpdateNotify : public MsgType { glm::ivec3 pos; BlockId id; BlockData data; - //goodform::variant extdata; + meiose::variant extdata; LightData light; enum Cause : uint8 { Unspecified = 0, @@ -45,7 +47,7 @@ struct BlockUpdatePlace : public MsgType { glm::ivec3 pos; BlockId id; BlockData data; - //goodform::variant extdata; + meiose::variant extdata; void writeToMsg(OutMessage&) const override; void readFromMsg(InMessage&) override; diff --git a/src/network/msgtypes/Chat.hpp b/src/network/msgtypes/Chat.hpp index 33d0472..a8a76c1 100644 --- a/src/network/msgtypes/Chat.hpp +++ b/src/network/msgtypes/Chat.hpp @@ -3,7 +3,7 @@ #include "MsgType.hpp" -#include +#include #include "../../Player.hpp" @@ -18,7 +18,7 @@ enum class ChatSubtype : uint8 { }; struct ChatSend : public MsgType { - goodform::variant msg; + meiose::variant msg; void writeToMsg(OutMessage&) const override; void readFromMsg(InMessage&) override; @@ -28,9 +28,9 @@ struct ChatAnnouncement : public MsgType { std::string announcementType; struct Origin { std::string name; - goodform::variant display; + meiose::variant display; } origin; - goodform::variant msg; + meiose::variant msg; void writeToMsg(OutMessage&) const override; void readFromMsg(InMessage&) override; @@ -39,9 +39,9 @@ struct ChatAnnouncement : public MsgType { struct ChatPlayerTalk : public MsgType { struct ChatPlayer { PlayerGameID id; - goodform::variant display; + meiose::variant display; } player; - goodform::variant msg; + meiose::variant msg; void writeToMsg(OutMessage&) const override; void readFromMsg(InMessage&) override; diff --git a/src/network/msgtypes/ServerInfo.hpp b/src/network/msgtypes/ServerInfo.hpp index d9c3aa1..91cdcbe 100644 --- a/src/network/msgtypes/ServerInfo.hpp +++ b/src/network/msgtypes/ServerInfo.hpp @@ -3,7 +3,7 @@ #include "MsgType.hpp" -#include +#include namespace Diggler { namespace Net { @@ -16,14 +16,14 @@ enum class ServerInfoSubtype : uint8 { struct ServerInfoRequest : public MsgType { std::vector infos; - goodform::variant params; + meiose::variant params; void writeToMsg(OutMessage&) const override; void readFromMsg(InMessage&) override; }; struct ServerInfoResponse : public MsgType { - goodform::variant infos; + meiose::variant infos; void writeToMsg(OutMessage&) const override; void readFromMsg(InMessage&) override; diff --git a/src/platform/Endian.hpp b/src/platform/Endian.hpp index 1eef813..609fed7 100644 --- a/src/platform/Endian.hpp +++ b/src/platform/Endian.hpp @@ -6,17 +6,33 @@ namespace Diggler { constexpr uint16_t byteSwap16(uint16_t x) { +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + return __builtin_bswap16(x); +#else return static_cast((x >> 8) | (x << 8)); +#endif } constexpr uint32_t byteSwap32(uint32_t x) { - return (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24);; +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + return __builtin_bswap32(x); +#elif defined(__ICC) || defined(__INTEL_COMPILER) + return _bswap(x); +#else + return (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24); +#endif } constexpr uint64_t byteSwap64(uint64_t x) { +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + return __builtin_bswap64(x); +#elif defined(__ICC) || defined(__INTEL_COMPILER) + return _bswap64(x); +#else return (x>>56) | ((x<<40) & 0x00FF000000000000UL) | ((x<<24) & 0x0000FF0000000000UL) | ((x<<8) & 0x000000FF00000000UL) | ((x>>8) & 0x00000000FF000000UL) | ((x>>24) & 0x0000000000FF0000UL) | ((x>>40) & 0x000000000000FF00UL) | (x<<56); +#endif } enum class Endianness : uint8_t { @@ -27,9 +43,11 @@ enum class Endianness : uint8_t { #if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ || \ defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \ defined(__BIG_ENDIAN__) || \ - defined(__ARMEB__) || \ - defined(__THUMBEB__) || \ - defined(__AARCH64EB__) || \ + defined(__sparc) || defined(__sparc__) || \ + defined(_POWER) || defined(__powerpc__) || \ + defined(__ppc__) || defined(__hpux) || \ + defined(__s390__) || \ + defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \ defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__) constexpr Endianness SystemEndianness = Endianness::Big; @@ -51,9 +69,13 @@ constexpr uint64_t fromLe64(uint64_t x) { return byteSwap64(x); } #elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || \ defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || \ defined(__LITTLE_ENDIAN__) || \ - defined(__ARMEL__) || \ - defined(__THUMBEL__) || \ - defined(__AARCH64EL__) || \ + defined(__i386__) || defined(__alpha__) || \ + defined(__ia64) || defined(__ia64__) || \ + defined(_M_IX86) || defined(_M_IA64) || \ + defined(_M_ALPHA) || defined(__amd64) || \ + defined(__amd64__) || defined(_M_AMD64) || \ + defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ + defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || \ defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) constexpr Endianness SystemEndianness = Endianness::Little; diff --git a/src/platform/Types.hpp b/src/platform/Types.hpp index 28be7da..e41c060 100644 --- a/src/platform/Types.hpp +++ b/src/platform/Types.hpp @@ -10,6 +10,7 @@ using uint = std::uint32_t; using uint32 = std::uint32_t; using uint64 = std::uint64_t; using uint16 = std::uint16_t; +using ushort = uint16; using uint8 = std::uint8_t; using int64 = std::int64_t; using int32 = std::int32_t; diff --git a/src/render/gl/DelegateGL.hpp b/src/render/gl/DelegateGL.hpp index 512aa28..6b338d8 100644 --- a/src/render/gl/DelegateGL.hpp +++ b/src/render/gl/DelegateGL.hpp @@ -1,6 +1,7 @@ #ifndef DIGGLER_RENDER_GL_DELEGATE_GL_HPP #define DIGGLER_RENDER_GL_DELEGATE_GL_HPP +#include #include #include #include @@ -38,6 +39,16 @@ public: GLsizei width, GLsizei height, GLenum format, GLenum type, std::unique_ptr &&data); + template + static std::future()())> run(Func &&func) { + std::promise()())> promise; + auto future = promise.get_future(); + push([func { std::move(func) }, promise { std::move(promise) }] { + promise.set_value_at_thread_exit(func()); + }); + return future; + } + static void execute(); }; diff --git a/src/render/gl/VBO.hpp b/src/render/gl/VBO.hpp index 292a2cd..54b04f7 100644 --- a/src/render/gl/VBO.hpp +++ b/src/render/gl/VBO.hpp @@ -6,6 +6,7 @@ #include "OpenGL.hpp" #include "../../platform/PreprocUtils.hpp" +#include "../../platform/Types.hpp" namespace Diggler { namespace Render { diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index e4c6067..60f7f66 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -37,10 +37,12 @@ else() endif() if (DIGGLER_ENABLE_JEMALLOC) + find_package(Jemalloc REQUIRED) + diggler_add_definition( -DDIGGLER_ENABLE_JEMALLOC=1 ) diggler_link_libraries( - jemalloc + ${JEMALLOC_LIBRARIES} ) endif() diff --git a/src/util/MemoryTracker.disabled.cpp b/src/util/MemoryTracker.disabled.cpp new file mode 100644 index 0000000..b9d15b4 --- /dev/null +++ b/src/util/MemoryTracker.disabled.cpp @@ -0,0 +1,17 @@ +#include "MemoryTracker.hpp" + +namespace Diggler { +namespace Util { +namespace MemoryTracker { + +void init() {} + +void setCategory(const char*, uint_fast32_t) {} + +std::vector categoryStats() { + return {}; +} + +} +} +}