280 lines
7.6 KiB
Markdown
280 lines
7.6 KiB
Markdown
# stk (Stalwart Toolkit)
|
|
|
|
[](https://opensource.org/licenses/MPL-2.0)
|
|
|
|
`stk` is a lightweight, modular toolkit for building games and game engines. It provides a **portable foundation** for dynamically loading modules, native or WASM, without enforcing any architecture or design choices.
|
|
|
|
It is designed to run on modern systems running POSIX and Windows using C89.
|
|
|
|
---
|
|
|
|
## Key Features
|
|
|
|
- **Dynamic module loading** (native `.so` / `.dll` / `.dylib`)
|
|
- **Hot-swapping** of modules at runtime
|
|
- **Cross-platform** (Linux, BSD, Windows, macOS)
|
|
- **Optional WASM support** for multi-language modules (planned)
|
|
- **Developer tools**: lightweight metadata, logging/tracing, and dependency management (in progress)
|
|
- **Minimal, portable API**
|
|
|
|
---
|
|
|
|
## Philosophy
|
|
|
|
`stk` is **non-opinionated**: developers control architecture, engine design, and game logic while relying on a predictable, lean foundation.
|
|
|
|
See [docs/design.md](docs/design.md) for the full design philosophy and roadmap.
|
|
|
|
---
|
|
|
|
## Quick Start
|
|
|
|
### Building
|
|
|
|
```bash
|
|
# Unix (Linux/BSD/macOS)
|
|
./build.sh debug release
|
|
|
|
# Windows
|
|
build.bat debug release
|
|
```
|
|
|
|
### Installation
|
|
|
|
#### Unix (Linux/BSD/macOS)
|
|
```bash
|
|
sudo ./build.sh install
|
|
```
|
|
|
|
Installs to `/usr/local` by default. Use `PREFIX` to customize:
|
|
```bash
|
|
sudo ./build.sh PREFIX=$HOME/.local install
|
|
```
|
|
|
|
#### Windows
|
|
```
|
|
build.bat release
|
|
```
|
|
* Once finished building, copy the headers from `include/` to `your_project/include/stk/` and `bin/release/stk.dll` to your project's lib directory.
|
|
|
|
---
|
|
|
|
## Usage
|
|
|
|
### Basic Example
|
|
|
|
```c
|
|
#include <stk/stk.h>
|
|
#include <stdio.h>
|
|
|
|
int main(void)
|
|
{
|
|
int running = 1;
|
|
size_t events;
|
|
|
|
/* Initialize stk */
|
|
if (stk_init() != STK_INIT_SUCCESS) {
|
|
fprintf(stderr, "Failed to initialize stk\n");
|
|
return 1;
|
|
}
|
|
|
|
/* Main loop - poll for module changes */
|
|
while (running) {
|
|
events = stk_poll();
|
|
if (events > 0) {
|
|
printf("Detected %zu module event(s)\n", events);
|
|
}
|
|
|
|
/* Your game/application logic here */
|
|
}
|
|
|
|
/* Shutdown stk systems*/
|
|
stk_shutdown();
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
### Creating a Module
|
|
|
|
Modules are simple shared libraries with `stk_mod_init` and `stk_mod_shutdown` functions:
|
|
|
|
```c
|
|
/* my_module.c */
|
|
#include <stdio.h>
|
|
|
|
int stk_mod_init(void)
|
|
{
|
|
printf("Module loaded!\n");
|
|
return 0; /* Return 0 on success */
|
|
}
|
|
|
|
void stk_mod_shutdown(void)
|
|
{
|
|
printf("Module unloaded!\n");
|
|
}
|
|
```
|
|
|
|
Build as a shared library:
|
|
```bash
|
|
# Linux/BSD
|
|
cc -shared -fPIC -o my_module.so my_module.c
|
|
|
|
# macOS
|
|
cc -shared -fPIC -o my_module.dylib my_module.c
|
|
|
|
# Windows (MSVC)
|
|
cl /LD my_module.c /Fe:my_module.dll
|
|
|
|
# Windows (MinGW)
|
|
cc -shared -o my_module.dll my_module.c
|
|
```
|
|
|
|
Place the compiled module in the `mods/` directory (default), and `stk` will automatically load it and watch for changes.
|
|
|
|
### Module Metadata
|
|
|
|
Modules can optionally export metadata functions:
|
|
|
|
```c
|
|
const char *stk_mod_name(void) { return "My Module"; }
|
|
const char *stk_mod_version(void) { return "1.2.0"; }
|
|
const char *stk_mod_description(void) { return "Does something useful"; }
|
|
```
|
|
|
|
All three are optional. Version defaults to `0.0.0` if not exported or unparseable.
|
|
|
|
### Declaring Dependencies
|
|
|
|
Modules declare dependencies via an exported sentinel-terminated array. No stk headers are required in the module. The only requirement is that the memory layout matches: `{ char[64], char[32] }`.
|
|
|
|
```c
|
|
typedef struct {
|
|
char id[64];
|
|
char version[32];
|
|
} dep_t;
|
|
|
|
dep_t stk_mod_deps[] = {
|
|
{ "physics", ">=2.0.0" },
|
|
{ "renderer", "^1.0.0" },
|
|
{ "", "" } /* sentinel */
|
|
};
|
|
```
|
|
|
|
Version constraint operators:
|
|
- `=1.0.0` exact match
|
|
- `>=2.0.0` minimum version, also the default if no operator is specified
|
|
- `^1.0.0` same major, greater or equal minor/patch
|
|
|
|
If a dependency is removed at runtime, all affected modules are unloaded and queued. When the dependency comes back, they load automatically.
|
|
|
|
### Configuration
|
|
|
|
```c
|
|
/* Set custom module directory (default: "mods") */
|
|
stk_set_mod_dir("custom_mods");
|
|
|
|
/* Set custom temp directory name (default: ".tmp") */
|
|
stk_set_tmp_dir_name(".my_tmp");
|
|
|
|
/* Set custom init function name (default: "stk_mod_init") */
|
|
stk_set_module_init_fn("my_init");
|
|
|
|
/* Set custom shutdown function name (default: "stk_mod_shutdown") */
|
|
stk_set_module_shutdown_fn("my_shutdown");
|
|
|
|
/* Set function name to get module name (default: "stk_mod_name") */
|
|
stk_set_module_name_fn("my_mod_name");
|
|
|
|
/* Set function name to get module version (default: "stk_mod_version") */
|
|
stk_set_module_version_fn("my_mod_version");
|
|
|
|
/* Set function name to get module description (default: "stk_mod_description") */
|
|
stk_set_module_description_fn("my_mod_description");
|
|
|
|
/* Set deps array symbol name (default: "stk_mod_deps") */
|
|
stk_set_module_deps_sym("my_mod_deps");
|
|
|
|
/*
|
|
* All the above functions must be called before stk_init()
|
|
* if the defaults need to be changed.
|
|
*/
|
|
stk_init();
|
|
```
|
|
|
|
### API Reference
|
|
|
|
#### Initialization
|
|
- `unsigned char stk_init(void)` - Initialize stk, returns `STK_INIT_SUCCESS` on success
|
|
- `void stk_shutdown(void)` - Shutdown and cleanup all modules
|
|
|
|
#### Runtime
|
|
- `size_t stk_poll(void)` - Poll for module changes, returns number of events processed
|
|
- `size_t stk_module_count(void)` - Get number of currently loaded modules
|
|
|
|
#### Configuration
|
|
- `void stk_set_mod_dir(const char *path)` - Set module directory
|
|
- `void stk_set_tmp_dir_name(const char *name)` - Set temp directory name
|
|
- `void stk_set_module_init_fn(const char *name)` - Set module init function name
|
|
- `void stk_set_module_shutdown_fn(const char *name)` - Set module shutdown function name
|
|
- `void stk_set_module_name_fn(const char *name);` - Set module name function name
|
|
- `void stk_set_module_version_fn(const char *name);` - Set module version function name
|
|
- `void stk_set_module_description_fn(const char *name);` - Set module description function name
|
|
- `void stk_set_module_deps_sym(const char *name)` - Set module deps array symbol name (default: `stk_mod_deps`)
|
|
|
|
#### Logging
|
|
- `void stk_set_logging_enabled(unsigned char enabled)` - Enable/disable all logging
|
|
- `unsigned char stk_is_logging_enabled(void)` - Query logging state
|
|
- `void stk_set_log_output(FILE *fp)` - Set log output stream (default: stdout, NULL disables)
|
|
- `void stk_set_log_prefix(const char *prefix)` - Set log prefix (default: "stk")
|
|
- `void stk_set_log_level(stk_log_level_t level)` - Set minimum log level (default: INFO)
|
|
|
|
**Log Levels:** `STK_LOG_ERROR`, `STK_LOG_WARN`, `STK_LOG_INFO`, `STK_LOG_DEBUG`
|
|
|
|
---
|
|
|
|
## Project Status
|
|
|
|
**Current Version:** 1.0.0-pre.6
|
|
|
|
### What Works
|
|
- Cross-platform module loading and hot-reloading
|
|
- File watching (inotify/kqueue/FindFirstFile)
|
|
- Robust hot-reload even during extremely rapid file changes
|
|
- Enhanced logging with levels, timestamps, and filtering
|
|
- Runtime-configurable logging behavior
|
|
- Optional module metadata (name, version, description)
|
|
- Dependency declaration, validation, and versioning
|
|
- Detailed dependency failure logging (missing ids, version mismatches)
|
|
- Cascade unload when dependencies are removed
|
|
- Pending queue with automatic retry when deps become available
|
|
- Topological sort with cycle detection
|
|
|
|
### Phase 2
|
|
- WASM module support
|
|
|
|
See [CHANGELOG.md](CHANGELOG.md) for detailed release notes.
|
|
|
|
---
|
|
|
|
## Testing
|
|
|
|
Run the included test suite:
|
|
```bash
|
|
./build.sh test # Unix
|
|
build.bat test # Windows
|
|
```
|
|
|
|
The test will watch the `mods/` directory and report when modules are loaded, reloaded, or unloaded.
|
|
|
|
---
|
|
|
|
## License
|
|
|
|
Mozilla Public License 2.0 (MPL-2.0)
|
|
|
|
---
|
|
|
|
## Contributing
|
|
|
|
Contributions welcome! Please ensure code follows C89 standard and works across all supported platforms.
|