Rewrite on simdjson with a flat src and smack-style build

This commit is contained in:
shweet committed 2026-11-12 21:43:49 -05:00
1 parent 2d11cddc5e
commit 1a0db1abbd
178 files changed
+5935 -44757

No files matched your search

+209
View File
@@ -0,0 +1,209 @@
#include "save.h"
#include <SDL3/SDL.h>
#include <cstdio>
#include <type_traits>
#ifdef SDL_PLATFORM_EMSCRIPTEN
#include <emscripten.h>
#endif
constexpr const char* KEY_DISCOVERED = "discovered";
constexpr const char* KEY_ITEM = "item";
constexpr const char* SETTINGS_FILE = "settings.txt";
static void value_read(const char* text, float& value)
{
value = (float)SDL_atof(text);
}
static void value_read(const char* text, int& value)
{
value = SDL_atoi(text);
}
static void value_read(const char* text, bool& value)
{
value = SDL_atoi(text);
}
static void value_read(const char* text, Measurement& value)
{
value = (Measurement)SDL_atoi(text);
}
static void value_read(const char* text, std::string& value)
{
value = text;
}
static void value_read(const char* text, Vec2& value)
{
SDL_sscanf(text, "%f %f", &value.x, &value.y);
}
static void value_read(const char* text, Color& value)
{
SDL_sscanf(text, "%f %f %f", &value.r, &value.g, &value.b);
}
static std::string value_write(float value)
{
return std::to_string(value);
}
static std::string value_write(int value)
{
return std::to_string(value);
}
static std::string value_write(const std::string& value)
{
return value;
}
static std::string value_write(Vec2 value)
{
return value_write(value.x) + " " + value_write(value.y);
}
static std::string value_write(Color value)
{
return value_write(value.r) + " " + value_write(value.g) + " " + value_write(value.b);
}
// Calls line with each key and value of a key=value text file. Returns whether it was there.
template <class Line> static bool lines_read(const std::string& path, Line&& line)
{
char* text = (char*)SDL_LoadFile(path.c_str(), nullptr);
if (!text)
return false;
char* rest = nullptr;
for (char* entry = SDL_strtok_r(text, "\r\n", &rest); entry; entry = SDL_strtok_r(nullptr, "\r\n", &rest))
{
char* value = SDL_strchr(entry, '=');
if (!value)
continue;
*value++ = '\0';
line(std::string(entry), value);
}
SDL_free(text);
return true;
}
static void file_write(const std::string& path, const std::string& text)
{
SDL_CreateDirectory(path.substr(0, path.find_last_of('/')).c_str());
if (!SDL_SaveFile(path.c_str(), text.data(), text.size()))
SDL_Log("Failed to save %s: %s", path.c_str(), SDL_GetError());
#ifdef SDL_PLATFORM_EMSCRIPTEN
EM_ASM(FS.syncfs(false, () => {}));
#endif
}
// Reads every field a visitable struct names from a key=value file, and writes them back.
template <class Fields> static bool fields_read(const std::string& path, Fields& fields)
{
return lines_read(path, [&](const std::string& key, const char* value) {
fields.visit([&](const char* name, auto& field) {
if (key == name)
value_read(value, field);
});
});
}
template <class Fields> static std::string fields_write(Fields& fields)
{
std::string text;
fields.visit([&](const char* name, auto& field) {
using Type = std::decay_t<decltype(field)>;
if constexpr (std::is_same_v<Type, bool> || std::is_enum_v<Type>)
text += std::string(name) + "=" + value_write((int)field) + "\n";
else
text += std::string(name) + "=" + value_write(field) + "\n";
});
return text;
}
template <class Visitor> void Settings::visit(Visitor&& visitor)
{
visitor("character_color", isCharacterColor);
visitor("color", color);
visitor("console", isConsole);
visitor("height", height);
visitor("last_character", lastCharacter);
visitor("measurement", measurement);
visitor("mute", isMuted);
visitor("volume", volume);
visitor("width", width);
}
void Settings::load()
{
fields_read(pref_path_get(SETTINGS_FILE), *this);
}
void Settings::save()
{
file_write(pref_path_get(SETTINGS_FILE), fields_write(*this));
}
// Puts back the defaults of what the settings menu shows.
void Settings::reset()
{
Settings defaults;
color = defaults.color;
measurement = defaults.measurement;
volume = defaults.volume;
isCharacterColor = defaults.isCharacterColor;
isMuted = defaults.isMuted;
}
template <class Visitor> void Progress::visit(Visitor&& visitor)
{
visitor("alternate", isAlternate);
visitor("calories", calories);
visitor("capacity", capacity);
visitor("digesting", isDigesting);
visitor("digestion_progress", digestionProgress);
visitor("digestion_rate", digestionRate);
visitor("digestion_timer", digestionTimer);
visitor("pan", pan);
visitor("playtime", playtime);
visitor("postgame", isPostgame);
visitor("spawn_delay", spawnDelay);
visitor("total_calories", totalCalories);
visitor("total_consumed", totalConsumed);
visitor("total_spawned", totalSpawned);
visitor("weight", weight);
visitor("zoom", zoom);
}
// Items are kept one per line as their position, velocity, rotation and then name.
void Progress::load(const std::string& path)
{
*this = {};
isValid = fields_read(path, *this);
lines_read(path, [&](const std::string& key, const char* value) {
if (key == KEY_DISCOVERED)
discovered.emplace_back(value);
SavedItem item;
int length = 0;
if (key == KEY_ITEM && std::sscanf(value, "%f %f %f %f %f %n", &item.position.x, &item.position.y,
&item.velocity.x, &item.velocity.y, &item.rotation, &length) == 5)
{
item.name = value + length;
items.push_back(item);
}
});
}
void Progress::save(const std::string& path)
{
std::string text = fields_write(*this);
for (const std::string& name : discovered)
text += std::string(KEY_DISCOVERED) + "=" + name + "\n";
for (const SavedItem& item : items)
text += std::string(KEY_ITEM) + "=" + value_write(item.position) + " " + value_write(item.velocity) + " " +
value_write(item.rotation) + " " + item.name + "\n";
file_write(path, text);
}