[ALL] Add Prepatcher Warning

This commit is contained in:
Ben C 2023-05-13 18:55:59 -04:00
parent 19dfbb800a
commit 606f366d78
No known key found for this signature in database
GPG Key ID: 556064B755159BBC
9 changed files with 80 additions and 25 deletions

View File

@ -1,2 +1,4 @@
[alias] [alias]
xtask = "run --package xtask --" xtask = "run --package xtask --"
lint = "clippy --all-targets -- -D warnings"

View File

@ -306,12 +306,21 @@ async fn run_from_cli(cli: BaseCli) -> Result<()> {
Commands::Enable { unique_name } | Commands::Disable { unique_name } => { Commands::Enable { unique_name } | Commands::Disable { unique_name } => {
let db = LocalDatabase::fetch(&config.owml_path)?; let db = LocalDatabase::fetch(&config.owml_path)?;
let enable = matches!(cli.command, Commands::Enable { unique_name: _ }); let enable = matches!(cli.command, Commands::Enable { unique_name: _ });
let mut show_warnings_for: Vec<String> = vec![];
if unique_name == "*" || unique_name == "all" { if unique_name == "*" || unique_name == "all" {
for local_mod in db.valid() { for local_mod in db.valid() {
toggle_mod(&local_mod.manifest.unique_name, &db, enable, false)?; show_warnings_for.extend(toggle_mod(
&local_mod.manifest.unique_name,
&db,
enable,
false,
)?);
} }
} else { } else {
toggle_mod(unique_name, &db, enable, r)?; show_warnings_for = toggle_mod(unique_name, &db, enable, r)?;
}
for mod_name in show_warnings_for {
warn!("========\n{mod_name} possibly modified game files.\nIn order to disable it completely, use the \"verify game files\" option in Steam / Epic.\nCheck {mod_name}'s readme for more information.\n========")
} }
} }
Commands::LogServer { port } => { Commands::LogServer { port } => {

View File

@ -17,6 +17,12 @@ pub struct LocalMod {
pub manifest: ModManifest, pub manifest: ModManifest,
} }
impl LocalMod {
pub fn uses_pre_patcher(&self) -> bool {
self.manifest.patcher.is_some()
}
}
/// Represents a mod that completely failed to load /// Represents a mod that completely failed to load
#[typeshare] #[typeshare]
#[derive(Serialize, Clone)] #[derive(Serialize, Clone)]
@ -157,6 +163,7 @@ pub struct ModManifest {
pub conflicts: Option<Vec<String>>, pub conflicts: Option<Vec<String>>,
pub paths_to_preserve: Option<Vec<String>>, pub paths_to_preserve: Option<Vec<String>>,
pub warning: Option<ModWarning>, pub warning: Option<ModWarning>,
pub patcher: Option<String>,
} }
/// Represents a warning a mod wants to show to the user on start /// Represents a warning a mod wants to show to the user on start

View File

@ -56,6 +56,11 @@ pub fn get_mod_enabled(mod_path: &Path) -> Result<bool> {
/// Toggle a mod to a given enabled value. /// Toggle a mod to a given enabled value.
/// Also support applying this action recursively. /// Also support applying this action recursively.
/// ///
///
/// ## Returns
///
/// A list of mod names that were disabled and use pre patchers, and therefore **should alert the user to check the mod's README for instructions on how to fully disable it**.
///
/// ## Errors /// ## Errors
/// ///
/// If we can't read/save to the config files of the mod or (if recursive is true) any of it's dependents. /// If we can't read/save to the config files of the mod or (if recursive is true) any of it's dependents.
@ -65,19 +70,27 @@ pub fn toggle_mod(
local_db: &LocalDatabase, local_db: &LocalDatabase,
enabled: bool, enabled: bool,
recursive: bool, recursive: bool,
) -> Result<()> { ) -> Result<Vec<String>> {
let mut show_warnings_for: Vec<String> = vec![];
let local_mod = local_db let local_mod = local_db
.get_mod(unique_name) .get_mod(unique_name)
.ok_or_else(|| anyhow!("Mod {} not found", unique_name))?; .ok_or_else(|| anyhow!("Mod {} not found", unique_name))?;
let config_path = PathBuf::from(&local_mod.mod_path).join("config.json"); let config_path = PathBuf::from(&local_mod.mod_path).join("config.json");
if !enabled && local_mod.uses_pre_patcher() {
show_warnings_for.push(local_mod.manifest.name.clone());
}
if config_path.is_file() { if config_path.is_file() {
let mut config = read_config(&config_path)?; let mut config = read_config(&config_path)?;
config.enabled = enabled; config.enabled = enabled;
write_config(&config, &config_path)?; write_config(&config, &config_path)?;
} else { } else {
generate_config(&config_path)?; generate_config(&config_path)?;
toggle_mod(unique_name, local_db, enabled, recursive)?; show_warnings_for.extend(toggle_mod(unique_name, local_db, enabled, recursive)?);
} }
if recursive { if recursive {
if let Some(deps) = local_mod.manifest.dependencies.as_ref() { if let Some(deps) = local_mod.manifest.dependencies.as_ref() {
for dep in deps.iter() { for dep in deps.iter() {
@ -98,12 +111,12 @@ pub fn toggle_mod(
} }
} }
if flag { if flag {
toggle_mod( show_warnings_for.extend(toggle_mod(
&dep_mod.manifest.unique_name, &dep_mod.manifest.unique_name,
local_db, local_db,
enabled, enabled,
recursive, recursive,
)?; )?);
} }
} }
} else { } else {
@ -112,7 +125,7 @@ pub fn toggle_mod(
} }
} }
} }
Ok(()) Ok(show_warnings_for)
} }
#[cfg(test)] #[cfg(test)]

View File

@ -208,24 +208,25 @@ pub async fn toggle_mod(
unique_name: &str, unique_name: &str,
enabled: bool, enabled: bool,
state: tauri::State<'_, State>, state: tauri::State<'_, State>,
) -> Result { ) -> Result<Vec<String>> {
let db = state.local_db.read().await; let db = state.local_db.read().await;
owmods_core::toggle::toggle_mod(unique_name, &db, enabled, false)?; let show_warnings_for = owmods_core::toggle::toggle_mod(unique_name, &db, enabled, false)?;
Ok(()) Ok(show_warnings_for)
} }
#[tauri::command] #[tauri::command]
pub async fn toggle_all(enabled: bool, state: tauri::State<'_, State>) -> Result { pub async fn toggle_all(enabled: bool, state: tauri::State<'_, State>) -> Result<Vec<String>> {
let local_db = state.local_db.read().await; let local_db = state.local_db.read().await;
let mut show_warnings_for: Vec<String> = vec![];
for local_mod in local_db.valid() { for local_mod in local_db.valid() {
owmods_core::toggle::toggle_mod( show_warnings_for.extend(owmods_core::toggle::toggle_mod(
&local_mod.manifest.unique_name, &local_mod.manifest.unique_name,
&local_db, &local_db,
enabled, enabled,
false, false,
)?; )?);
} }
Ok(()) Ok(show_warnings_for)
} }
#[tauri::command] #[tauri::command]

View File

@ -77,6 +77,8 @@
"Outdated": "This mod is outdated, consider updating (latest version is v$payload$)", "Outdated": "This mod is outdated, consider updating (latest version is v$payload$)",
"PLATFORM": "Platform: $platform$", "PLATFORM": "Platform: $platform$",
"PRERELEASE_WARNING": "Prereleases are experimental versions of mods that may not work correctly. Are you sure you want to install?", "PRERELEASE_WARNING": "Prereleases are experimental versions of mods that may not work correctly. Are you sure you want to install?",
"PREPATCHER_WARNING": "$name$ possibly modified game files. In order to disable it completely, use the \"verify game files\" option in Steam / Epic. Check $name$'s readme for more information.",
"PREPATCHER_WARNING_TITLE": "Warning for $name$",
"Pink": "Pink", "Pink": "Pink",
"Purple": "Purple", "Purple": "Purple",
"RAINBOW": "Rainbow Mode", "RAINBOW": "Rainbow Mode",

View File

@ -37,8 +37,8 @@ const commandInfo = {
getLocalMod: $<ModCommand<UnsafeLocalMod>>("get_local_mod"), getLocalMod: $<ModCommand<UnsafeLocalMod>>("get_local_mod"),
getRemoteMod: $<ModCommand<RemoteMod>>("get_remote_mod"), getRemoteMod: $<ModCommand<RemoteMod>>("get_remote_mod"),
getLogLine: $<CommandInfo<{ port: number; line: number }, GameMessage>>("get_game_message"), getLogLine: $<CommandInfo<{ port: number; line: number }, GameMessage>>("get_game_message"),
toggleMod: $<ActionCommand<{ uniqueName: string; enabled: boolean }>>("toggle_mod"), toggleMod: $<CommandInfo<{ uniqueName: string; enabled: boolean }, string[]>>("toggle_mod"),
toggleAll: $<ActionCommand<{ enabled: boolean }>>("toggle_all"), toggleAll: $<CommandInfo<{ enabled: boolean }, string[]>>("toggle_all"),
openModFolder: $<ModAction>("open_mod_folder"), openModFolder: $<ModAction>("open_mod_folder"),
openModReadme: $<ModAction>("open_mod_readme"), openModReadme: $<ModAction>("open_mod_readme"),
uninstallMod: $<ModAction>("uninstall_mod"), uninstallMod: $<ModAction>("uninstall_mod"),

View File

@ -7,6 +7,7 @@ import ModValidationModal, {
import { useGetTranslation } from "@hooks"; import { useGetTranslation } from "@hooks";
import { memo, useCallback, useEffect, useRef, useState } from "react"; import { memo, useCallback, useEffect, useRef, useState } from "react";
import UnsafeModRow from "./UnsafeModRow"; import UnsafeModRow from "./UnsafeModRow";
import { dialog } from "@tauri-apps/api";
const LocalMods = memo(function LocalMods() { const LocalMods = memo(function LocalMods() {
const validationModalRef = useRef<ModValidationModalHandle>(); const validationModalRef = useRef<ModValidationModalHandle>();
@ -20,12 +21,23 @@ const LocalMods = memo(function LocalMods() {
commands.refreshLocalDb(); commands.refreshLocalDb();
}, []); }, []);
const onToggleAll = useCallback((enabled: boolean) => { const onToggleAll = useCallback(
commands (enabled: boolean) => {
.toggleAll({ enabled }) commands
.then(() => commands.refreshLocalDb()) .toggleAll({ enabled })
.catch(console.warn); .then((warnings) => {
}, []); commands.refreshLocalDb();
for (const modName of warnings) {
dialog.message(getTranslation("PREPATCHER_WARNING", { name: modName }), {
type: "warning",
title: getTranslation("PREPATCHER_WARNING_TITLE", { name: modName })
});
}
})
.catch(console.warn);
},
[getTranslation]
);
const onSearch = (newFilter: string) => { const onSearch = (newFilter: string) => {
if (activeTimeout !== null) { if (activeTimeout !== null) {

View File

@ -5,6 +5,7 @@ import { confirm } from "@tauri-apps/api/dialog";
import { LocalMod, ModValidationError } from "@types"; import { LocalMod, ModValidationError } from "@types";
import { memo, useCallback } from "react"; import { memo, useCallback } from "react";
import LocalModRow from "./LocalModRow"; import LocalModRow from "./LocalModRow";
import { dialog } from "@tauri-apps/api";
interface LocalModRowProps { interface LocalModRowProps {
mod: LocalMod; mod: LocalMod;
@ -45,9 +46,17 @@ const ValidModRow = memo(function ValidModRow({ mod, onValidationClick }: LocalM
uniqueName: mod.manifest.uniqueName, uniqueName: mod.manifest.uniqueName,
enabled: newVal enabled: newVal
}) })
.then(() => commands.refreshLocalDb()); .then((warnings) => {
commands.refreshLocalDb();
for (const modName of warnings) {
dialog.message(getTranslation("PREPATCHER_WARNING", { name: modName }), {
type: "warning",
title: getTranslation("PREPATCHER_WARNING_TITLE", { name: modName })
});
}
});
}, },
[mod.manifest.uniqueName] [mod.manifest.uniqueName, getTranslation]
); );
const onOpen = useCallback(() => { const onOpen = useCallback(() => {