Update some things.
This commit is contained in:
parent
f215bc3742
commit
f9d6e7a70a
35 changed files with 575 additions and 905 deletions
60
Shared/Paths.cpp
Normal file
60
Shared/Paths.cpp
Normal 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
24
Shared/Paths.h
Normal 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
58
Shared/Settings.cpp
Normal 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
85
Shared/Settings.h
Normal 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();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,7 +1,11 @@
|
|||
#include <iostream>
|
||||
|
||||
#include "Shared.h"
|
||||
|
||||
namespace Artifact {
|
||||
|
||||
|
||||
void log(std::string msg) {
|
||||
std::cout << msg << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue