diff --git a/source/client/StarClientApplication.cpp b/source/client/StarClientApplication.cpp index f347cd5..3c2cc80 100644 --- a/source/client/StarClientApplication.cpp +++ b/source/client/StarClientApplication.cpp @@ -558,6 +558,7 @@ void ClientApplication::setError(String const& error) { void ClientApplication::setError(String const& error, std::exception const& e) { Logger::error("{}\n{}", error, outputException(e, true)); m_errorScreen->setMessage(strf("{}\n{}", error, outputException(e, false))); + changeState(MainAppState::Title); } void ClientApplication::updateMods() { diff --git a/source/core/CMakeLists.txt b/source/core/CMakeLists.txt index 5e4f090..cf64c3a 100644 --- a/source/core/CMakeLists.txt +++ b/source/core/CMakeLists.txt @@ -83,6 +83,7 @@ SET (star_core_HEADERS StarOptionParser.hpp StarOrderedMap.hpp StarOrderedSet.hpp + StarOutputProxy.hpp StarParametricFunction.hpp StarPch.hpp StarPeriodic.hpp diff --git a/source/core/StarAudio.cpp b/source/core/StarAudio.cpp index ef5d2f4..1718aa8 100644 --- a/source/core/StarAudio.cpp +++ b/source/core/StarAudio.cpp @@ -65,7 +65,7 @@ namespace { if ((strcmp(riffSig.get(), "RIFF") != 0) || (strcmp(waveSig.get(), "WAVE") != 0)) { // bytes are not magic auto p = [](char a) { return isprint(a) ? a : '?'; }; - throw AudioException(strf("Wav file has wrong magic bytes, got `{}{}{}{}' and `{}{}{}{}' but expected `RIFF' and `WAVE'", + throw AudioException(strf("Wav file has wrong magic bytes, got `{:c}{:c}{:c}{:c}' and `{:c}{:c}{:c}{:c}' but expected `RIFF' and `WAVE'", p(riffSig[0]), p(riffSig[1]), p(riffSig[2]), p(riffSig[3]), p(waveSig[0]), p(waveSig[1]), p(waveSig[2]), p(waveSig[3]))); } @@ -74,7 +74,7 @@ namespace { device->readFull(fmtSig.get(), sigLength); if (strcmp(fmtSig.get(), "fmt ") != 0) { // friendship is magic auto p = [](char a) { return isprint(a) ? a : '?'; }; - throw AudioException(strf("Wav file fmt subchunk has wrong magic bytes, got `{}{}{}{}' but expected `fmt '", + throw AudioException(strf("Wav file fmt subchunk has wrong magic bytes, got `{:c}{:c}{:c}{:c}' but expected `fmt '", p(fmtSig[0]), p(fmtSig[1]), p(fmtSig[2]), @@ -110,7 +110,7 @@ namespace { device->readFull(dataSig.get(), sigLength); if (strcmp(dataSig.get(), "data") != 0) { // magic or more magic? auto p = [](char a) { return isprint(a) ? a : '?'; }; - throw AudioException(strf("Wav file data subchunk has wrong magic bytes, got `{}{}{}{}' but expected `data'", + throw AudioException(strf("Wav file data subchunk has wrong magic bytes, got `{:c}{:c}{:c}{:c}' but expected `data'", p(dataSig[0]), p(dataSig[1]), p(dataSig[2]), p(dataSig[3]))); } diff --git a/source/core/StarException.hpp b/source/core/StarException.hpp index 4774dd2..0e6a4ed 100644 --- a/source/core/StarException.hpp +++ b/source/core/StarException.hpp @@ -1,10 +1,18 @@ #ifndef STAR_EXCEPTION_HPP #define STAR_EXCEPTION_HPP -#include "StarFormat.hpp" +#include "StarMemory.hpp" +#include "StarOutputProxy.hpp" + + +#include + namespace Star { +template +std::string strf(fmt::format_string fmt, T&&... args); + class StarException : public std::exception { public: template @@ -68,22 +76,22 @@ void fatalException(std::exception const& e, bool showStackTrace); {} #endif -#define STAR_EXCEPTION(ClassName, BaseName) \ - class ClassName : public BaseName { \ - public: \ - template \ - static ClassName format(fmt::format_string fmt, Args const&... args) { \ - return ClassName(strf(fmt, args...)); \ - } \ - ClassName() : BaseName(#ClassName, std::string()) {} \ +#define STAR_EXCEPTION(ClassName, BaseName) \ + class ClassName : public BaseName { \ + public: \ + template \ + static ClassName format(fmt::format_string fmt, Args const&... args) { \ + return ClassName(strf(fmt, args...)); \ + } \ + ClassName() : BaseName(#ClassName, std::string()) {} \ explicit ClassName(std::string message, bool genStackTrace = true) : BaseName(#ClassName, move(message), genStackTrace) {} \ - explicit ClassName(std::exception const& cause) : BaseName(#ClassName, std::string(), cause) {} \ - ClassName(std::string message, std::exception const& cause) : BaseName(#ClassName, move(message), cause) {} \ - \ - protected: \ + explicit ClassName(std::exception const& cause) : BaseName(#ClassName, std::string(), cause) {} \ + ClassName(std::string message, std::exception const& cause) : BaseName(#ClassName, move(message), cause) {} \ + \ + protected: \ ClassName(char const* type, std::string message, bool genStackTrace = true) : BaseName(type, move(message), genStackTrace) {} \ - ClassName(char const* type, std::string message, std::exception const& cause) \ - : BaseName(type, move(message), cause) {} \ + ClassName(char const* type, std::string message, std::exception const& cause) \ + : BaseName(type, move(message), cause) {} \ } STAR_EXCEPTION(OutOfRangeException, StarException); diff --git a/source/core/StarException_windows.cpp b/source/core/StarException_windows.cpp index 87d9ed6..8f5786f 100644 --- a/source/core/StarException_windows.cpp +++ b/source/core/StarException_windows.cpp @@ -1,4 +1,5 @@ #include "StarException.hpp" +#include "StarOutputProxy.hpp" #include "StarLogging.hpp" #include "StarCasting.hpp" #include "StarString_windows.hpp" diff --git a/source/core/StarFormat.hpp b/source/core/StarFormat.hpp index ccfb80c..c31697f 100644 --- a/source/core/StarFormat.hpp +++ b/source/core/StarFormat.hpp @@ -2,6 +2,7 @@ #define STAR_FORMAT_HPP #include "StarMemory.hpp" +#include "StarException.hpp" #include "fmt/core.h" #include "fmt/ostream.h" @@ -10,23 +11,19 @@ namespace Star { -struct FormatException : public std::exception { - FormatException(std::string what) : whatmsg(move(what)) {} +STAR_EXCEPTION(FormatException, StarException); - char const* what() const noexcept override { - return whatmsg.c_str(); +template +std::string strf(fmt::format_string fmt, T&&... args) { + try { return fmt::format(fmt, args...); } + catch (std::exception const& e) { + throw FormatException(strf("Exception thrown during string format: {}", e.what())); } - - std::string whatmsg; -}; - } -namespace Star { - template void format(std::ostream& out, fmt::format_string fmt, T&&... args) { - out << fmt::format(fmt, args...); + out << strf(fmt, args...); } // Automatically flushes, use format to avoid flushing. @@ -43,66 +40,6 @@ void cerrf(char const* fmt, Args const&... args) { std::cerr.flush(); } -template -std::string strf(fmt::format_string fmt, T&&... args) { - return fmt::format(fmt, args...); } -namespace OutputAnyDetail { - template - std::basic_string string(T const& t) { - return fmt::format("", typeid(T).name(), (void*)&t); - } - - template - std::basic_ostream& output(std::basic_ostream& os, T const& t) { - return os << string(t); - } - - namespace Operator { - template - std::basic_ostream& operator<<(std::basic_ostream& os, T const& t) { - return output(os, t); - } - } - - template - struct Wrapper { - T const& wrapped; - }; - - template - std::ostream& operator<<(std::ostream& os, Wrapper const& wrapper) { - using namespace Operator; - return os << wrapper.wrapped; - } -} - -// Wraps a type so that is printable no matter what.. If no operator<< is -// defined for a type, then will print -template -OutputAnyDetail::Wrapper outputAny(T const& t) { - return OutputAnyDetail::Wrapper{t}; -} - -struct OutputProxy { - typedef function PrintFunction; - - OutputProxy(PrintFunction p) - : print(move(p)) {} - - PrintFunction print; -}; - -inline std::ostream& operator<<(std::ostream& os, OutputProxy const& p) { - p.print(os); - return os; -} - -} - -template -struct fmt::formatter> : ostream_formatter {}; -template <> struct fmt::formatter : ostream_formatter {}; - #endif diff --git a/source/core/StarOutputProxy.hpp b/source/core/StarOutputProxy.hpp new file mode 100644 index 0000000..6449d94 --- /dev/null +++ b/source/core/StarOutputProxy.hpp @@ -0,0 +1,68 @@ +#ifndef STAR_OUTPUT_PROXY_HPP +#define STAR_OUTPUT_PROXY_HPP + +#include "StarMemory.hpp" + +#include "fmt/format.h" +#include "fmt/ostream.h" + +namespace Star { + +namespace OutputAnyDetail { + template + std::basic_string string(T const& t) { + return fmt::format("", typeid(T).name(), (void*)&t); + } + + template + std::basic_ostream& output(std::basic_ostream& os, T const& t) { + return os << string(t); + } + + namespace Operator { + template + std::basic_ostream& operator<<(std::basic_ostream& os, T const& t) { + return output(os, t); + } + } + + template + struct Wrapper { + T const& wrapped; + }; + + template + std::ostream& operator<<(std::ostream& os, Wrapper const& wrapper) { + using namespace Operator; + return os << wrapper.wrapped; + } +} + +// Wraps a type so that is printable no matter what.. If no operator<< is +// defined for a type, then will print +template +OutputAnyDetail::Wrapper outputAny(T const& t) { + return OutputAnyDetail::Wrapper{t}; +} + +struct OutputProxy { + typedef function PrintFunction; + + OutputProxy(PrintFunction p) + : print(move(p)) {} + + PrintFunction print; +}; + +inline std::ostream& operator<<(std::ostream& os, OutputProxy const& p) { + p.print(os); + return os; +} + +} + +template +struct fmt::formatter> : ostream_formatter {}; +template <> struct fmt::formatter : ostream_formatter {}; + +#endif \ No newline at end of file diff --git a/source/frontend/StarChatBubbleSeparation.cpp b/source/frontend/StarChatBubbleSeparation.cpp index 23a34fe..ba22ed5 100644 --- a/source/frontend/StarChatBubbleSeparation.cpp +++ b/source/frontend/StarChatBubbleSeparation.cpp @@ -73,8 +73,8 @@ RectF separateBubble(List const& sortedLeftEdges, List const& sort if (overlappingBoxes.empty()) break; RectF overlapBoundBox = fold(overlappingBoxes, box, [](RectF const& a, RectF const& b) { return a.combined(b); }); - SpatialLogger::logPoly("screen", PolyF(box), { 255, 0, 0, 255 }); - SpatialLogger::logPoly("screen", PolyF(overlapBoundBox), { 0, 0, 255, 255 }); + //SpatialLogger::logPoly("screen", PolyF(box), { 255, 0, 0, 255 }); + //SpatialLogger::logPoly("screen", PolyF(overlapBoundBox), { 0, 0, 255, 255 }); auto height = box.height(); box.setYMin(overlapBoundBox.yMax()); box.setYMax(box.yMin() + height); diff --git a/source/game/StarGameTypes.cpp b/source/game/StarGameTypes.cpp index 7e47eeb..0ea2c6e 100644 --- a/source/game/StarGameTypes.cpp +++ b/source/game/StarGameTypes.cpp @@ -2,6 +2,9 @@ namespace Star { +float WorldTimestep = 1.0f / 120.0f; +float ServerWorldTimestep = 1.0f / 20.0f; + EnumMap const DirectionNames{ {Direction::Left, "left"}, {Direction::Right, "right"}, diff --git a/source/game/StarGameTypes.hpp b/source/game/StarGameTypes.hpp index 2e33740..ab8dd63 100644 --- a/source/game/StarGameTypes.hpp +++ b/source/game/StarGameTypes.hpp @@ -93,7 +93,8 @@ extern EnumMap const RarityNames; // distance (one tile). unsigned const TilePixels = 8; -float const WorldTimestep = 1.0f / 60.0f; +extern float WorldTimestep; +extern float ServerWorldTimestep; float const SystemWorldTimestep = 1.0f / 20.0f; size_t const WorldSectorSize = 32; diff --git a/source/game/StarWorldClient.cpp b/source/game/StarWorldClient.cpp index 3e91779..3a3fe39 100644 --- a/source/game/StarWorldClient.cpp +++ b/source/game/StarWorldClient.cpp @@ -32,6 +32,7 @@ WorldClient::WorldClient(PlayerPtr mainPlayer) { m_clientConfig = assets->json("/client.config"); m_currentStep = 0; + m_currentServerStep = 0.0; m_fullBright = false; m_worldDimTimer = GameTimer(m_clientConfig.getFloat("worldDimTime")); m_worldDimTimer.setDone(); @@ -463,10 +464,15 @@ void WorldClient::render(WorldRenderData& renderData, unsigned bufferTiles) { for (size_t y = 0; y < ySize; ++y) { auto& tile = column[y]; - Vec3F light = materialDatabase->radiantLight(tile.foreground, tile.foregroundMod); - light += liquidsDatabase->radiantLight(tile.liquid) * tile.liquid.level; + Vec3F light; + if (tile.foreground != EmptyMaterialId || tile.foregroundMod != NoModId) + light += materialDatabase->radiantLight(tile.foreground, tile.foregroundMod); + + if (tile.liquid.liquid != EmptyLiquidId && tile.liquid.level != 0.0f) + light += liquidsDatabase->radiantLight(tile.liquid); if (tile.foregroundLightTransparent) { - light += materialDatabase->radiantLight(tile.background, tile.backgroundMod); + if (tile.background != EmptyMaterialId || tile.backgroundMod != NoModId) + light += materialDatabase->radiantLight(tile.background, tile.backgroundMod); if (tile.backgroundLightTransparent && pos[1] + y > undergroundLevel) light += environmentLight; } @@ -758,7 +764,8 @@ void WorldClient::handleIncomingPackets(List const& packets) { tryGiveMainPlayerItem(itemDatabase->item(giveItem->item)); } else if (auto stepUpdate = as(packet)) { - m_interpolationTracker.receiveStepUpdate(stepUpdate->remoteStep); + m_currentServerStep = ((double)stepUpdate->remoteStep * (WorldTimestep / ServerWorldTimestep)); + m_interpolationTracker.receiveStepUpdate(m_currentServerStep); } else if (auto environmentUpdatePacket = as(packet)) { m_sky->readUpdate(environmentUpdatePacket->skyDelta); @@ -893,7 +900,8 @@ void WorldClient::update() { } ++m_currentStep; - m_interpolationTracker.update(m_currentStep); + //m_interpolationTracker.update(m_currentStep); + m_interpolationTracker.update(Time::monotonicTime()); List triggeredActions; eraseWhere(m_timers, [&triggeredActions](pair& timer) { @@ -1464,6 +1472,7 @@ void WorldClient::clearWorld() { } m_currentStep = 0; + m_currentServerStep = 0.0; m_inWorld = false; m_clientId.reset(); diff --git a/source/game/StarWorldClient.hpp b/source/game/StarWorldClient.hpp index 3a9d7af..1a86f80 100644 --- a/source/game/StarWorldClient.hpp +++ b/source/game/StarWorldClient.hpp @@ -235,6 +235,7 @@ private: WorldGeometry m_geometry; uint64_t m_currentStep; + double m_currentServerStep; bool m_fullBright; CellularLightingCalculator m_lightingCalculator; mutable CellularLightIntensityCalculator m_lightIntensityCalculator; diff --git a/source/rendering/StarTextPainter.cpp b/source/rendering/StarTextPainter.cpp index 6db4a34..eb161d4 100644 --- a/source/rendering/StarTextPainter.cpp +++ b/source/rendering/StarTextPainter.cpp @@ -6,9 +6,9 @@ namespace Star { namespace Text { + static auto stripEscapeRegex = std::regex(strf("\\{:c}[^;]*{:c}", CmdEsc, EndEsc)); String stripEscapeCodes(String const& s) { - String regex = strf("\\{}[^;]*{}", CmdEsc, EndEsc); - return std::regex_replace(s.utf8(), std::regex(regex.utf8()), ""); + return std::regex_replace(s.utf8(), stripEscapeRegex, ""); } String preprocessEscapeCodes(String const& s) {