Use template engine to build mod_data.lua
The string-building version became too complex to maintain properly.
This commit is contained in:
parent
b1ff69fa08
commit
d0e074ccce
5 changed files with 99 additions and 68 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -906,6 +906,7 @@ dependencies = [
|
|||
"futures",
|
||||
"lazy_static",
|
||||
"luajit2-sys",
|
||||
"minijinja",
|
||||
"nexusmods",
|
||||
"oodle",
|
||||
"path-slash",
|
||||
|
@ -2084,6 +2085,15 @@ version = "0.3.17"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "minijinja"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "208758577ef2c86cf5dd3e85730d161413ec3284e2d73b2ef65d9a24d9971bcb"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
|
|
|
@ -35,3 +35,4 @@ ansi-parser = "0.9.0"
|
|||
string_template = "0.2.1"
|
||||
luajit2-sys = { path = "../../lib/luajit2-sys", version = "*" }
|
||||
async-recursion = "1.0.5"
|
||||
minijinja = "1.0.10"
|
||||
|
|
27
crates/dtmm/assets/mod_data.lua.j2
Normal file
27
crates/dtmm/assets/mod_data.lua.j2
Normal file
|
@ -0,0 +1,27 @@
|
|||
return {
|
||||
{% for mod in mods %}
|
||||
{
|
||||
id = "{{ mod.id }}",
|
||||
name = "{{ mod.name }}",
|
||||
bundled = {{ mod.bundled }},
|
||||
packages = {
|
||||
{% for pkg in mod.packages %}
|
||||
"{{ pkg }}",
|
||||
{% endfor %}
|
||||
},
|
||||
run = function()
|
||||
{% if mod.data is none %}
|
||||
return dofile("{{ mod.init }}")
|
||||
{% else %}
|
||||
new_mod("{{ mod.id }}", {
|
||||
mod_script = "{{ mod.init }}",
|
||||
mod_data = "{{ mod.data }}",
|
||||
{% if not mod.localization is none %}
|
||||
mod_localization = "{{ mod.localization }}",
|
||||
{% endif %}
|
||||
})
|
||||
{% endif %}
|
||||
end,
|
||||
},
|
||||
{% endfor %}
|
||||
}
|
|
@ -61,14 +61,14 @@ local function patch_mod_loading_state()
|
|||
if state == "load_package" and package_manager:update() then
|
||||
log("StateBootLoadMods", "Packages loaded, loading mods")
|
||||
self._state = "load_mods"
|
||||
local ModLoader = require("scripts/mods/dml/init")
|
||||
local DML = require("scripts/mods/dml/init")
|
||||
|
||||
local mod_data = require("scripts/mods/mod_data")
|
||||
local mod_loader = ModLoader:new(mod_data, self._parent:gui())
|
||||
local mod_loader = DML.create_loader(mod_data, self._parent:gui())
|
||||
|
||||
self._mod_loader = mod_loader
|
||||
self._dml = DML
|
||||
Managers.mod = mod_loader
|
||||
elseif state == "load_mods" and self._mod_loader:update(dt) then
|
||||
elseif state == "load_mods" and self._dml.update(Managers.mod, dt) then
|
||||
log("StateBootLoadMods", "Mods loaded, exiting")
|
||||
return true, false
|
||||
end
|
||||
|
@ -112,7 +112,7 @@ local require_store = {}
|
|||
-- This token is treated as a string template and filled by DTMM during deployment.
|
||||
-- This allows hiding unsafe I/O functions behind a setting.
|
||||
-- It's also a valid table definition, thereby degrading gracefully when not replaced.
|
||||
local is_io_enabled = { { is_io_enabled } } -- luacheck: ignore 113
|
||||
local is_io_enabled = {{ is_io_enabled }} -- luacheck: ignore 113
|
||||
local lua_libs = {
|
||||
debug = debug,
|
||||
os = {
|
||||
|
|
|
@ -8,7 +8,7 @@ use color_eyre::eyre::Context;
|
|||
use color_eyre::{eyre, Help, Report, Result};
|
||||
use futures::StreamExt;
|
||||
use futures::{stream, TryStreamExt};
|
||||
use path_slash::PathBufExt;
|
||||
use minijinja::Environment;
|
||||
use sdk::filetype::lua;
|
||||
use sdk::filetype::package::Package;
|
||||
use sdk::murmur::Murmur64;
|
||||
|
@ -201,10 +201,10 @@ async fn copy_recursive(
|
|||
async move {
|
||||
if is_dir {
|
||||
tracing::trace!("Creating directory '{}'", dest.display());
|
||||
fs::create_dir(&dest)
|
||||
.await
|
||||
.map(|_| ())
|
||||
.wrap_err_with(|| format!("Failed to create directory '{}'", dest.display()))
|
||||
// Instead of trying to filter "already exists" errors out explicitly,
|
||||
// we just ignore all. It'll fail eventually with the next copy operation.
|
||||
let _ = fs::create_dir(&dest).await;
|
||||
Ok(())
|
||||
} else {
|
||||
tracing::trace!("Copying file '{}' -> '{}'", path.display(), dest.display());
|
||||
fs::copy(&path, &dest).await.map(|_| ()).wrap_err_with(|| {
|
||||
|
@ -262,67 +262,60 @@ async fn copy_mod_folders(state: Arc<ActionState>) -> Result<Vec<String>> {
|
|||
Ok(ids)
|
||||
}
|
||||
|
||||
fn build_mod_data_lua(state: Arc<ActionState>) -> String {
|
||||
let mut lua = String::from("return {\n");
|
||||
|
||||
// DMF is handled explicitely by the loading procedures, as it actually drives most of that
|
||||
// and should therefore not show up in the load order.
|
||||
for mod_info in state.mods.iter().filter(|m| m.id != "dml" && m.enabled) {
|
||||
lua.push_str(" {\n name = \"");
|
||||
lua.push_str(&mod_info.name);
|
||||
|
||||
lua.push_str("\",\n id = \"");
|
||||
lua.push_str(&mod_info.id);
|
||||
|
||||
lua.push_str("\",\n bundled = \"");
|
||||
if mod_info.bundled {
|
||||
lua.push_str("true");
|
||||
} else {
|
||||
lua.push_str("false");
|
||||
fn build_mod_data_lua(state: Arc<ActionState>) -> Result<String> {
|
||||
#[derive(Serialize)]
|
||||
struct TemplateDataMod {
|
||||
id: String,
|
||||
name: String,
|
||||
bundled: bool,
|
||||
init: String,
|
||||
data: Option<String>,
|
||||
localization: Option<String>,
|
||||
packages: Vec<String>,
|
||||
}
|
||||
|
||||
lua.push_str("\",\n run = function()\n");
|
||||
let mut env = Environment::new();
|
||||
env.add_template("mod_data.lua", include_str!("../../assets/mod_data.lua.j2"))
|
||||
.wrap_err("Failed to compile template for `mod_data.lua`")?;
|
||||
let tmpl = env
|
||||
.get_template("mod_data.lua")
|
||||
.wrap_err("Failed to get template `mod_data.lua`")?;
|
||||
|
||||
let resources = &mod_info.resources;
|
||||
if resources.data.is_some() || resources.localization.is_some() {
|
||||
lua.push_str(" new_mod(\"");
|
||||
lua.push_str(&mod_info.id);
|
||||
lua.push_str("\", {\n mod_script = \"");
|
||||
lua.push_str(&resources.init.to_slash_lossy());
|
||||
|
||||
if let Some(data) = resources.data.as_ref() {
|
||||
lua.push_str("\",\n mod_data = \"");
|
||||
lua.push_str(&data.to_slash_lossy());
|
||||
let data: Vec<TemplateDataMod> = state
|
||||
.mods
|
||||
.iter()
|
||||
.filter_map(|m| {
|
||||
if m.id == "dml" || !m.enabled {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(localization) = &resources.localization {
|
||||
lua.push_str("\",\n mod_localization = \"");
|
||||
lua.push_str(&localization.to_slash_lossy());
|
||||
}
|
||||
Some(TemplateDataMod {
|
||||
id: m.id.clone(),
|
||||
name: m.name.clone(),
|
||||
bundled: m.bundled,
|
||||
init: m.resources.init.to_string_lossy().to_string(),
|
||||
data: m
|
||||
.resources
|
||||
.data
|
||||
.as_ref()
|
||||
.map(|p| p.to_string_lossy().to_string()),
|
||||
localization: m
|
||||
.resources
|
||||
.localization
|
||||
.as_ref()
|
||||
.map(|p| p.to_string_lossy().to_string()),
|
||||
packages: m.packages.iter().map(|p| p.name.clone()).collect(),
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
lua.push_str("\",\n })\n");
|
||||
} else {
|
||||
lua.push_str(" return dofile(\"");
|
||||
lua.push_str(&resources.init.to_slash_lossy());
|
||||
lua.push_str("\")\n");
|
||||
}
|
||||
let lua = tmpl
|
||||
.render(minijinja::context!(mods => data))
|
||||
.wrap_err("Failed to render template `mod_data.lua`")?;
|
||||
|
||||
lua.push_str(" end,\n packages = {\n");
|
||||
tracing::debug!("mod_data.lua:\n{}", lua);
|
||||
|
||||
for pkg_info in &mod_info.packages {
|
||||
lua.push_str(" \"");
|
||||
lua.push_str(&pkg_info.name);
|
||||
lua.push_str("\",\n");
|
||||
}
|
||||
|
||||
lua.push_str(" },\n },\n");
|
||||
}
|
||||
|
||||
lua.push('}');
|
||||
|
||||
tracing::debug!("mod_data_lua:\n{}", lua);
|
||||
|
||||
lua
|
||||
Ok(lua)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
|
@ -340,7 +333,7 @@ async fn build_bundles(state: Arc<ActionState>) -> Result<Vec<Bundle>> {
|
|||
let span = tracing::debug_span!("Building mod data script");
|
||||
let _enter = span.enter();
|
||||
|
||||
let lua = build_mod_data_lua(state.clone());
|
||||
let lua = build_mod_data_lua(state.clone()).wrap_err("Failed to build Lua mod data")?;
|
||||
|
||||
tracing::trace!("Compiling mod data script");
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue