Fix broken regex, make game timestep non-const

This commit is contained in:
Kae 2023-06-28 00:20:22 +10:00
parent 2496789ea7
commit 152af87655
13 changed files with 129 additions and 99 deletions

View File

@ -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() {

View File

@ -83,6 +83,7 @@ SET (star_core_HEADERS
StarOptionParser.hpp
StarOrderedMap.hpp
StarOrderedSet.hpp
StarOutputProxy.hpp
StarParametricFunction.hpp
StarPch.hpp
StarPeriodic.hpp

View File

@ -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])));
}

View File

@ -1,10 +1,18 @@
#ifndef STAR_EXCEPTION_HPP
#define STAR_EXCEPTION_HPP
#include "StarFormat.hpp"
#include "StarMemory.hpp"
#include "StarOutputProxy.hpp"
#include <string>
namespace Star {
template <typename... T>
std::string strf(fmt::format_string<T...> fmt, T&&... args);
class StarException : public std::exception {
public:
template <typename... Args>
@ -68,22 +76,22 @@ void fatalException(std::exception const& e, bool showStackTrace);
{}
#endif
#define STAR_EXCEPTION(ClassName, BaseName) \
class ClassName : public BaseName { \
public: \
template <typename... Args> \
static ClassName format(fmt::format_string<Args...> 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 <typename... Args> \
static ClassName format(fmt::format_string<Args...> 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);

View File

@ -1,4 +1,5 @@
#include "StarException.hpp"
#include "StarOutputProxy.hpp"
#include "StarLogging.hpp"
#include "StarCasting.hpp"
#include "StarString_windows.hpp"

View File

@ -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 <typename... T>
std::string strf(fmt::format_string<T...> 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 <typename... T>
void format(std::ostream& out, fmt::format_string<T...> 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 <typename... T>
std::string strf(fmt::format_string<T...> fmt, T&&... args) {
return fmt::format(fmt, args...);
}
namespace OutputAnyDetail {
template<typename T, typename CharT, typename Traits>
std::basic_string<CharT, Traits> string(T const& t) {
return fmt::format("<type {} at address: {}>", typeid(T).name(), (void*)&t);
}
template<typename T, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& output(std::basic_ostream<CharT, Traits>& os, T const& t) {
return os << string<T, CharT, Traits>(t);
}
namespace Operator {
template<typename T, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, T const& t) {
return output(os, t);
}
}
template <typename T>
struct Wrapper {
T const& wrapped;
};
template <typename T>
std::ostream& operator<<(std::ostream& os, Wrapper<T> 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 <type [typeid] at address: [address]>
template <typename T>
OutputAnyDetail::Wrapper<T> outputAny(T const& t) {
return OutputAnyDetail::Wrapper<T>{t};
}
struct OutputProxy {
typedef function<void(std::ostream&)> 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 <typename T>
struct fmt::formatter<Star::OutputAnyDetail::Wrapper<T>> : ostream_formatter {};
template <> struct fmt::formatter<Star::OutputProxy> : ostream_formatter {};
#endif

View File

@ -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<typename T, typename CharT, typename Traits>
std::basic_string<CharT, Traits> string(T const& t) {
return fmt::format("<type {} at address: {}>", typeid(T).name(), (void*)&t);
}
template<typename T, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& output(std::basic_ostream<CharT, Traits>& os, T const& t) {
return os << string<T, CharT, Traits>(t);
}
namespace Operator {
template<typename T, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, T const& t) {
return output(os, t);
}
}
template <typename T>
struct Wrapper {
T const& wrapped;
};
template <typename T>
std::ostream& operator<<(std::ostream& os, Wrapper<T> 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 <type [typeid] at address: [address]>
template <typename T>
OutputAnyDetail::Wrapper<T> outputAny(T const& t) {
return OutputAnyDetail::Wrapper<T>{t};
}
struct OutputProxy {
typedef function<void(std::ostream&)> 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 <typename T>
struct fmt::formatter<Star::OutputAnyDetail::Wrapper<T>> : ostream_formatter {};
template <> struct fmt::formatter<Star::OutputProxy> : ostream_formatter {};
#endif

View File

@ -73,8 +73,8 @@ RectF separateBubble(List<RectF> const& sortedLeftEdges, List<RectF> 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);

View File

@ -2,6 +2,9 @@
namespace Star {
float WorldTimestep = 1.0f / 120.0f;
float ServerWorldTimestep = 1.0f / 20.0f;
EnumMap<Direction> const DirectionNames{
{Direction::Left, "left"},
{Direction::Right, "right"},

View File

@ -93,7 +93,8 @@ extern EnumMap<Rarity> 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;

View File

@ -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<PacketPtr> const& packets) {
tryGiveMainPlayerItem(itemDatabase->item(giveItem->item));
} else if (auto stepUpdate = as<StepUpdatePacket>(packet)) {
m_interpolationTracker.receiveStepUpdate(stepUpdate->remoteStep);
m_currentServerStep = ((double)stepUpdate->remoteStep * (WorldTimestep / ServerWorldTimestep));
m_interpolationTracker.receiveStepUpdate(m_currentServerStep);
} else if (auto environmentUpdatePacket = as<EnvironmentUpdatePacket>(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<WorldAction> triggeredActions;
eraseWhere(m_timers, [&triggeredActions](pair<int, WorldAction>& timer) {
@ -1464,6 +1472,7 @@ void WorldClient::clearWorld() {
}
m_currentStep = 0;
m_currentServerStep = 0.0;
m_inWorld = false;
m_clientId.reset();

View File

@ -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;

View File

@ -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) {