feat: Add button to reset mod deployment
For now this merely recovers backed-up game files and leaves mod bundles in-tact. The game doesn't care about those anyways. Closes #8.
This commit is contained in:
parent
c5b2e136fa
commit
bb671c5fd2
4 changed files with 79 additions and 4 deletions
|
@ -547,6 +547,37 @@ pub(crate) async fn deploy_mods(state: State) -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(state))]
|
||||
pub(crate) async fn reset_mod_deployment(state: State) -> Result<()> {
|
||||
let paths = [BUNDLE_DATABASE_NAME, BOOT_BUNDLE_NAME];
|
||||
let bundle_dir = state.get_game_dir().join("bundle");
|
||||
|
||||
tracing::info!("Resetting mod deployment in {}", bundle_dir.display());
|
||||
|
||||
for p in paths {
|
||||
let path = bundle_dir.join(p);
|
||||
let backup = bundle_dir.join(&format!("{}.bak", p));
|
||||
|
||||
tracing::debug!(
|
||||
"Copying from backup: {} -> {}",
|
||||
backup.display(),
|
||||
path.display()
|
||||
);
|
||||
|
||||
fs::copy(&backup, &path)
|
||||
.await
|
||||
.wrap_err_with(|| format!("failed to '{}' restore from backup", p))?;
|
||||
|
||||
tracing::debug!("Deleting backup: {}", backup.display(),);
|
||||
|
||||
fs::remove_file(&backup)
|
||||
.await
|
||||
.wrap_err_with(|| format!("failed to remove backup '{}'", p))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(state))]
|
||||
pub(crate) async fn import_mod(state: State, info: FileInfo) -> Result<ModInfo> {
|
||||
let data = fs::read(&info.path)
|
||||
|
|
|
@ -19,10 +19,12 @@ use druid::SingleUse;
|
|||
use druid::Target;
|
||||
use engine::delete_mod;
|
||||
use engine::import_mod;
|
||||
use engine::reset_mod_deployment;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use state::ACTION_FINISH_ADD_MOD;
|
||||
use state::ACTION_FINISH_DELETE_SELECTED_MOD;
|
||||
use state::ACTION_FINISH_RESET_DEPLOYMENT;
|
||||
use tokio::runtime::Runtime;
|
||||
use tokio::sync::mpsc::UnboundedReceiver;
|
||||
use tokio::sync::RwLock;
|
||||
|
@ -102,6 +104,17 @@ fn work_thread(
|
|||
)
|
||||
.expect("failed to send command");
|
||||
}),
|
||||
AsyncAction::ResetDeployment(state) => tokio::spawn(async move {
|
||||
if let Err(err) = reset_mod_deployment(state).await {
|
||||
tracing::error!("Failed to reset mod deployment: {:?}", err);
|
||||
}
|
||||
|
||||
event_sink
|
||||
.write()
|
||||
.await
|
||||
.submit_command(ACTION_FINISH_RESET_DEPLOYMENT, (), Target::Auto)
|
||||
.expect("failed to send command");
|
||||
}),
|
||||
};
|
||||
}
|
||||
});
|
||||
|
|
|
@ -7,7 +7,7 @@ use druid::{
|
|||
lens, FileDialogOptions, FileSpec, Insets, LensExt, SingleUse, Widget, WidgetExt, WindowDesc,
|
||||
};
|
||||
|
||||
use crate::state::{ModInfo, PathBufFormatter, State, View};
|
||||
use crate::state::{ModInfo, PathBufFormatter, State, View, ACTION_START_RESET_DEPLOYMENT};
|
||||
use crate::state::{
|
||||
ACTION_ADD_MOD, ACTION_SELECTED_MOD_DOWN, ACTION_SELECTED_MOD_UP, ACTION_SELECT_MOD,
|
||||
ACTION_START_DELETE_SELECTED_MOD, ACTION_START_DEPLOY,
|
||||
|
@ -60,9 +60,11 @@ fn build_top_bar() -> impl Widget<State> {
|
|||
)
|
||||
.with_default_spacer()
|
||||
.with_child(
|
||||
Button::new("Run Game").on_click(|_ctx, _state: &mut State, _env| {
|
||||
todo!();
|
||||
}),
|
||||
Button::new("Reset Mods")
|
||||
.on_click(|ctx, _state: &mut State, _env| {
|
||||
ctx.submit_command(ACTION_START_RESET_DEPLOYMENT);
|
||||
})
|
||||
.disabled_if(|data, _| !data.can_reset_deployment()),
|
||||
),
|
||||
)
|
||||
.padding(theme::TOP_BAR_INSETS)
|
||||
|
|
|
@ -24,6 +24,11 @@ pub(crate) const ACTION_FINISH_DELETE_SELECTED_MOD: Selector<SingleUse<ModInfo>>
|
|||
pub(crate) const ACTION_START_DEPLOY: Selector = Selector::new("dtmm.action.start-deploy");
|
||||
pub(crate) const ACTION_FINISH_DEPLOY: Selector = Selector::new("dtmm.action.finish-deploy");
|
||||
|
||||
pub(crate) const ACTION_START_RESET_DEPLOYMENT: Selector =
|
||||
Selector::new("dtmm.action.start-reset-deployment");
|
||||
pub(crate) const ACTION_FINISH_RESET_DEPLOYMENT: Selector =
|
||||
Selector::new("dtmm.action.finish-reset-deployment");
|
||||
|
||||
pub(crate) const ACTION_ADD_MOD: Selector<FileInfo> = Selector::new("dtmm.action.add-mod");
|
||||
pub(crate) const ACTION_FINISH_ADD_MOD: Selector<SingleUse<ModInfo>> =
|
||||
Selector::new("dtmm.action.finish-add-mod");
|
||||
|
@ -145,6 +150,7 @@ pub(crate) struct State {
|
|||
mods: Vector<ModInfo>,
|
||||
selected_mod_index: Option<usize>,
|
||||
is_deployment_in_progress: bool,
|
||||
is_reset_in_progress: bool,
|
||||
game_dir: Arc<PathBuf>,
|
||||
data_dir: Arc<PathBuf>,
|
||||
ctx: Arc<sdk::Context>,
|
||||
|
@ -163,6 +169,7 @@ impl State {
|
|||
mods: Vector::new(),
|
||||
selected_mod_index: None,
|
||||
is_deployment_in_progress: false,
|
||||
is_reset_in_progress: false,
|
||||
game_dir: Arc::new(config.game_dir.unwrap_or_default()),
|
||||
data_dir: Arc::new(config.data_dir.unwrap_or_default()),
|
||||
}
|
||||
|
@ -208,6 +215,10 @@ impl State {
|
|||
!self.is_deployment_in_progress
|
||||
}
|
||||
|
||||
pub fn can_reset_deployment(&self) -> bool {
|
||||
!self.is_reset_in_progress
|
||||
}
|
||||
|
||||
pub(crate) fn get_game_dir(&self) -> &PathBuf {
|
||||
&self.game_dir
|
||||
}
|
||||
|
@ -292,6 +303,7 @@ impl<T: Data> Lens<Vector<T>, Vector<(usize, T)>> for IndexedVectorLens {
|
|||
|
||||
pub(crate) enum AsyncAction {
|
||||
DeployMods(State),
|
||||
ResetDeployment(State),
|
||||
AddMod((State, FileInfo)),
|
||||
DeleteMod((State, ModInfo)),
|
||||
}
|
||||
|
@ -334,6 +346,23 @@ impl AppDelegate<State> for Delegate {
|
|||
state.is_deployment_in_progress = false;
|
||||
Handled::Yes
|
||||
}
|
||||
cmd if cmd.is(ACTION_START_RESET_DEPLOYMENT) => {
|
||||
if self
|
||||
.sender
|
||||
.send(AsyncAction::ResetDeployment(state.clone()))
|
||||
.is_ok()
|
||||
{
|
||||
state.is_reset_in_progress = true;
|
||||
} else {
|
||||
tracing::error!("Failed to queue action to reset mod deployment");
|
||||
}
|
||||
|
||||
Handled::Yes
|
||||
}
|
||||
cmd if cmd.is(ACTION_FINISH_RESET_DEPLOYMENT) => {
|
||||
state.is_reset_in_progress = false;
|
||||
Handled::Yes
|
||||
}
|
||||
cmd if cmd.is(ACTION_SELECT_MOD) => {
|
||||
let index = cmd
|
||||
.get(ACTION_SELECT_MOD)
|
||||
|
|
Loading…
Add table
Reference in a new issue