Skip to content

Commit c2e7b3a

Browse files
Added auto variant to the --target option
The `auto` profile attempts to connect to both the game and the editor. Whichever connects successfully first is the winner.
1 parent 8a9101a commit c2e7b3a

2 files changed

Lines changed: 70 additions & 17 deletions

File tree

crates/cli/src/main.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub(crate) struct CliOptions {
2727
ip: String,
2828

2929
/// Select connection target
30-
#[clap(long, value_enum, default_value="game", display_order=1)]
30+
#[clap(long, value_enum, default_value="auto", display_order=1)]
3131
target: ConnectionTarget,
3232

3333
/// The maximum amount of milliseconds that program should wait for the game to respond.
@@ -51,10 +51,12 @@ pub(crate) struct CliOptions {
5151

5252
#[derive(Debug, ArgEnum, Clone, Copy, PartialEq, Eq)]
5353
enum ConnectionTarget {
54-
/// Connect to the game running on its own
54+
/// Connect to the standalone game running with debug arguments.
5555
Game,
56-
/// Connect to the game running through REDkit editor
57-
Editor
56+
/// Connect to the game running through the REDkit editor.
57+
Editor,
58+
/// Try connecting to either the standalone game or one running through REDkit.
59+
Auto
5860
}
5961

6062
#[derive(Debug, ArgEnum, Clone, Copy, PartialEq, Eq)]

crates/cli/src/server_subcommands.rs

Lines changed: 64 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{net::Ipv4Addr, str::FromStr, thread, time::Duration};
22

3-
use anyhow::Context;
3+
use anyhow::{bail, Context};
44
use clap::Subcommand;
55
use rw3d_net::{connection::{WitcherConnection, WitcherPort}, messages::requests::*};
66
use rw3d_net_client::WitcherClient;
@@ -50,19 +50,13 @@ pub(crate) enum ServerSubcommands {
5050
pub(crate) fn handle_server_subcommand( cmd: ServerSubcommands, options: CliOptions ) -> anyhow::Result<()> {
5151
let ip = Ipv4Addr::from_str(&options.ip).context("Invalid IPv4 address specified")?;
5252

53-
const CONNECT_TIMEOUT_MILLIS: u64 = 5000;
54-
55-
let port = if options.target == ConnectionTarget::Game {
56-
WitcherPort::Game
57-
} else {
58-
WitcherPort::Editor
59-
};
60-
6153
println_log("Connecting to the game...");
62-
let mut connection =
63-
WitcherConnection::connect_timeout(ip.into(), port.clone(), Duration::from_millis(CONNECT_TIMEOUT_MILLIS))
64-
.context(format!("Failed to connect to the game on address {}:{}.\n\
65-
Make sure the game is running and that it was launched with following flags: -net -debugscripts.", ip.to_string(), port.as_number()))?;
54+
55+
let mut connection = match options.target {
56+
ConnectionTarget::Game => connect_to_standalone(ip),
57+
ConnectionTarget::Editor => connect_to_redkit(ip),
58+
ConnectionTarget::Auto => connect_try_both(ip),
59+
}?;
6660

6761
connection.set_read_timeout(Duration::from_millis(options.response_timeout)).unwrap();
6862

@@ -149,3 +143,60 @@ pub(crate) fn handle_server_subcommand( cmd: ServerSubcommands, options: CliOpti
149143
println_log("\nShutting down client...");
150144
client.stop().context("Failed to shut down client connection")
151145
}
146+
147+
148+
const CONNECT_TIMEOUT_MILLIS: u64 = 5000;
149+
150+
fn connect_to_standalone(ip: Ipv4Addr) -> anyhow::Result<WitcherConnection> {
151+
let port = WitcherPort::Game;
152+
153+
WitcherConnection::connect_timeout(ip.into(), port.clone(), Duration::from_millis(CONNECT_TIMEOUT_MILLIS))
154+
.context(format!("Failed to connect to the game on address {}:{}.\n\
155+
Make sure the game is running and that it was launched with following debug flags: -net -debugscripts.", ip.to_string(), port.as_number()))
156+
}
157+
158+
fn connect_to_redkit(ip: Ipv4Addr) -> anyhow::Result<WitcherConnection> {
159+
let port = WitcherPort::Editor;
160+
161+
WitcherConnection::connect_timeout(ip.into(), port.clone(), Duration::from_millis(CONNECT_TIMEOUT_MILLIS))
162+
.context(format!("Failed to connect to the game in REDkit on address {}:{}.\n\
163+
Make sure REDkit is running.", ip.to_string(), port.as_number()))
164+
}
165+
166+
fn connect_try_both(ip: Ipv4Addr) -> anyhow::Result<WitcherConnection> {
167+
let (conns_send, conns_recv) = std::sync::mpsc::channel::<(anyhow::Result<WitcherConnection>, WitcherPort)>();
168+
169+
let connect_on_port = |port: WitcherPort| {
170+
let sender = conns_send.clone();
171+
std::thread::spawn(move || {
172+
let conn = WitcherConnection::connect_timeout(ip.clone().into(), port.clone(), Duration::from_millis(CONNECT_TIMEOUT_MILLIS));
173+
let _ = sender.send((conn, port));
174+
})
175+
};
176+
177+
connect_on_port(WitcherPort::Game);
178+
connect_on_port(WitcherPort::Editor);
179+
180+
let mut port_errors = String::new();
181+
for _ in 0..2 {
182+
match conns_recv.recv().context("Failed to establish any connection")? {
183+
(Ok(conn), _) => {
184+
return Ok(conn)
185+
}
186+
(Err(err), port) => {
187+
let port_name = if port == WitcherPort::Game {
188+
"standalone"
189+
} else {
190+
"editor"
191+
};
192+
193+
port_errors.push_str(&format!(" [{}] {:?}\n", port_name, err));
194+
}
195+
}
196+
}
197+
198+
// no successfull connection has been established and only errors were received
199+
bail!("Failed to connect to the game on address {}.\n\
200+
Make sure either the REDkit is running or that the game was launched with following debug flags: -net -debugscripts.\n\n\
201+
Caused by:\n{}", ip.to_string(), port_errors)
202+
}

0 commit comments

Comments
 (0)