Merge pull request 'feat/filesystem' (#8) from feat/filesystem into main
CI / build-and-test (push) Successful in 2m40s
Sync Docs to Gitea Wiki / Sync docs to Gitea wiki (push) Successful in 11s

Reviewed-on: #8
This commit was merged in pull request #8.
This commit is contained in:
2026-03-13 02:07:25 +00:00
24 changed files with 1186 additions and 48 deletions
+3
View File
@@ -13,3 +13,6 @@
[submodule "external/physfs"]
path = external/physfs
url = https://github.com/icculus/physfs
[submodule "external/snkv"]
path = external/snkv
url = https://github.com/hash-anu/snkv
+41
View File
@@ -19,6 +19,43 @@ add_subdirectory(external/angelscript/sdk/angelscript/projects/cmake)
# -------------------------
add_subdirectory(external/physfs)
# -------------------------
# SNKV (submodule)
# -------------------------
add_library(snkv STATIC
external/snkv/src/kvstore.c
external/snkv/src/btree.c
external/snkv/src/btmutex.c
external/snkv/src/pager.c
external/snkv/src/pcache.c
external/snkv/src/pcache1.c
external/snkv/src/wal.c
external/snkv/src/memjournal.c
external/snkv/src/bitvec.c
external/snkv/src/os.c
external/snkv/src/os_unix.c
external/snkv/src/os_win.c
external/snkv/src/os_kv.c
external/snkv/src/mutex.c
external/snkv/src/mutex_noop.c
external/snkv/src/mutex_unix.c
external/snkv/src/mutex_w32.c
external/snkv/src/malloc.c
external/snkv/src/status.c
external/snkv/src/global.c
external/snkv/src/hash.c
external/snkv/src/util.c
external/snkv/src/printf.c
external/snkv/src/random.c
external/snkv/src/threads.c
external/snkv/src/fault.c
external/snkv/src/mem1.c
)
target_include_directories(snkv PUBLIC
external/snkv/include
)
# -------------------------
# Dear ImGui (docking branch)
# -------------------------
@@ -99,6 +136,8 @@ add_library(simian_core STATIC
src/scripting/InputBindings.cpp
src/scripting/SceneBindings.cpp
src/scripting/PhysFSBindings.cpp
src/scripting/SNKVBindings.cpp
src/scripting/GlobalsBindings.cpp
src/HotReload.cpp
src/gui/GuiManager.cpp
src/gui/ImViewGuizmoIntegration.cpp
@@ -123,6 +162,7 @@ target_include_directories(simian_core PUBLIC
external/angelscript/sdk/add_on/scriptbuilder
external/angelscript/sdk/add_on/scriptarray
external/physfs/src
external/snkv/include
external/imgui
external/ImViewGuizmo
)
@@ -131,6 +171,7 @@ target_link_libraries(simian_core PUBLIC
raylib
angelscript
PhysFS::PhysFS-static
snkv
scriptstdstring
scriptbuilder
scriptarray
+2
View File
@@ -132,6 +132,7 @@ cd ../.. && git add external/raylib external/angelscript && git commit -m "Updat
- The project was developed and tested on Windows with Visual Studio; Linux builds are supported but may need X11 / audio dev packages installed depending on your environment.
- The codebase avoids changing tracked submodule contents; use the `cmake/` wrappers when a submodule doesn't include a CMake build.
- Runtime writes are limited to `user/`. Scene saves and asset registry writes require `--editor`.
## License
@@ -139,3 +140,4 @@ cd ../.. && git add external/raylib external/angelscript && git commit -m "Updat
* AngelScript: MIT License (see https://github.com/angelcode/angelscript/blob/master/license.txt)
* Simian: Not open source (yet)
* Entt: MIT License (see https://github.com/skypjack/entt/blob/main/LICENSE)
* SNKV: Apache-2.0 License (see https://github.com/hash-anu/snkv/blob/master/LICENSE)
+1 -1
View File
@@ -5,7 +5,7 @@
key = "Torus"
type = "primitive"
primitive = "torus"
params = [0.5, 1, 16, 8]
params = [0.5, 1, 32, 16]
[[model]]
key = "demo_cube"
+49
View File
@@ -55,6 +55,55 @@ ECS::AddTexture(e, Asset::GetTextureId("grid"));
ECS::AddMaterial(e, Asset::GetMaterialId("toon_mat"));
```
## Key-Value Store (SNKV)
- Databases are stored under `user/db/<name>.db`.
- `Open()` returns a handle (0 on failure). Use that handle for all operations.
- TTL values are in milliseconds and are applied relative to the current time.
Example:
```angelscript
uint db = KV::Open("session_cache");
if (db != 0) {
KV::Put(db, "player", "nick");
// Expire in 30 seconds
KV::PutTtl(db, "token", "abc123", 30000);
string value;
int64 remainingMs = 0;
if (KV::GetTtl(db, "token", value, remainingMs)) {
Print("token=" + value + " remaining=" + remainingMs);
}
KV::Close(db);
}
```
## Globals (in-memory)
- Cross-scene, in-memory store for runtime state.
- Uses the same typed overloads as the KV API.
- Values persist while the app is running, but are not saved to disk.
- `Get()` returns `false` if the key does not exist or the type does not match.
Example:
```angelscript
Globals::Set("difficulty", 2);
Globals::Set("player_name", "Nina");
int diff = 0;
string name;
if (Globals::Get("difficulty", diff)) {
Print("difficulty=" + diff);
}
if (Globals::Get("player_name", name)) {
Print("player=" + name);
}
```
## Examples
- `scripts/game.as` — demo showing ECS usage, rendering, scenegraph and input actions.
+8
View File
@@ -52,6 +52,14 @@ ctest --test-dir build --output-on-failure
- The engine watches the scripts directory and will hot-reload scripts when changed.
- Predefined API is declared in `scripts/as.predefined`.
## Filesystem / Writable Data
- `user/` is the only writable directory in runtime mode.
- In editor mode (`--editor`), scene files in `scenes/` and the asset registry at
`assets/registry.toml` are writable.
- Scene saves are blocked outside editor mode.
- Logs are written to `user/log.txt`.
## Documentation & Wiki
Docs source lives in the `docs/` folder. The repository contains a CI workflow and a local script to mirror `docs/` to the Gitea wiki.
Vendored Submodule
+1
Submodule external/snkv added at a9370019a7
+3 -3
View File
@@ -21,7 +21,7 @@ Collapsed=0
DockId=0x00000002,0
[Window][##TOAST0]
Pos=1035,637
Pos=1609,928
Size=225,63
Collapsed=0
@@ -31,12 +31,12 @@ Size=225,63
Collapsed=0
[Window][##TOAST2]
Pos=1035,491
Pos=1675,814
Size=225,63
Collapsed=0
[Window][##TOAST3]
Pos=1675,741
Pos=1035,418
Size=225,63
Collapsed=0
+1
View File
@@ -18,6 +18,7 @@ void ClearSearchPath();
bool SetWriteDir(const std::string& path);
bool EnsureDir(const std::string& path);
void SetEditorEnabled(bool enabled);
bool Exists(const std::string& path);
bool IsDirectory(const std::string& path);
+5
View File
@@ -0,0 +1,5 @@
#pragma once
class asIScriptEngine;
void RegisterGlobalsBindings(asIScriptEngine* engine);
+5
View File
@@ -0,0 +1,5 @@
#pragma once
class asIScriptEngine;
void RegisterSNKVBindings(asIScriptEngine* engine);
+13 -16
View File
@@ -11,31 +11,29 @@ rotation_deg = [0.000, 0.000, 0.000]
id = "entity_2"
parent = "entity_1"
tag = "Parent"
position = [2.000, -1.555, 0.000]
position = [2.000, -1.100, 0.000]
scale = [1.000, 1.000, 1.000]
rotation_deg = [0.000, 0.000, 0.000]
model_asset = "Torus"
model_id = 2
model_id = 1
color = 0x00FF00FF
outline_size = 0.000
shader_vs = "shaders/toon.vs"
shader_fs = "shaders/toon.fs"
script = "scripts/ball.as"
script_var_phase = "0.000000"
script_var_speed = "0.699000"
script_var_amplitude = "1.748000"
script_var_speed = "0.699000"
script_var_phase = "0.000000"
[[entity]]
id = "entity_3"
parent = "entity_2"
tag = "Child"
position = [0.500, -3.100, 1.600]
position = [0.500, -2.175, 1.600]
scale = [0.600, 0.600, 0.600]
rotation_deg = [0.000, 0.000, 0.000]
model = "sphere"
radius = 0.500
rings = 16
slices = 16
model_asset = "Torus"
model_id = 1
color = 0xFF0000FF
outline_size = 0.000
shader_vs = "shaders/toon.vs"
@@ -47,19 +45,18 @@ script_var_amplitude = "1.452000"
id = "entity_6"
parent = "entity_2"
tag = "Child 2"
position = [0.000, 0.351, 1.900]
position = [0.000, 0.871, 1.900]
scale = [1.000, 1.000, 1.000]
rotation_deg = [0.000, 0.000, 0.000]
model = "sphere"
radius = 0.500
rings = 16
slices = 16
model_asset = "demo_cube"
model = "cube"
model_size = [1.000, 1.000, 1.000]
color = 0x4523BAFF
outline_size = 0.000
shader_vs = "shaders/toon.vs"
shader_fs = "shaders/toon.fs"
script = "scripts/ball.as"
script_var_amplitude = "0.568000"
script_var_phase = "0.472000"
script_var_speed = "10.000000"
script_var_phase = "0.472000"
script_var_amplitude = "0.568000"
+64
View File
@@ -263,6 +263,70 @@ namespace MouseButton {
const int MIDDLE = 2;
}
// Key-value store (SNKV)
namespace KV {
uint Open(const string &in name);
bool Close(uint handle);
bool Put(uint handle, const string &in key, const string &in value);
bool Put(uint handle, const string &in key, int value);
bool Put(uint handle, const string &in key, uint value);
bool Put(uint handle, const string &in key, int64 value);
bool Put(uint handle, const string &in key, float value);
bool Put(uint handle, const string &in key, double value);
bool Put(uint handle, const string &in key, bool value);
bool Put(uint handle, const string &in key, const array<uint8> &in value);
bool PutTtl(uint handle, const string &in key, const string &in value, int64 ttlMs);
bool PutTtl(uint handle, const string &in key, int value, int64 ttlMs);
bool PutTtl(uint handle, const string &in key, uint value, int64 ttlMs);
bool PutTtl(uint handle, const string &in key, int64 value, int64 ttlMs);
bool PutTtl(uint handle, const string &in key, float value, int64 ttlMs);
bool PutTtl(uint handle, const string &in key, double value, int64 ttlMs);
bool PutTtl(uint handle, const string &in key, bool value, int64 ttlMs);
bool PutTtl(uint handle, const string &in key, const array<uint8> &in value, int64 ttlMs);
bool Get(uint handle, const string &in key, string &out value);
bool Get(uint handle, const string &in key, int &out value);
bool Get(uint handle, const string &in key, uint &out value);
bool Get(uint handle, const string &in key, int64 &out value);
bool Get(uint handle, const string &in key, float &out value);
bool Get(uint handle, const string &in key, double &out value);
bool Get(uint handle, const string &in key, bool &out value);
bool Get(uint handle, const string &in key, array<uint8> &out value);
bool GetTtl(uint handle, const string &in key, string &out value, int64 &out remainingMs);
bool GetTtl(uint handle, const string &in key, int &out value, int64 &out remainingMs);
bool GetTtl(uint handle, const string &in key, uint &out value, int64 &out remainingMs);
bool GetTtl(uint handle, const string &in key, int64 &out value, int64 &out remainingMs);
bool GetTtl(uint handle, const string &in key, float &out value, int64 &out remainingMs);
bool GetTtl(uint handle, const string &in key, double &out value, int64 &out remainingMs);
bool GetTtl(uint handle, const string &in key, bool &out value, int64 &out remainingMs);
bool GetTtl(uint handle, const string &in key, array<uint8> &out value, int64 &out remainingMs);
bool Delete(uint handle, const string &in key);
bool Exists(uint handle, const string &in key);
bool TtlRemaining(uint handle, const string &in key, int64 &out remainingMs);
int PurgeExpired(uint handle);
}
// In-memory globals (cross-scene, not persisted)
namespace Globals {
bool Set(const string &in key, const string &in value);
bool Set(const string &in key, int value);
bool Set(const string &in key, uint value);
bool Set(const string &in key, int64 value);
bool Set(const string &in key, float value);
bool Set(const string &in key, double value);
bool Set(const string &in key, bool value);
bool Set(const string &in key, const array<uint8> &in value);
bool Get(const string &in key, string &out value);
bool Get(const string &in key, int &out value);
bool Get(const string &in key, uint &out value);
bool Get(const string &in key, int64 &out value);
bool Get(const string &in key, float &out value);
bool Get(const string &in key, double &out value);
bool Get(const string &in key, bool &out value);
bool Get(const string &in key, array<uint8> &out value);
bool Has(const string &in key);
bool Remove(const string &in key);
}
namespace GamepadButton {
const int UNKNOWN = 0;
const int LEFT_FACE_UP = 1;
+6 -3
View File
@@ -2,8 +2,7 @@
// Runs before any scene/game script to configure input and preload resources.
void Autoload() {
// Pick the initial scene to load.
Scene::Load("scenes/demo.toml");
ClearAllActions();
@@ -36,5 +35,9 @@ void Autoload() {
BindGamepadAxis("move_left", 0, GamepadAxis::LEFT_X, 0.3f, true);
BindGamepadAxis("move_right", 0, GamepadAxis::LEFT_X, 0.3f, false);
// TODO: Preload assets and other config here.
// Pick the initial scene to load.
Scene::Load("scenes/demo.toml");
Globals::Set("demo_var",100);
}
+1
View File
@@ -40,6 +40,7 @@ class EntityScript
phase += dt;
float offset = Math::Sin(phase * speed + float(entity) * 0.1f) * amplitude;
ECS::SetPosition(entity, baseX, baseY + offset, baseZ);
ECS::SetRotationEuler(entity, 0.0f, phase * 50.0f * dt, 0.0f);
}
void Shutdown(uint entity)
+34 -4
View File
@@ -6,18 +6,48 @@ class SceneScript {
uint cube = 0;
float time = 0.0f;
bool highlight = false;
void Init() {
uint kvStore = KV::Open("demo_scene");
Log(LOG_INFO, "Demo scene script init");
int var;
if (Globals::Get("demo_var", var)) {
Log(LOG_INFO, "Loaded global variable 'demo_var' with value: " + var);
} else {
Log(LOG_INFO, "No global variable 'demo_var' found, starting fresh.");
var = 42;
}
Globals::Set("demo_var", var + 1);
int value;
string strValue;
if (KV::Get(kvStore, "int", value)) {
Log(LOG_INFO, "Loaded int value from KV store: " + value);
} else {
Log(LOG_INFO, "No int value found in KV store, starting fresh.");
value = 0;
}
if (KV::Get(kvStore, "str", strValue)) {
Log(LOG_INFO, "Loaded string value from KV store: " + strValue);
} else {
Log(LOG_INFO, "No string value found in KV store, starting fresh.");
strValue = "Hello, KV!";
}
cube = ECS::CreateEntity();
ECS::AddTransform(cube, 0.0f, 1.5f, 0.0f);
uint modelId = Asset::GetModelId("demo_cube");
ECS::AddTransform(cube, 0.0f, 2.5f, 0.0f);
uint modelId = Asset::GetModelId("demo2_cube");
if (modelId == 0) {
modelId = Asset::LoadCube("demo_cube", 1.0f, 1.0f, 1.0f);
modelId = Asset::LoadCube("demo2_cube", 1.0f, 1.0f, 1.0f);
}
ECS::AddModelRenderer(cube, int(modelId), 0xFFAA00FF, 0.0f);
ECS::AddTag(cube, "InputCube");
KV::Put(kvStore, "int", value+1);
KV::Put(kvStore, "str", strValue + " (updated " + value + ")");
var = 0;
if (Globals::Get("demo_var", var)) {
Log(LOG_INFO, "Updated global variable 'demo_var' to value: " + var);
}
}
void Shutdown() {
+32 -15
View File
@@ -12,6 +12,7 @@
#include <thread>
#include <cstring>
#include <cstdio>
#include <filesystem>
#include <entt.hpp>
#include "log/log.h"
@@ -24,7 +25,8 @@
const char *Application::WINDOW_TITLE = "Simian";
static const char* kAutoloadScriptFile = "scripts/autoload.as";
static const char* kAssetRegistryFile = "assets/registry.toml";
static const char* kLogFilePath = "log.txt";
static const char* kLogFilePath = "user/log.txt";
static const char* kPackageFile = "game.zip";
static void PhysFSLogCallback(log_Event* ev)
{
@@ -72,20 +74,6 @@ bool Application::Initialize(int argc, char *argv[])
return false;
}
PhysFSManager::SetWriteDir(".");
const char* mountDirs[] = {"scripts", "scenes", "assets", "shaders", "fonts", "textures", "models"};
for (const char* dir : mountDirs) {
PhysFSManager::MountPath(dir, dir, true);
}
logFile = PhysFSManager::OpenWrite(kLogFilePath);
if (logFile) {
log_add_callback(PhysFSLogCallback, logFile, LOG_TRACE);
}
SetTraceLogCallback(raylib_log);
enableEditor = false;
// Parse command-line arguments
@@ -97,6 +85,35 @@ bool Application::Initialize(int argc, char *argv[])
}
}
std::filesystem::create_directories("user/db");
PhysFSManager::SetEditorEnabled(enableEditor);
PhysFSManager::SetWriteDir(".");
PhysFSManager::MountPath("user", "user", true);
bool mountedPackage = false;
if (std::filesystem::exists(kPackageFile)) {
mountedPackage = PhysFSManager::MountPath(kPackageFile, "", true);
if (!mountedPackage) {
log_warn("Failed to mount package: %s", kPackageFile);
}
}
if (!mountedPackage) {
const char* mountDirs[] = {"scripts", "scenes", "assets", "shaders", "fonts", "textures", "models"};
for (const char* dir : mountDirs) {
PhysFSManager::MountPath(dir, dir, true);
}
}
logFile = PhysFSManager::OpenWrite(kLogFilePath);
if (logFile) {
log_add_callback(PhysFSLogCallback, logFile, LOG_TRACE);
}
SetTraceLogCallback(raylib_log);
// Initialize Raylib
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
InitWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE);
+100
View File
@@ -9,6 +9,50 @@
namespace PhysFSManager {
static bool g_initialized = false;
static bool g_editorEnabled = false;
static std::string NormalizePath(std::string path) {
std::replace(path.begin(), path.end(), '\\', '/');
while (path.rfind("./", 0) == 0) {
path.erase(0, 2);
}
while (!path.empty() && path.front() == '/') {
path.erase(path.begin());
}
return path;
}
static bool StartsWith(const std::string& value, const std::string& prefix) {
return value.size() >= prefix.size() && value.compare(0, prefix.size(), prefix) == 0;
}
static bool IsWriteAllowed(const std::string& rawPath) {
std::string path = NormalizePath(rawPath);
if (path.empty()) {
return false;
}
if (path.find("..") != std::string::npos) {
return false;
}
if (path == "user" || StartsWith(path, "user/")) {
return true;
}
if (!g_editorEnabled) {
return false;
}
if (path == "scenes" || StartsWith(path, "scenes/")) {
return true;
}
if (path == "assets" || path == "assets/registry.toml") {
return true;
}
return false;
}
static unsigned char* RaylibLoadFileDataCallback(const char* fileName, int* dataSize) {
if (!fileName || !dataSize) {
@@ -47,11 +91,49 @@ static unsigned char* RaylibLoadFileDataCallback(const char* fileName, int* data
return data;
}
static char* RaylibLoadFileTextCallback(const char* fileName) {
if (!fileName) {
return nullptr;
}
PHYSFS_File* file = PHYSFS_openRead(fileName);
if (!file) {
return nullptr;
}
PHYSFS_sint64 length = PHYSFS_fileLength(file);
if (length <= 0 || length > static_cast<PHYSFS_sint64>(INT32_MAX)) {
PHYSFS_close(file);
return nullptr;
}
char* text = static_cast<char*>(MemAlloc(static_cast<size_t>(length) + 1));
if (!text) {
PHYSFS_close(file);
return nullptr;
}
PHYSFS_sint64 read = PHYSFS_readBytes(file, text, length);
PHYSFS_close(file);
if (read != length) {
MemFree(text);
return nullptr;
}
text[length] = '\0';
return text;
}
static bool RaylibSaveFileDataCallback(const char* fileName, void* data, int dataSize) {
if (!fileName || !data || dataSize <= 0) {
return false;
}
if (!IsWriteAllowed(fileName)) {
log_warn("PhysFS write blocked: %s", fileName);
return false;
}
PHYSFS_File* file = PHYSFS_openWrite(fileName);
if (!file) {
return false;
@@ -76,6 +158,7 @@ bool Initialize(const char* argv0) {
// Configure raylib to use PhysFS for all file reads/writes.
SetLoadFileDataCallback(RaylibLoadFileDataCallback);
SetLoadFileTextCallback(RaylibLoadFileTextCallback);
SetSaveFileDataCallback(RaylibSaveFileDataCallback);
g_initialized = true;
@@ -136,11 +219,20 @@ bool SetWriteDir(const std::string& path) {
return true;
}
void SetEditorEnabled(bool enabled) {
g_editorEnabled = enabled;
}
bool EnsureDir(const std::string& path) {
if (path.empty()) {
return true;
}
if (!IsWriteAllowed(path)) {
log_warn("PhysFS mkdir blocked: %s", path.c_str());
return false;
}
std::string normalized = path;
std::replace(normalized.begin(), normalized.end(), '\\', '/');
@@ -223,6 +315,10 @@ bool ReadTextFile(const std::string& path, std::string& out) {
}
bool WriteTextFile(const std::string& path, const std::string& contents) {
if (!IsWriteAllowed(path)) {
log_warn("PhysFS write blocked: %s", path.c_str());
return false;
}
PHYSFS_File* file = PHYSFS_openWrite(path.c_str());
if (!file) {
return false;
@@ -238,6 +334,10 @@ PHYSFS_File* OpenRead(const std::string& path) {
}
PHYSFS_File* OpenWrite(const std::string& path) {
if (!IsWriteAllowed(path)) {
log_warn("PhysFS write blocked: %s", path.c_str());
return nullptr;
}
return PHYSFS_openWrite(path.c_str());
}
+252
View File
@@ -0,0 +1,252 @@
#include "scripting/GlobalsBindings.h"
#include "scriptarray.h"
#include <angelscript.h>
#include <cassert>
#include <cstdint>
#include <string>
#include <unordered_map>
#include <variant>
#include <vector>
namespace {
enum class ValueType {
String,
Int,
UInt,
Int64,
Float,
Double,
Bool,
Bytes
};
using ValueData = std::variant<int, asUINT, int64_t, float, double, bool, std::string, std::vector<uint8_t>>;
struct Value {
ValueType type;
ValueData data;
};
std::unordered_map<std::string, Value> g_values;
std::vector<uint8_t> ArrayToBytes(const CScriptArray* value) {
std::vector<uint8_t> bytes;
if (!value) {
return bytes;
}
const asUINT size = value->GetSize();
bytes.resize(size);
for (asUINT i = 0; i < size; ++i) {
const uint8_t* element = static_cast<const uint8_t*>(value->At(i));
bytes[i] = *element;
}
return bytes;
}
bool BytesToArray(const std::vector<uint8_t>& bytes, CScriptArray* outValue) {
if (!outValue) {
return false;
}
outValue->Resize(static_cast<asUINT>(bytes.size()));
for (asUINT i = 0; i < outValue->GetSize(); ++i) {
*static_cast<uint8_t*>(outValue->At(i)) = bytes[i];
}
return true;
}
bool SetValue(const std::string& key, ValueType type, ValueData data) {
g_values[key] = Value{type, std::move(data)};
return true;
}
const Value* GetValue(const std::string& key, ValueType type) {
auto it = g_values.find(key);
if (it == g_values.end()) {
return nullptr;
}
if (it->second.type != type) {
return nullptr;
}
return &it->second;
}
bool AS_SetString(const std::string& key, const std::string& value) {
return SetValue(key, ValueType::String, value);
}
bool AS_SetInt(const std::string& key, int value) {
return SetValue(key, ValueType::Int, value);
}
bool AS_SetUInt(const std::string& key, asUINT value) {
return SetValue(key, ValueType::UInt, value);
}
bool AS_SetInt64(const std::string& key, int64_t value) {
return SetValue(key, ValueType::Int64, value);
}
bool AS_SetFloat(const std::string& key, float value) {
return SetValue(key, ValueType::Float, value);
}
bool AS_SetDouble(const std::string& key, double value) {
return SetValue(key, ValueType::Double, value);
}
bool AS_SetBool(const std::string& key, bool value) {
return SetValue(key, ValueType::Bool, value);
}
bool AS_SetArray(const std::string& key, const CScriptArray* value) {
return SetValue(key, ValueType::Bytes, ArrayToBytes(value));
}
bool AS_GetString(const std::string& key, std::string& outValue) {
const Value* value = GetValue(key, ValueType::String);
if (!value) {
return false;
}
outValue = std::get<std::string>(value->data);
return true;
}
bool AS_GetInt(const std::string& key, int& outValue) {
const Value* value = GetValue(key, ValueType::Int);
if (!value) {
return false;
}
outValue = std::get<int>(value->data);
return true;
}
bool AS_GetUInt(const std::string& key, asUINT& outValue) {
const Value* value = GetValue(key, ValueType::UInt);
if (!value) {
return false;
}
outValue = std::get<asUINT>(value->data);
return true;
}
bool AS_GetInt64(const std::string& key, int64_t& outValue) {
const Value* value = GetValue(key, ValueType::Int64);
if (!value) {
return false;
}
outValue = std::get<int64_t>(value->data);
return true;
}
bool AS_GetFloat(const std::string& key, float& outValue) {
const Value* value = GetValue(key, ValueType::Float);
if (!value) {
return false;
}
outValue = std::get<float>(value->data);
return true;
}
bool AS_GetDouble(const std::string& key, double& outValue) {
const Value* value = GetValue(key, ValueType::Double);
if (!value) {
return false;
}
outValue = std::get<double>(value->data);
return true;
}
bool AS_GetBool(const std::string& key, bool& outValue) {
const Value* value = GetValue(key, ValueType::Bool);
if (!value) {
return false;
}
outValue = std::get<bool>(value->data);
return true;
}
bool AS_GetArray(const std::string& key, CScriptArray* outValue) {
const Value* value = GetValue(key, ValueType::Bytes);
if (!value) {
return false;
}
return BytesToArray(std::get<std::vector<uint8_t>>(value->data), outValue);
}
bool AS_Has(const std::string& key) {
return g_values.find(key) != g_values.end();
}
bool AS_Remove(const std::string& key) {
return g_values.erase(key) > 0;
}
} // namespace
void RegisterGlobalsBindings(asIScriptEngine* engine) {
int r;
engine->SetDefaultNamespace("Globals");
r = engine->RegisterGlobalFunction("bool Set(const string &in key, const string &in value)",
asFUNCTION(AS_SetString), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("bool Set(const string &in key, int value)",
asFUNCTION(AS_SetInt), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("bool Set(const string &in key, uint value)",
asFUNCTION(AS_SetUInt), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("bool Set(const string &in key, int64 value)",
asFUNCTION(AS_SetInt64), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("bool Set(const string &in key, float value)",
asFUNCTION(AS_SetFloat), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("bool Set(const string &in key, double value)",
asFUNCTION(AS_SetDouble), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("bool Set(const string &in key, bool value)",
asFUNCTION(AS_SetBool), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("bool Set(const string &in key, const array<uint8> &in value)",
asFUNCTION(AS_SetArray), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("bool Get(const string &in key, string &out value)",
asFUNCTION(AS_GetString), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("bool Get(const string &in key, int &out value)",
asFUNCTION(AS_GetInt), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("bool Get(const string &in key, uint &out value)",
asFUNCTION(AS_GetUInt), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("bool Get(const string &in key, int64 &out value)",
asFUNCTION(AS_GetInt64), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("bool Get(const string &in key, float &out value)",
asFUNCTION(AS_GetFloat), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("bool Get(const string &in key, double &out value)",
asFUNCTION(AS_GetDouble), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("bool Get(const string &in key, bool &out value)",
asFUNCTION(AS_GetBool), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("bool Get(const string &in key, array<uint8> &out value)",
asFUNCTION(AS_GetArray), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("bool Has(const string &in key)",
asFUNCTION(AS_Has), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("bool Remove(const string &in key)",
asFUNCTION(AS_Remove), asCALL_CDECL);
assert(r >= 0);
engine->SetDefaultNamespace("");
}
File diff suppressed because it is too large Load Diff
+4
View File
@@ -9,6 +9,8 @@
#include "scripting/InputBindings.h"
#include "scripting/SceneBindings.h"
#include "scripting/PhysFSBindings.h"
#include "scripting/SNKVBindings.h"
#include "scripting/GlobalsBindings.h"
void ScriptBindings::RegisterAll(asIScriptEngine *engine)
{
@@ -23,4 +25,6 @@ void ScriptBindings::RegisterAll(asIScriptEngine *engine)
RegisterInputBindings(engine);
RegisterSceneBindings(engine);
RegisterPhysFSBindings(engine);
RegisterSNKVBindings(engine);
RegisterGlobalsBindings(engine);
}
+1
View File
@@ -11,6 +11,7 @@ bool InitPhysFSTest(const std::filesystem::path& writeDir) {
g_initialized = true;
}
PhysFSManager::SetEditorEnabled(true);
PhysFSManager::SetWriteDir(writeDir.string());
return true;
}
+4 -3
View File
@@ -248,7 +248,7 @@ void test_resource_bindings_script(void) {
void test_asset_registry_material(void) {
std::filesystem::path tmpDir = std::filesystem::current_path() / "tmp_asset_registry";
std::filesystem::create_directories(tmpDir);
std::filesystem::path registryPath = tmpDir / "registry.toml";
std::filesystem::path registryPath = tmpDir / "assets" / "registry.toml";
TEST_CHECK(InitPhysFSTest(tmpDir) == true);
TEST_CHECK(MountPhysFSTest(tmpDir, "") == true);
@@ -261,7 +261,7 @@ void test_asset_registry_material(void) {
unsigned int materialId = assets.CreateMaterial("test_mat", 0, albedo);
TEST_CHECK(materialId != 0);
bool saved = assets.SaveRegistry("registry.toml");
bool saved = assets.SaveRegistry("assets/registry.toml");
TEST_CHECK(saved == true);
assets.Clear();
@@ -271,7 +271,7 @@ void test_asset_registry_material(void) {
AssetManager assetsReload;
assetsReload.SetManagers(nullptr, nullptr, &materialManagerReload, nullptr);
bool loaded = assetsReload.LoadRegistry("registry.toml");
bool loaded = assetsReload.LoadRegistry("assets/registry.toml");
TEST_CHECK(loaded == true);
unsigned int loadedId = assetsReload.GetMaterialId("test_mat");
@@ -288,5 +288,6 @@ void test_asset_registry_material(void) {
ShutdownPhysFSTest();
std::filesystem::remove(registryPath);
std::filesystem::remove(registryPath.parent_path());
std::filesystem::remove(tmpDir);
}
+4 -3
View File
@@ -265,7 +265,7 @@ void test_scene_loader_asset_keys(void) {
std::filesystem::path tmpDir = std::filesystem::current_path() / "tmp_scene_assets";
std::filesystem::create_directories(tmpDir);
std::filesystem::path registryPath = tmpDir / "registry.toml";
std::filesystem::path registryPath = tmpDir / "assets" / "registry.toml";
std::filesystem::path scenePath = tmpDir / "scene_asset.toml";
TEST_CHECK(InitPhysFSTest(tmpDir) == true);
@@ -278,7 +278,7 @@ void test_scene_loader_asset_keys(void) {
AssetManager assets;
assets.SetManagers(&modelManager, &shaderManager, nullptr, &textureManager);
assets.LoadCube("demo_cube", 1.0f, 1.0f, 1.0f);
assets.SaveRegistry("registry.toml");
assets.SaveRegistry("assets/registry.toml");
}
entt::registry registry;
@@ -288,7 +288,7 @@ void test_scene_loader_asset_keys(void) {
TextureManager textureManager;
AssetManager assets;
assets.SetManagers(&modelManager, &shaderManager, nullptr, &textureManager);
assets.LoadRegistry("registry.toml");
assets.LoadRegistry("assets/registry.toml");
SetSceneContext(&registry, &modelManager, &shaderManager, &textureManager);
SetSceneAssetManager(&assets);
@@ -335,6 +335,7 @@ void test_scene_loader_asset_keys(void) {
std::filesystem::remove(scenePath);
std::filesystem::remove(registryPath);
std::filesystem::remove(registryPath.parent_path());
std::filesystem::remove(tmpDir);
}