diff --git a/Cargo.lock b/Cargo.lock
index d9337383..7f799e98 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -234,6 +234,7 @@ dependencies = [
"iana-time-zone",
"js-sys",
"num-traits",
+ "serde",
"wasm-bindgen",
"windows-targets",
]
@@ -361,6 +362,41 @@ dependencies = [
"libc",
]
+[[package]]
+name = "darling"
+version = "0.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "dashmap"
version = "5.5.3"
@@ -368,7 +404,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
dependencies = [
"cfg-if",
- "hashbrown 0.14.0",
+ "hashbrown 0.14.1",
"lock_api",
"once_cell",
"parking_lot_core",
@@ -385,6 +421,9 @@ name = "deranged"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946"
+dependencies = [
+ "serde",
+]
[[package]]
name = "digest"
@@ -418,6 +457,12 @@ dependencies = [
"cfg-if",
]
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
[[package]]
name = "errno"
version = "0.3.3"
@@ -616,7 +661,7 @@ dependencies = [
"futures-sink",
"futures-util",
"http",
- "indexmap",
+ "indexmap 1.9.3",
"slab",
"tokio",
"tokio-util",
@@ -645,9 +690,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
-version = "0.14.0"
+version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
+checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12"
[[package]]
name = "headers"
@@ -685,6 +730,12 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
[[package]]
name = "hmac"
version = "0.12.1"
@@ -809,6 +860,12 @@ dependencies = [
"cc",
]
+[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
[[package]]
name = "idna"
version = "0.4.0"
@@ -827,6 +884,18 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
+ "serde",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.14.1",
+ "serde",
]
[[package]]
@@ -1033,6 +1102,7 @@ dependencies = [
"reqwest",
"serde",
"serde_json",
+ "serde_with",
"serial_test",
"sysinfo",
"tar",
@@ -1419,6 +1489,35 @@ dependencies = [
"serde",
]
+[[package]]
+name = "serde_with"
+version = "3.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ca3b16a3d82c4088f343b7480a93550b3eabe1a358569c2dfe38bbcead07237"
+dependencies = [
+ "base64",
+ "chrono",
+ "hex",
+ "indexmap 1.9.3",
+ "indexmap 2.0.2",
+ "serde",
+ "serde_json",
+ "serde_with_macros",
+ "time",
+]
+
+[[package]]
+name = "serde_with_macros"
+version = "3.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e6be15c453eb305019bfa438b1593c731f36a289a7853f7707ee29e870b3b3c"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "serial_test"
version = "2.0.0"
@@ -1597,8 +1696,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe"
dependencies = [
"deranged",
+ "itoa",
"serde",
"time-core",
+ "time-macros",
]
[[package]]
@@ -1607,6 +1708,15 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
+[[package]]
+name = "time-macros"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20"
+dependencies = [
+ "time-core",
+]
+
[[package]]
name = "tinyvec"
version = "1.6.0"
diff --git a/README.md b/README.md
index 2f9a0e7d..8b7b14b5 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,9 @@
+
[![All Contributors](https://img.shields.io/badge/all_contributors-13-orange.svg?style=flat-square)](#contributors-)
+
## Table of Contents
diff --git a/docker-compose.yml b/docker-compose.yml
index 713ce4e1..dd1a13e2 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -19,6 +19,12 @@ services:
AUTO_UPDATE: 1
AUTO_UPDATE_SCHEDULE: "0 1 * * *"
TYPE: Vanilla
+ DEBUG_MODE: 1
+ PRESET: "Hammer"
+ MODIFIERS: |
+ raids=muchmore
+ combat=hard
+ deathpenalty=casual
build:
context: .
dockerfile: ./Dockerfile.valheim
diff --git a/src/odin/Cargo.toml b/src/odin/Cargo.toml
index 074ac605..71760ea0 100644
--- a/src/odin/Cargo.toml
+++ b/src/odin/Cargo.toml
@@ -46,6 +46,7 @@ zip = { version = "0.6.3" }
fs_extra = "1.2.0"
glob = "0.3.0"
a2s = "0.5.2"
+serde_with = "3.3.0"
[dev-dependencies]
once_cell = "1"
diff --git a/src/odin/cli.rs b/src/odin/cli.rs
index e1e2b263..023b607d 100644
--- a/src/odin/cli.rs
+++ b/src/odin/cli.rs
@@ -9,8 +9,9 @@ pub struct Cli {
pub run_as_root: bool,
/// Make everything noisy but very helpful to identify issues.
- #[arg(long)]
- pub debug: bool,
+ /// This will enable debugging, you can use the env variable DEBUG_MODE to set this as well.
+ #[arg(long, env = "DEBUG_MODE", action = clap::ArgAction::Set)]
+ pub debug: String,
/// Will spit out the commands as if it were to run them but not really.
#[arg(short = 'r', long)]
@@ -52,6 +53,19 @@ pub enum Commands {
/// Sets the public state of the server, (Can be set with ENV variable PUBLIC)
#[arg(short = 'o', long, env = "PUBLIC")]
public: String,
+
+ /// Sets flag modifiers for launching the server, (Can be set with ENV variable MODIFIERS)
+ /// This should be comma separated with equal variables, e.g. "raids=none,combat=hard"
+ #[arg(long, env = "MODIFIERS")]
+ modifiers: Option,
+
+ /// Sets flag preset for launching the server, (Can be set with ENV variable PRESET)
+ #[arg(long, env = "PRESET")]
+ preset: Option,
+
+ /// Sets flag set_key for launching the server, (Can be set with ENV variable SET_KEY)
+ #[arg(long, env = "SET_KEY")]
+ set_key: Option,
},
/// Installs Valheim with steamcmd
diff --git a/src/odin/commands/configure.rs b/src/odin/commands/configure.rs
index 274de022..530d29c6 100644
--- a/src/odin/commands/configure.rs
+++ b/src/odin/commands/configure.rs
@@ -2,17 +2,61 @@ use crate::files::config::{config_file, write_config};
use crate::files::discord::{discord_file, write_discord};
use log::debug;
+use serde::{Deserialize, Serialize};
+
+/// See: https://user-images.githubusercontent.com/34519392/273088066-b9c94664-9eef-419d-999a-8b8798462dee.PNG
+/// for a list of modifiers
+#[derive(Deserialize, Serialize, Debug)]
+pub struct Modifiers {
+ /// The name of the modifier
+ pub name: String,
+
+ /// The value of the modifier
+ pub value: String,
+}
+
+impl From for Modifiers {
+ /// Creates a new modifier from a string
+ fn from(value: String) -> Self {
+ let mut split = value.split('=');
+ let name = split.next().unwrap().to_string();
+ let value = split.next().unwrap().to_string();
+ Modifiers { name, value }
+ }
+}
pub struct Configuration {
+ /// Sets the name of the server, (Can be set with ENV variable NAME)
pub name: String,
+
+ /// Sets the servers executable path.
pub server_executable: String,
+
+ /// Sets the port of the server, (Can be set with ENV variable PORT)
pub port: u16,
+
+ /// Sets the world of the server, (Can be set with ENV variable WORLD)
pub world: String,
+
+ /// Sets the password of the server, (Can be set with ENV variable PASSWORD)
pub password: String,
+
+ /// Sets the public state of the server, (Can be set with ENV variable PUBLIC)
pub public: bool,
+
+ /// Sets flag preset for launching the server, (Can be set with ENV variable PRESET)
+ pub preset: Option,
+
+ /// Sets flag modifiers for launching the server, (Can be set with ENV variable MODIFIERS)
+ pub modifiers: Option>,
+
+ /// Sets flag set_key for launching the server, (Can be set with ENV variable SET_KEY)
+ pub set_key: Option,
}
impl Configuration {
+ /// Creates a new configuration
+ #[allow(clippy::too_many_arguments)]
pub fn new(
name: String,
server_executable: String,
@@ -20,6 +64,9 @@ impl Configuration {
world: String,
password: String,
public: bool,
+ preset: Option,
+ modifiers: Option>,
+ set_key: Option,
) -> Self {
Configuration {
name,
@@ -28,8 +75,13 @@ impl Configuration {
world,
password,
public,
+ preset,
+ modifiers,
+ set_key,
}
}
+
+ /// Invokes the configuration by writing the config file
pub fn invoke(self) {
debug!("Pulling config file...");
let config = config_file();
diff --git a/src/odin/files/config.rs b/src/odin/files/config.rs
index e05848f9..2fb2382b 100644
--- a/src/odin/files/config.rs
+++ b/src/odin/files/config.rs
@@ -1,4 +1,4 @@
-use crate::commands::configure::Configuration;
+use crate::commands::configure::{Configuration, Modifiers};
use crate::files::{FileManager, ManagedFile};
use crate::traits::AsOneOrZero;
use crate::utils::environment::fetch_var;
@@ -9,17 +9,41 @@ use std::{fs, path::PathBuf, process::exit};
const ODIN_CONFIG_FILE_VAR: &str = "ODIN_CONFIG_FILE";
-#[derive(Deserialize, Serialize)]
+#[derive(Deserialize, Serialize, Debug)]
pub struct ValheimArguments {
+ /// The port of the server, (Can be set with ENV variable PORT)
pub(crate) port: String,
+
+ /// The name of the server, (Can be set with ENV variable NAME)
pub(crate) name: String,
+
+ /// The world of the server, (Can be set with ENV variable WORLD)
pub(crate) world: String,
+
+ /// The public state of the server, (Can be set with ENV variable PUBLIC)
pub(crate) public: String,
+
+ /// The password of the server, (Can be set with ENV variable PASSWORD)
pub(crate) password: String,
+
+ /// The command to launch the server
pub(crate) command: String,
+
+ /// The preset for launching the server, (Can be set with ENV variable PRESET)
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub(crate) preset: Option,
+
+ /// The modifiers for launching the server, (Can be set with ENV variable MODIFIERS)
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub(crate) modifiers: Option>,
+
+ /// The set_key for launching the server, (Can be set with ENV variable SET_KEY)
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub(crate) set_key: Option,
}
impl From for ValheimArguments {
+ /// Creates a new ValheimArguments from a Configuration
fn from(value: Configuration) -> Self {
let command = match fs::canonicalize(PathBuf::from(value.server_executable)) {
Ok(command_path) => command_path.to_str().unwrap().to_string(),
@@ -36,10 +60,14 @@ impl From for ValheimArguments {
public: value.public.as_string(),
password: value.password,
command,
+ preset: value.preset,
+ modifiers: value.modifiers,
+ set_key: value.set_key,
}
}
}
+/// Loads the configuration from the config file
pub fn load_config() -> ValheimArguments {
let file = config_file();
let config = read_config(file);
@@ -52,12 +80,14 @@ pub fn load_config() -> ValheimArguments {
config
}
+/// Creates a new config file
pub fn config_file() -> ManagedFile {
let name = fetch_var(ODIN_CONFIG_FILE_VAR, "config.json");
debug!("Config file set to: {}", name);
ManagedFile { name }
}
+/// Reads the config file
pub fn read_config(config: ManagedFile) -> ValheimArguments {
let content = config.read();
if content.is_empty() {
@@ -66,6 +96,7 @@ pub fn read_config(config: ManagedFile) -> ValheimArguments {
serde_json::from_str(content.as_str()).unwrap()
}
+/// Writes the config file
pub fn write_config(config: ManagedFile, args: Configuration) -> bool {
let content = ValheimArguments::from(args);
diff --git a/src/odin/main.rs b/src/odin/main.rs
index d2045aa6..49f19fc3 100644
--- a/src/odin/main.rs
+++ b/src/odin/main.rs
@@ -1,4 +1,6 @@
+use crate::commands::configure::Modifiers;
use clap::Parser;
+use commands::configure::Configuration;
use dotenv::dotenv;
use log::debug;
@@ -40,13 +42,26 @@ fn main() {
server_executable,
world,
port,
- } => commands::configure::Configuration::new(
+ modifiers,
+ preset,
+ set_key,
+ } => Configuration::new(
name,
server_executable,
port,
world,
password,
{ public.eq("1") }.to_owned(),
+ preset,
+ {
+ modifiers.map(|modifiers| {
+ modifiers
+ .split(',')
+ .map(|modifier| Modifiers::from(modifier.to_string()))
+ .collect()
+ })
+ },
+ set_key,
)
.invoke(),
Commands::Install {} => handle_exit_status(
diff --git a/src/odin/server/startup.rs b/src/odin/server/startup.rs
index 2ff7faaa..bde1463b 100644
--- a/src/odin/server/startup.rs
+++ b/src/odin/server/startup.rs
@@ -35,7 +35,7 @@ pub fn start_daemonized(config: ValheimArguments) -> Result CommandResult {
format!("{}/linux64", game_directory()).as_str(),
);
debug!(target: "server_startup","Setting up base command");
+ debug!(target: "server_startup","Launching With Args: \n{:#?}", &config);
let mut base_command = command
// Extra launch arguments
.arg(fetch_var(
@@ -69,7 +70,27 @@ pub fn start(config: &ValheimArguments) -> CommandResult {
"-public",
config.public.as_str(),
])
- .env("SteamAppId", environment::fetch_var("APPID", "892970"))
+ .arg(if let Some(set_key) = &config.set_key {
+ format!("-setkey {}", set_key)
+ } else {
+ String::new()
+ })
+ .arg(if let Some(preset) = &config.preset {
+ format!("-preset {}", preset)
+ } else {
+ String::new()
+ })
+ .arg(if let Some(modifiers) = &config.modifiers {
+ modifiers
+ .iter()
+ .map(|modifier| format!("-modifier {} {}", modifier.name, modifier.value))
+ .collect::>()
+ .join(" ")
+ .to_string()
+ } else {
+ String::new()
+ })
+ .env("SteamAppId", fetch_var("APPID", "892970"))
.current_dir(game_directory());
let is_public = config.public.eq("1");
diff --git a/src/scripts/entrypoint.sh b/src/scripts/entrypoint.sh
index f4547db5..f81d700f 100644
--- a/src/scripts/entrypoint.sh
+++ b/src/scripts/entrypoint.sh
@@ -68,6 +68,9 @@ setup_cron_env() {
ENABLE_CROSSPLAY=${ENABLE_CROSSPLAY:-"0"}
UPDATE_ON_STARTUP=${UPDATE_ON_STARTUP}
SERVER_EXTRA_LAUNCH_ARGS=${SERVER_EXTRA_LAUNCH_ARGS}
+ PRESET=${PRESET}
+ MODIFIERS=$(echo "${MODIFIERS}" | xargs echo -n | tr ' ' ',' | sed 's/,,/,/g')
+ SET_KEY=${SET_KEY}
WEBHOOK_URL=${WEBHOOK_URL:-""}
WEBHOOK_STATUS_SUCCESSFUL=${WEBHOOK_STATUS_SUCCESSFUL:-"1"}
diff --git a/src/scripts/start_valheim.sh b/src/scripts/start_valheim.sh
index bb4fdba1..d183a7da 100644
--- a/src/scripts/start_valheim.sh
+++ b/src/scripts/start_valheim.sh
@@ -90,6 +90,22 @@ log "World: ${WORLD}"
log "Public: ${PUBLIC}"
log "With Crossplay: ${ENABLE_CROSSPLAY}"
log "Password: (REDACTED)"
+log "Preset: ${PRESET}"
+log "Modifiers: ${MODIFIERS}"
+log "Set Key: ${SET_KEY}"
+log "Auto Update: ${AUTO_UPDATE}"
+log "Auto Backup: ${AUTO_BACKUP}"
+log "Auto Backup On Update: ${AUTO_BACKUP_ON_UPDATE}"
+log "Auto Backup On Shutdown: ${AUTO_BACKUP_ON_SHUTDOWN}"
+log "Auto Backup Pause With No Players: ${AUTO_BACKUP_PAUSE_WITH_NO_PLAYERS}"
+log "Auto Backup Pause With Players: ${AUTO_BACKUP_PAUSE_WITH_PLAYERS}"
+log "Auto Backup Remove Old: ${AUTO_BACKUP_REMOVE_OLD}"
+log "Auto Backup Days To Live: ${AUTO_BACKUP_DAYS_TO_LIVE}"
+log "Auto Backup Nice Level: ${AUTO_BACKUP_NICE_LEVEL}"
+log "Update On Startup: ${UPDATE_ON_STARTUP}"
+log "Mods: ${MODS}"
+line
+
export SteamAppId=${APPID:-892970}
diff --git a/test.sh b/test.sh
new file mode 100644
index 00000000..07ef268b
--- /dev/null
+++ b/test.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+
+
+export MODIFIERS="
+raids=muchmore
+combat=hard
+deathpenalty=casual
+"
+
+echo "${MODIFIERS}" | xargs echo -n | tr ' ' ',' | sed 's/,,/,/g'
\ No newline at end of file