You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# Modern Command Framework (MCF)
**MCF** is the next-generation command framework for Starfield, evolved from Custom Command Framework (CCF). Built with **libxe's updated CommonLibSF**, MCF provides a robust, modern API for registering custom console commands in Starfield.
## Features
✅ **Easy Command Registration** - Simple API for adding custom commands
✅ **Argument Parsing** - Automatic parsing with quote support
✅ **Console Integration** - Full integration with Starfield's console
✅ **Reference Selection** - Access to selected references
✅ **Form Lookup** - Hex string to form conversion
✅ **Modern C++** - Built with C++23 and modern standards
✅ **Updated CommonLibSF** - Using libxe's latest version
## What's New in MCF 2.0?
### From CCF to MCF
- **Updated Library**: Built on libxe's CommonLibSF instead of old version
- **No DKUtil Dependency**: Uses standard SFSE logging and hooking
- **Modern Build System**: Supports both CMake and xmake
- **Improved Performance**: Better memory management and faster command execution
- **Enhanced API**: Cleaner, more maintainable codebase
### Technical Improvements
1. **CommonLibSF Update**: Using libxe's updated version for better compatibility
2. **Removed DKUtil**: Direct SFSE integration for cleaner dependencies
3. **xmake Support**: Alternative build system for faster builds
4. **Better Logging**: Standard spdlog integration
5. **Code Quality**: Modern C++23 features and best practices
## Installation
### For End Users
1. Download `ModernCommandFramework.dll`
2. Place in `Data/SFSE/Plugins/`
3. Launch Starfield via SFSE
### For Mod Developers
To use MCF in your mod:
1. Copy `MCF_API.h` to your project
2. Include it: `#include "MCF_API.h"`
3. Register commands using the API
## API Usage
### Including MCF API
```cpp
#include "MCF_API.h"
```
### Registering a Command
```cpp
void MyCommandCallback(
const MCF::simple_array& args,
const char* fullString,
MCF::ConsoleInterface* console)
{
// Get selected reference
auto ref = console->GetSelectedReference();
if (!ref) {
console->PrintLn("No reference selected!");
return;
}
// Print to console
console->PrintLn("Command executed successfully!");
// Prevent default command text print
console->PreventDefaultPrint();
}
// In your plugin initialization
MCF::RegisterCommand("mycommand", MyCommandCallback);
```
### Console Interface
The `ConsoleInterface` provides these methods:
```cpp
class ConsoleInterface
{
public:
// Get currently selected reference in console
virtual RE::NiPointer GetSelectedReference() = 0;
// Convert hex string to form (e.g., "00000014" -> Player)
virtual RE::TESForm* HexStrToForm(const simple_string_view& str) = 0;
// Print a line to console
virtual void PrintLn(const simple_string_view& text) = 0;
// Prevent default "command text" from being printed
virtual void PreventDefaultPrint() = 0;
};
```
### Argument Handling
```cpp
void CommandWithArgs(
const MCF::simple_array& args,
const char* fullString,
MCF::ConsoleInterface* console)
{
if (args.size() < 1) {
console->PrintLn("Usage: mycommand [arg2]");
return;
}
// Access arguments (0-indexed, command name is removed)
std::string_view arg1 = args[0];
if (args.size() > 1) {
std::string_view arg2 = args[1];
// Handle second argument
}
// Arguments support quoted strings with spaces
// Example: mycommand "hello world" test
// args[0] = "hello world"
// args[1] = "test"
}
```
### Form Lookup Example
```cpp
void LookupFormCommand(
const MCF::simple_array& args,
const char* fullString,
MCF::ConsoleInterface* console)
{
if (args.size() < 1) {
console->PrintLn("Usage: lookup ");
return;
}
auto* form = console->HexStrToForm(args[0]);
if (!form) {
console->PrintLn("Invalid form ID!");
return;
}
auto name = form->GetName();
console->PrintLn(std::format("Found form: {}", name).c_str());
}
```
## Building from Source
### Prerequisites
- Visual Studio 2022 or later
- CMake 3.21+ OR xmake 2.7.0+
- libxe's updated CommonLibSF
- vcpkg (for CMake) or xrepo (for xmake)
### Building with CMake
```bash
# Configure
cmake --preset vs2022-windows
# Build
cmake --build build --config Release
```
### Building with xmake
```bash
# Configure and build
xmake
# Or for release build
xmake f -m release
xmake
# Install to Starfield
xmake install
# Create package
xmake package
```
### xmake Advantages
- **Faster builds**: Incremental compilation
- **Simpler configuration**: No generator needed
- **Built-in tasks**: install, package, clean
- **Better dependency management**: Integrated xrepo
## Project Structure
```
MCF/
├── src/
│ ├── MCF_API.h # Public API header
│ ├── Commands.h # Command system interface
│ ├── Commands.cpp # Command implementation
│ ├── PCH.h # Precompiled header
│ └── main.cpp # Plugin entry point
├── cmake/ # CMake configuration
├── CMakeLists.txt # CMake build file
├── xmake.lua # xmake build file
├── vcpkg.json # CMake dependencies
└── README.md # This file
```
## Command Registration Flow
1. **Your Plugin** calls `MCF::RegisterCommand(name, callback)`
2. **MCF** loads your command into registry
3. **User** types command in console
4. **MCF** intercepts console execution
5. **MCF** parses arguments and calls your callback
6. **Your Callback** executes with parsed arguments
7. **MCF** handles console output
## Examples
### Simple Command
```cpp
void HelloWorld(
const MCF::simple_array& args,
const char* fullString,
MCF::ConsoleInterface* console)
{
console->PrintLn("Hello, Starfield!");
}
// Register
MCF::RegisterCommand("hello", HelloWorld);
// Use in console
> hello
Hello, Starfield!
```
### Command with Selected Reference
```cpp
void GetRefInfo(
const MCF::simple_array& args,
const char* fullString,
MCF::ConsoleInterface* console)
{
auto ref = console->GetSelectedReference();
if (!ref) {
console->PrintLn("No reference selected!");
return;
}
auto* base = ref->GetBaseObject();
if (base) {
console->PrintLn(std::format(
"Name: {}",
base->GetName()
).c_str());
}
}
// Register
MCF::RegisterCommand("refinfo", GetRefInfo);
// Use in console (with reference selected)
> refinfo
Name: Container
```
### Command with Arguments
```cpp
void SetValue(
const MCF::simple_array& args,
const char* fullString,
MCF::ConsoleInterface* console)
{
if (args.size() < 2) {
console->PrintLn("Usage: setvalue ");
return;
}
auto* form = console->HexStrToForm(args[0]);
if (!form) {
console->PrintLn("Invalid form ID!");
return;
}
try {
int value = std::stoi(std::string{args[1]});
// Use the value...
console->PrintLn(std::format(
"Set value to {} for {}",
value,
form->GetName()
).c_str());
} catch (...) {
console->PrintLn("Invalid value!");
}
}
// Register
MCF::RegisterCommand("setvalue", SetValue);
// Use in console
> setvalue 00000014 100
Set value to 100 for Player
```
## Comparison: CCF vs MCF
| Feature | CCF 1.x | MCF 2.0 |
|---------|---------|---------|
| CommonLibSF | Old version | libxe's updated |
| Dependencies | DKUtil | None (SFSE only) |
| Build Systems | CMake only | CMake + xmake |
| Logging | DKUtil | spdlog |
| C++ Standard | C++20 | C++23 |
| API Name | CCF::* | MCF::* |
| DLL Name | CustomCommandFramework.dll | ModernCommandFramework.dll |
## Migration from CCF
### Code Changes
```cpp
// Old (CCF)
#include "CCF_API.h"
CCF::RegisterCommand("cmd", callback);
// New (MCF)
#include "MCF_API.h"
MCF::RegisterCommand("cmd", callback);
```
### Build Changes
1. Update include path: `CCF_API.h` → `MCF_API.h`
2. Update namespace: `CCF::` → `MCF::`
3. Link against `ModernCommandFramework.dll`
4. Optional: Switch to xmake for faster builds
### Runtime Changes
1. Remove `CustomCommandFramework.dll`
2. Install `ModernCommandFramework.dll`
3. Your commands work identically!
## FAQ
**Q: Is MCF compatible with CCF?**
A: At the API level, yes (just change namespaces). DLL-wise, they're separate frameworks.
**Q: Can I use both CCF and MCF?**
A: No, they both hook the same console function. Use one or the other.
**Q: Why xmake instead of CMake?**
A: xmake offers faster builds, simpler configuration, and better dependency management. CMake is still fully supported.
**Q: Do I need to rebuild my mod?**
A: Yes, you need to recompile against MCF headers and link to MCF DLL.
**Q: What about DKUtil?**
A: MCF doesn't use DKUtil. It uses standard SFSE and spdlog directly.
## Technical Details
### Hooking
MCF hooks the console's command execution function:
- **Address**: `REL::ID(166307), offset 0xD2`
- **Method**: Trampoline hook via SFSE
- **Behavior**: Intercepts before vanilla command processing
### Argument Parsing
- **Delimiter**: Space character
- **Quotes**: Supports `"quoted strings with spaces"`
- **Escaping**: Quote character as escape
- **Case**: Command names are case-insensitive
### Thread Safety
- **Registry**: Protected by `std::mutex`
- **Execution**: Single-threaded (console thread)
- **Callbacks**: Must be thread-safe if they spawn threads
## Performance
- **Registration**: O(1) hash map lookup
- **Execution**: ~0.1ms overhead per command
- **Memory**: ~1KB per registered command
- **Hooks**: Single trampoline hook (14 bytes)
## Limitations
- **Console Only**: Commands work only in console, not via scripts
- **Single Hook**: Only one framework can hook console at a time
- **No Persistence**: Commands must be re-registered each game launch
- **String Only**: Arguments are always strings (parse in your callback)
## Contributing
Contributions welcome! Please ensure:
- Code follows existing style
- All CCF references changed to MCF
- Works with libxe's CommonLibSF
- Tests pass (if applicable)
- Documentation updated
## Credits
- **Original CCF**: Deweh (Snapdragon)
- **MCF Development**: MCF Team
- **CommonLibSF**: libxe and contributors
- **SFSE**: SFSE Team
## License
MCF inherits the license from CCF. See LICENSE file for details.
## Support
For issues, questions, or feature requests:
- **GitHub Issues**: [Repository Link]
- **Discord**: [Community Server]
- **Nexus Mods**: [Mod Page]
---
**MCF**: Making console commands modern since 2026 🚀
Built with ❤️ and libxe's CommonLibSF
# ModernCommandFramework-
# ModernCommandFramework-
---
## Building (Linux → Windows cross-compile)
This fork adds an [xmake](https://xmake.io) build that cross-compiles the SFSE
plugin **from Linux** to a Windows x64 DLL, using `clang-cl` + `lld-link` +
`llvm-rc` against an [xwin](https://github.com/Jake-Shadle/xwin)/MSVC Windows SDK
tree (referenced here as `~/.vsxwin`).
```sh
# Provide the dependencies under extern/ first (see below), then:
xmake f -p windows -a x64 -m releasedbg --toolchain=clang-cl --sdk=$HOME/.vsxwin -y
xmake build
```
Output: `build/windows/x64/releasedbg/ModernCommandFramework.dll`.
Exports: `SFSEPlugin_Version`, `SFSEPlugin_Load`, `RegisterCommand`.
### Dependencies (not committed — `extern/` is git-ignored)
- `extern/commonlibsf/` — CommonLibSF (libxse fork, runtime 1.16.244.0) + nested
`commonlib-shared`, built from source. `spdlog` (v1.16.0, std_format + wchar) is
pulled transitively via xrepo.
`modules/detect/tools/find_rc.lua` (included) lets xmake locate an `rc` compiler on Linux.
## Credits
Original mod by **mielu91m** — .
This repository is a modified fork that adds the Linux cross-compile build system
above (and ports a few call sites to the current CommonLibSF API); all mod
functionality and design are the original author's work.
## License
Distributed under the MIT License — see [LICENSE](LICENSE).
About
Modern Command Framework (MCF) — a replacement for CCF (Custom Command Framework) for Starfield. SFSE plugin with a console-command registration API, cross-compiled from Linux. Fork of mielu91m's mod adding an xmake build.