Skip to content

Commit

Permalink
Added a game installation detector
Browse files Browse the repository at this point in the history
  • Loading branch information
cohaereo committed Mar 27, 2024
1 parent e73a15a commit 9dba76c
Show file tree
Hide file tree
Showing 6 changed files with 339 additions and 52 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
### ✨ Major Features
- Reworked the map loading mechanism to allow for maps to be loaded individually by @cohaereo
- Added a map and activity browser by @cohaereo
- Added a game installation detector by @cohaereo

### Added

Expand Down
108 changes: 107 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ build-time = "0.1.3"
rustc-hash = "1.1.0"
once_cell = "1.19.0"
directories = "5.0.1"
game-detector = "0.1.1"

[features]
default = ["discord_rpc"]
Expand Down
163 changes: 163 additions & 0 deletions src/game_selector.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
use std::{mem::transmute, sync::Arc, time::Duration};

use game_detector::InstalledGame;
use windows::Win32::{
Foundation::DXGI_STATUS_OCCLUDED,
Graphics::{
Direct3D11::ID3D11Texture2D,
Dxgi::{
Common::DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_PRESENT_TEST, DXGI_SWAP_EFFECT_SEQUENTIAL,
},
},
};
use winit::{
dpi::PhysicalSize,
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
platform::run_return::EventLoopExtRunReturn,
};

use crate::{
icons::{ICON_CONTROLLER, ICON_MICROSOFT, ICON_STEAM},
overlays::{
big_button::BigButton,
gui::{GuiManager, PreDrawResult},
},
render::DeviceContextSwapchain,
resources::Resources,
};

/// Creates a temporary window with egui to select a game installation
/// This function should not be called in another render loop, as it will hang until this function completes
pub fn select_game_installation(event_loop: &mut EventLoop<()>) -> anyhow::Result<String> {
let window = winit::window::WindowBuilder::new()
.with_title("Alkahest")
.with_inner_size(PhysicalSize::new(320, 320))
.with_min_inner_size(PhysicalSize::new(320, 480))
.build(event_loop)?;

let window = Arc::new(window);

let dcs = Arc::new(DeviceContextSwapchain::create(&window)?);
let mut gui = GuiManager::create(&window, dcs.clone());
let mut empty_resources = Resources::default();

let mut present_parameters = 0;
let mut selected_path = Err(anyhow::anyhow!("No game installation selected"));

let mut installations = game_detector::find_all_games();
installations.retain(|i| match i {
InstalledGame::Steam(a) => a.appid == 1085660,
InstalledGame::EpicGames(m) => m.display_name == "Destiny 2",
InstalledGame::MicrosoftStore(p) => p.app_name == "Destiny2PCbasegame",
_ => false,
});

event_loop.run_return(|event, _, control_flow| match &event {
Event::WindowEvent { event, .. } => {
let _ = gui.handle_event(event);

match event {
WindowEvent::Resized(new_dims) => unsafe {
let _ = gui
.renderer
.resize_buffers(transmute(&dcs.swap_chain), || {
*dcs.swapchain_target.write() = None;
dcs.swap_chain
.ResizeBuffers(
1,
new_dims.width,
new_dims.height,
DXGI_FORMAT_B8G8R8A8_UNORM,
0,
)
.expect("Failed to resize swapchain");

let bb: ID3D11Texture2D = dcs.swap_chain.GetBuffer(0).unwrap();

let new_rtv = dcs.device.CreateRenderTargetView(&bb, None).unwrap();

dcs.context()
.OMSetRenderTargets(Some(&[Some(new_rtv.clone())]), None);

*dcs.swapchain_target.write() = Some(new_rtv);

transmute(0i32)
})
.unwrap();
},
WindowEvent::CloseRequested => {
*control_flow = ControlFlow::Exit;
}
_ => (),
}
}
Event::RedrawRequested(..) => {
gui.draw_frame(
window.clone(),
&mut empty_resources,
|ctx, _resources| {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("Select Destiny 2 installation");
for i in &installations {
let (icon, store_name, path) = match i {
InstalledGame::Steam(a) => {
(ICON_STEAM, "Steam", a.game_path.clone())
}
InstalledGame::EpicGames(e) => {
(ICON_CONTROLLER, "Epic Games", e.install_location.clone())
}
InstalledGame::MicrosoftStore(p) => {
(ICON_MICROSOFT, "Microsoft Store", p.path.clone())
}
_ => continue,
};

if BigButton::new(icon, store_name)
.with_subtext(&path)
.full_width()
.ui(ui)
.clicked()
{
selected_path = Ok(path.clone());
*control_flow = ControlFlow::Exit;
}
}

// if BigButton::new(ICON_FOLDER_OPEN, "Browse")
// .full_width()
// .ui(ui)
// .clicked()
// {
// let dialog = native_dialog::FileDialog::new()
// .set_title("Select Destiny 2 packages directory")
// .show_open_single_dir()?;
// }
});

PreDrawResult::Continue
},
|_, _| {},
);

unsafe {
if dcs
.swap_chain
.Present(DXGI_SWAP_EFFECT_SEQUENTIAL.0 as _, present_parameters)
== DXGI_STATUS_OCCLUDED
{
present_parameters = DXGI_PRESENT_TEST;
std::thread::sleep(Duration::from_millis(50));
} else {
present_parameters = 0;
}
}
}
Event::MainEventsCleared => {
window.request_redraw();
}
_ => (),
});

selected_path
}
21 changes: 19 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ mod config;
mod discord;
mod dxbc;
mod ecs;
mod game_selector;
mod hotkeys;
mod icons;
mod input;
Expand Down Expand Up @@ -210,6 +211,7 @@ pub async fn main() -> anyhow::Result<()> {
)
.expect("Failed to set up the tracing subscriber");

let mut event_loop = EventLoop::new();
let package_dir = if let Some(p) = &args.package_dir {
if p.ends_with(".pkg") {
warn!("Please specify the directory containing the packages, not the package itself! Support for this will be removed in the future!");
Expand All @@ -224,9 +226,25 @@ pub async fn main() -> anyhow::Result<()> {
} else if let Some(p) = config::with(|c| c.packages_directory.clone()) {
PathBuf::from_str(&p).context("Invalid package directory")?
} else {
panic!("No package directory specified")
let path = PathBuf::from_str(
&game_selector::select_game_installation(&mut event_loop)
.context("No game installation selected")?,
)
.unwrap();

path.join("packages")
};

if !package_dir.exists() {
config::with_mut(|c| c.packages_directory = None);
config::persist();

panic!(
"The specified package directory does not exist! ({})\nRelaunch alkahest with a valid package directory.",
package_dir.display()
);
}

let pm = info_span!("Initializing package manager")
.in_scope(|| PackageManager::new(package_dir, PackageVersion::Destiny2Lightfall).unwrap());

Expand All @@ -235,7 +253,6 @@ pub async fn main() -> anyhow::Result<()> {

*PACKAGE_MANAGER.write() = Some(Arc::new(pm));

let event_loop = EventLoop::new();
let window = winit::window::WindowBuilder::new()
.with_title("Alkahest")
.with_inner_size(config::with(|c| {
Expand Down
Loading

0 comments on commit 9dba76c

Please sign in to comment.