Development of version 3.0.0 of SMF is now in progress. It might finish by the eâŚnd of the month, the end of the year or months from now. Perhaps it will never finish, but I'll do my best to avoid that.
As a new major version, it brings with it breaking changes to hopefully improve the SMF experience. Here's a summary of the changes made so far.
# Breaking Changes
## Update checking overhaul
Update URLs have been removed, in favour of a new top-level `url` key in the manifest. All mods must now specify a URL that links to their mod page. This link will be shown in the GUI and also used for mod update checking.
If the URL links to a page on Nexus Mods (`https://nexusmods.com/hitman3/mods/453`), users will be notified when the Nexus version changes, and will have to manually redownload the mod to receive updates. This means that while Nexus update checking is now possible, it's still better to use one of the alternative URLs which provide fully automatic updating.
If the URL links to a GitHub repository (`https://github.com/Notexe/Portable-Chair`), users will be notified of new releases (assuming the release is tagged with a version like `1.0.0` - no `v` at the start) and the framework will be able to automatically update the mod.
If the URL links to a ModWorkshop page (`https://modworkshop.net/mod/45444`), users will be notified of new releases and the framework will be able to automatically update the mod.
```diff
{
"id": "Notex.PortableChair",
- "updateCheck": "https://github.com/Notexe/Portable-Chair/releases/latest/download/updates.json"
+ "url": "https://github.com/Notexe/Portable-Chair"
}
```
## Framework data moved to `data` key
Properties like `contentFolders` and `localisation` have now been moved into the top-level `data` key (this applies to options as well, so the option now has a `data` key instead of directly having `contentFolders`).
```diff
{
"id": "Notex.PortableChair",
- "contentFolders": ["content"],
+ "data": {
+ "contentFolders": ["content"]
+ }
}
```
## Options overhaul
Mod options have been completely overhauled. The easiest way by far to understand the new options system will be through the use of a schema and an editor like VS Code, but here are the basics.
Options now require IDs. The ID can be anything (not including braces or colons), and there's no set convention currently (though there may be one on release).
Most options now have the ability to be referenced within content files. This is done through a simple find-and-replace. `"bla": "#{option:TheOptionID}"` will be transformed into `"bla": true` for a boolean option, or `"bla": 1` for a number, etc. If a find-and-replace is inside of a string, like `"bla": "something #{option:TheOptionID} something"`, it will be replaced inline, like `"bla": "something 1 something"`.
Option groups now exist, which are sections of options that can be displayed based on a condition (such as another option being on or off, or another mod being enabled).
Option tooltips have been replaced with descriptions, which may or may not be displayed differently, depending on how the GUI is ultimately designed.
## Removal of `thumbs`
The `thumbs` manifest key no longer exists. It was previously used to disable dynamic resources to make REPO mods work online. Instead, it has been replaced with a new boolean `disableDynamicResources` key which the framework will manage, and which users can choose to ignore.
## Rename of `dependencies` to `portedResources`
The old name didn't indicate what it actually did, which is port resources to a given chunk (usually `chunk0`).
## Mod ID version range syntax change
The `requirements`, `incompatibilities`, `loadBefore` and `loadAfter` keys accept specific version ranges for the referenced mods. The syntax for defining these has changed.
```diff
{
- "requirements": [
- ["SomeoneElse.TheirMod", "^1.3.1"]
- ],
+ "requirements": ["SomeoneElse.TheirMod@^1.3.1"]
}
```
## Packagedefinition changes
The `packagedefinition` key has been renamed to `packageDefinition` and support for custom partitions has been removed, meaning the `type` key in its entries has been removed as well (since it would always be `entity`).
## Condition changes and script overhaul
Scripts and conditions have both been changed to use the Rhai language. This means they are now fully sandboxed and therefore safe for users; the framework will no longer give a warning when scripts are used in a mod.
Conditions should now be formatted as Rhai expressions (`config.loadOrder.contains("Mod")` rather than `"Mod" in config.loadOrder`).
The script interface has changed significantly.
**Old**
```ts
export async function analysis()
export async function preDeploy()
export async function postDeploy()
export const cachePolicy
```
**New**
```rs
fn pre_analysis(config: Config, data: &mut ManifestData) -> ();
fn post_analysis(config: Config, data: ManifestData) -> Vec<(String, Operation)>;
```
The first function, `pre_analysis`, receives the config and the manifest data (after options have been merged into it), and has the opportunity to modify the manifest data. For example, it can add a content folder based on a complex condition. The second function, `post_analysis`, receives the same information but has the ability to return a series of `(String, Operation)` tuples.
The mention of `Operation` may be confusing. It's due to the revamp of framework internals, which will be talked about later.
## Removal of `delta` special file type
The `XYZ.delta` special file type has been removed due to it being largely useless and highly brittle to any change in the file. It was not used in any mod on the Nexus. There is no replacement.
# Improvements
So, you've heard all the reasons why the new update will be a headache for you (don't worry, this should actually all be automatically update-able by SMF on release, so you won't actually have a headache updating). What's the benefit? The framework has been completely redesigned.
## New programming language
If you're fond of programming, you've probably heard of Rust. Simply switching to idiomatic Rust should significantly improve both the speed of deploys and the quality and clarity of errors. It also reduces the file size of Deploy.exe by at least half.
## Graph model
The framework will no longer simply deploy mods one by one. All mods are now deployed, all at once. You might ask whether this impacts the load order functionality - load order is still respected because the framework now represents each deploy as a dependency graph.
Essentially, instead of deploying files, the framework now applies operations like `ApplyQNPatch` or `OverwriteMaterial` in parallel across a graph which represents deploy order as dependencies (a later mod in the order depends on an earlier mod's patches finishing in order to perform its patches).
This also allows for more granular caching of data (such as specific manifest keys rather than the whole manifest being re-deployed), which should further improve deployment speed. The framework will also now be able to store the whole cache in a single compressed file, instead of the multi-gigabyte folder it previously had.
This is also where those two functions from the script interface come in. An `Operation` is in effect a node in the dependency graph, and the `String` its ID. A mod which wants to apply a dynamically-built patch, for example, can return an `ApplyQNPatch` operation. The ID is used for caching, which is another thing the framework could not previously do for scripts.
## Safety
In addition to scripts now being safe, other improvements have been made. Internal framework data structures can no longer be constructed at all with invalid data, meaning that a manifest with an invalid path will now immediately throw an error with a clear message explaining why.
## Synthesis
The speed of deploys should be significantly improved in this version, and the framework should now use far less disk I/O.
Scripts should now be a usable tool for more advanced mod developers.
Errors are now far, far clearer.
![Error with backtrace, from new SMF](https://media.discordapp.net/attachments/899227305661050941/1169135437437206619/image.png?ex=65544d39&is=6541d839&hm=7de6214c01a6c085e36e1dcfd09f29bd72f6bef6ce634eb8d96bdc53944eabbc&=)
## A note on the GUI
The Mod Manager will also receive a redesign as part of this update. The details of this have not yet been worked out, but much of it should stay the same. The mod option interface will obviously be revamped, and the underlying technology will likely be switched to Tauri.
# So what?
This post has been made to ask for your feedback. If you have any issues with the ideas above, any ideas of your own, any new features you'd like to see added or any issues you have with current SMF, feel free to share below!
Also, polls will be running on some changes in the Glacier 2 Modding discord server, which you can join [here](https://discord.gg/6UDtuYhZP6). A poll is currently running regarding where manifest metadata should be stored.
# Other notes
If you'd like to play around with the current iteration of the new manifest format, you can use this [schema.json](https://github.com/atampy25/simple-mod-framework/files/13226993/test-manifest-schema.json) with VS Code or in an online editor.