Update some things.

This commit is contained in:
Signal 2026-04-06 18:30:52 -04:00
parent f215bc3742
commit f9d6e7a70a
35 changed files with 575 additions and 905 deletions

60
Shared/Paths.cpp Normal file
View file

@ -0,0 +1,60 @@
#include "Paths.h"
namespace Artifact {
Path getDataPath() {
Path base;
// ────────────────────────────────────────────────
// 1. Windows — AppData/Roaming (most common choice)
// ────────────────────────────────────────────────
#ifdef _WIN32
const char* appdata = std::getenv("APPDATA");
if (!appdata || !fs::exists(appdata)) {
throw std::runtime_error("Cannot find APPDATA environment variable");
}
base = Path(appdata) / organization / GAME;
#elif defined(__APPLE__)
// ────────────────────────────────────────────────
// 2. macOS — Application Support
// ────────────────────────────────────────────────
const char* home = std::getenv("HOME");
if (!home) throw std::runtime_error("Cannot find HOME");
base = Path(home) / "Library" / "Application Support" / GAME;
#else
// ────────────────────────────────────────────────
// 3. Linux / BSD / Steam Deck — XDG_DATA_HOME
// ────────────────────────────────────────────────
const char* xdg_data = std::getenv("XDG_DATA_HOME");
if (xdg_data && *xdg_data) {
base = fs::path(xdg_data) / game;
} else {
const char* home = std::getenv("HOME");
if (!home) throw std::runtime_error("Cannot find HOME");
base = Path(home) / ".local" / "share" / GAME;
}
#endif
// Create folder structure if it doesn't exist
std::error_code ec;
std::filesystem::create_directories(base, ec);
if (ec) {
throw std::runtime_error("Failed to create directory: " +
base.string() + "" + ec.message());
}
return base;
}
Path getClientConfigPath() {
return getDataPath() / "client.conf";
}
Path getServerConfigPath() {
return getDataPath() / "server.conf";
}
}

24
Shared/Paths.h Normal file
View file

@ -0,0 +1,24 @@
#pragma once
#include <filesystem>
#include <iostream>
#ifndef APP_NAME
# define APP_NAME ArtifactEngine
#endif
#define TOSTRING(x) #x
#define GAME TOSTRING(APP_NAME)
namespace Artifact {
using Path = std::filesystem::path;
Path getDataPath();
Path getClientConfigPath();
Path getServerConfigPath();
}

58
Shared/Settings.cpp Normal file
View file

@ -0,0 +1,58 @@
#include "Settings.h"
namespace Artifact {
Settings::Settings() : Settings(getDataPath() / "settings.conf") {}
Settings::Settings(Path path) : path(path) {
reload();
}
std::string trim(const std::string& str) {
size_t first = str.find_first_not_of(" \t\r\n");
if (first == std::string::npos) return "";
size_t last = str.find_last_not_of(" \t\r\n");
return str.substr(first, last - first + 1);
}
void Settings::reload() {
clear();
std::ifstream file(path);
if (!file.is_open()) {
// TODO: Log a warning
return;
}
std::string line;
while (std::getline(file, line)) {
line = trim(line);
if (line.empty() || line[0] == '#' || line[0] == ';') {
continue;
}
size_t eq_pos = line.find('=');
if (eq_pos == std::string::npos) {
continue;
}
std::string key = trim(line.substr(0, eq_pos));
std::string value = trim(line.substr(eq_pos + 1));
if (!key.empty()) {
data[key] = value;
}
}
}
void Settings::save() {
std::ofstream file(path);
if (!file.is_open()) {
return;
}
for (const auto & [key, value] : data) {
file << key << " = " << value << '\n';
}
}
}

85
Shared/Settings.h Normal file
View file

@ -0,0 +1,85 @@
#pragma once
#include <string>
#include <fstream>
#include <sstream>
#include <optional>
#include "Paths.h"
#include "Events.h"
namespace Artifact {
namespace Events {
struct SettingChanged {
std::string key;
std::optional<std::string> value;
};
}
class Settings: public EventTarget {
const Path path;
std::unordered_map<std::string, std::string> data;
public:
Settings();
Settings(Path path);
void reload();
void save();
template<typename T>
T get(std::string & key, const T & fallback = {}) {
auto it = data.find(key);
if (it == data.end()) {
return fallback;
}
const std::string & str = it->second;
if constexpr (std::is_same_v<T, std::string>) {
return str;
}
if constexpr (std::is_same_v<T, bool>) {
std::string lower = str;
std::transform(lower.begin(), lower.end(), lower.begin(),
[](unsigned char c){ return static_cast<char>(std::tolower(c)); });
if (lower == "true" || lower == "1" || lower == "yes" || lower == "on") {
return true;
}
if (lower == "false" || lower == "0" || lower == "no" || lower == "off") {
return false;
}
return fallback;
}
std::istringstream iss(str);
T value;
if (iss >> value) {
return value;
}
return fallback;
}
template<typename T>
void set(const std::string & key, const T & value) {
std::ostringstream oss;
oss << std::boolalpha << value;
data[key] = oss.str();
dispatch(Events::SettingChanged { .key = key, .value = value });
}
void reset(const std::string & key) {
data.erase(key);
dispatch(Events::SettingChanged { .key = key, .value = std::nullopt });
}
void clear() {
data.clear();
}
};
}

View file

@ -1,7 +1,11 @@
#include <iostream>
#include "Shared.h"
namespace Artifact {
void log(std::string msg) {
std::cout << msg << std::endl;
}
}

View file

@ -75,12 +75,73 @@ public:
class BaseSubsystem {
public:
Engine<BaseSubsystem> * engine = nullptr;
virtual void init() {}
virtual void reload() {}
virtual void deinit() {}
virtual void render() {}
virtual void tick() {}
};
template<typename T> requires std::integral<T> || std::floating_point<T>
class Composed {
enum ModifierType {
Add, Multiply
};
using Modifier = std::pair<ModifierType, T>;
uint64_t nextID = 0;
std::vector<Modifier> modifiers;
T _value;
public:
Composed() : Composed(T{0}) {}
Composed(T base) {
add(Add, base);
}
T value() {
return _value;
}
void recompute() {
T sum;
T fac;
for (auto [type, value] : modifiers) {
if (type == Add) {
sum += value;
} else if (type == Multiply) {
fac *= value;
}
}
_value = sum * fac;
}
uint64_t add(ModifierType type, T value) {
modifiers.emplace_back(type, value);
recompute();
return nextID++;
}
bool remove(uint64_t id) {
auto it = std::find_if(modifiers.begin(), modifiers.end(),
[id](const Modifier & m) { return m.id == id; });
if (it == modifiers.end()) return false;
modifiers.erase(it);
recompute();
return true;
}
bool update(uint64_t id, T newValue) {
auto it = std::find_if(modifiers.begin(), modifiers.end(),
[id](const Modifier& m) { return m.id == id; });
if (it == modifiers.end()) return false;
it->value = newValue;
recompute();
return true;
}
};
void log(std::string msg);
}