Skip to content

Commit f2fb5df

Browse files
feat: game response formatting
1 parent 94cc88c commit f2fb5df

5 files changed

Lines changed: 136 additions & 12 deletions

File tree

src/cli/server_subcommands.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::{thread, net::{Shutdown, TcpStream}, sync::mpsc::{Receiver, TryRecvError}, time::Duration, io::Write};
22

33
use clap::Subcommand;
4+
use rw3d_core::response_formatting::ResponseFormatter;
45

56
use crate::{input_waiter::input_waiter, CliOptions};
67

@@ -74,23 +75,34 @@ pub(crate) fn handle_server_subcommand( cmd: ServerSubcommands, options: CliOpti
7475
if !options.no_wait { thread::sleep( Duration::from_millis(1000) ) }
7576
println!("Handling the command...");
7677

78+
let formatter: ResponseFormatter;
7779
let p = match cmd {
7880
ServerSubcommands::Reload => {
81+
//TODO needs some summary and maybe colored text for errors
82+
// erros are not always displayed at the end and can be easily missed
83+
formatter = rw3d_core::response_formatting::scripts_reload_formatter;
7984
rw3d_core::commands::scripts_reload()
8085
}
8186
ServerSubcommands::Exec { cmd } => {
87+
formatter = rw3d_core::response_formatting::scripts_execute_formatter;
8288
rw3d_core::commands::scripts_execute(cmd)
8389
}
8490
ServerSubcommands::Rootpath => {
91+
formatter = rw3d_core::response_formatting::scripts_root_path_formatter;
8592
rw3d_core::commands::scripts_root_path()
8693
}
8794
ServerSubcommands::Modlist => {
95+
//TODO would be nice to have these mod actually sorted alphabetically at least
96+
formatter = rw3d_core::response_formatting::mod_list_formatter;
8897
rw3d_core::commands::mod_list()
8998
}
9099
ServerSubcommands::Opcode { func_name, class_name } => {
100+
formatter = rw3d_core::response_formatting::opcode_formatter;
91101
rw3d_core::commands::opcode(func_name, class_name)
92102
}
93103
ServerSubcommands::Varlist { section, name } => {
104+
//TODO would be nice to have some option to sort those values
105+
formatter = rw3d_core::response_formatting::var_list_formatter;
94106
rw3d_core::commands::var_list(section, name)
95107
}
96108
// ServerSubcommands::Varset { section, name, value } => {
@@ -119,7 +131,7 @@ pub(crate) fn handle_server_subcommand( cmd: ServerSubcommands, options: CliOpti
119131

120132
// This function can either finish by itself by the means of response timeout
121133
// or be stopped by input waiter thread if that one sends him a signal
122-
read_responses(&mut stream, options.response_timeout, reader_rcv, options.verbose);
134+
read_responses(&mut stream, options.response_timeout, reader_rcv, options.verbose, formatter);
123135

124136
} else {
125137
// Wait a little bit to not finish the connection abruptly
@@ -159,7 +171,7 @@ fn try_connect(ip: String, max_tries: u8, tries_delay_ms: u64) -> Option<TcpStre
159171
None
160172
}
161173

162-
fn read_responses(stream: &mut TcpStream, response_timeout: i64, cancel_token: Receiver<()>, verbose_print: bool ) {
174+
fn read_responses(stream: &mut TcpStream, response_timeout: i64, cancel_token: Receiver<()>, verbose_print: bool, formatter: ResponseFormatter) {
163175
let mut peek_buffer = [0u8;6];
164176
let mut packet_available: bool;
165177
let mut response_wait_elapsed: i64 = 0;
@@ -194,7 +206,7 @@ fn read_responses(stream: &mut TcpStream, response_timeout: i64, cancel_token: R
194206
if verbose_print {
195207
println!("{:?}", packet);
196208
} else {
197-
println!("{}", packet);
209+
println!("{}", formatter(packet));
198210
}
199211
}
200212
Err(e) => {

src/core/core.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ mod tests;
33
pub mod constants;
44
mod packet_data;
55
pub mod packet;
6+
pub mod response_formatting;
67
pub mod commands;
78
pub mod scriptslog;

src/core/packet.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::{packet_data::WitcherPacketData, constants};
55

66
#[derive(Default, PartialEq, Eq)]
77
pub struct WitcherPacket {
8-
payload: Vec<WitcherPacketData>
8+
pub(crate) payload: Vec<WitcherPacketData>
99
}
1010

1111
impl WitcherPacket {

src/core/packet_data.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -223,14 +223,20 @@ impl std::fmt::Debug for WitcherPacketData {
223223

224224
impl std::fmt::Display for WitcherPacketData {
225225
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
226-
match self {
227-
Self::Int8(i) => write!(f, "{}", i),
228-
Self::Int16(i) => write!(f, "{}", i),
229-
Self::Int32(i) => write!(f, "{}", i),
230-
Self::UInt32(i) => write!(f, "{}", i),
231-
Self::Int64(i) => write!(f, "{}", i),
232-
Self::StringUTF8(s) => write!(f, "{}", s),
233-
Self::StringUTF16(s) => write!(f, "{}", s)
226+
let s = match self {
227+
Self::Int8(i) => format!("{}", i),
228+
Self::Int16(i) => format!("{}", i),
229+
Self::Int32(i) => format!("{}", i),
230+
Self::UInt32(i) => format!("{}", i),
231+
Self::Int64(i) => format!("{}", i),
232+
Self::StringUTF8(s) => format!("{}", s),
233+
Self::StringUTF16(s) => format!("{}", s)
234+
};
235+
236+
if let Some(width) = f.width() {
237+
write!(f, "{:w$}", s, w = width)
238+
} else {
239+
write!(f, "{}", s)
234240
}
235241
}
236242
}

src/core/response_formatting.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
use crate::{packet::WitcherPacket, packet_data::WitcherPacketData};
2+
3+
pub type ResponseFormatter = fn(WitcherPacket) -> String;
4+
5+
pub fn default_formatter(response: WitcherPacket) -> String {
6+
format!("{}", response)
7+
}
8+
9+
pub fn scripts_reload_formatter(response: WitcherPacket) -> String {
10+
if response.payload.len() > 2 && response.payload[0] == WitcherPacketData::StringUTF8("ScriptCompiler".to_string()) {
11+
if response.payload[1] == WitcherPacketData::StringUTF8("started".to_string()) {
12+
return "Script compilation started...".to_string();
13+
}
14+
else if response.payload[1] == WitcherPacketData::StringUTF8("log".to_string()) {
15+
return format!("{}", response.payload[2] );
16+
}
17+
else if response.payload[1] == WitcherPacketData::StringUTF8("warn".to_string()) {
18+
return format!("[Warning] {}({}): {}", response.payload[3], response.payload[2], response.payload[4] );
19+
}
20+
else if response.payload[1] == WitcherPacketData::StringUTF8("error".to_string()) {
21+
return format!("[Error] {}({}): {}", response.payload[3], response.payload[2], response.payload[4] );
22+
}
23+
else if response.payload[1] == WitcherPacketData::StringUTF8("finished".to_string()) {
24+
if response.payload[2] == WitcherPacketData::Int8(0) {
25+
return "Script compilation finished successfully.".to_string();
26+
} else {
27+
return "Script compilation finished with errors.".to_string();
28+
}
29+
}
30+
}
31+
32+
default_formatter(response)
33+
}
34+
35+
pub fn scripts_root_path_formatter(response: WitcherPacket) -> String {
36+
if response.payload.len() > 2
37+
&& response.payload[0] == WitcherPacketData::StringUTF8("ScriptCompiler".to_string())
38+
&& response.payload[1] == WitcherPacketData::StringUTF8("RootPathConfirm".to_string()) {
39+
return format!("{}", response.payload[2] );
40+
}
41+
42+
default_formatter(response)
43+
}
44+
45+
pub fn scripts_execute_formatter(response: WitcherPacket) -> String {
46+
if response.payload.len() > 2 {
47+
return format!("{}", response.payload[2] );
48+
}
49+
50+
default_formatter(response)
51+
}
52+
53+
pub fn mod_list_formatter(response: WitcherPacket) -> String {
54+
if response.payload.len() >= 3
55+
&& response.payload[0] == WitcherPacketData::StringUTF8("scripts".to_string())
56+
&& response.payload[1] == WitcherPacketData::StringUTF8("pkgSyncListing".to_string()) {
57+
let mut result = String::new();
58+
59+
if let WitcherPacketData::Int32(installed) = response.payload[2] {
60+
result += &format!("Mods installed: {}\n", installed);
61+
}
62+
63+
if response.payload.len() > 3 {
64+
for i in (3 .. response.payload.len()).step_by(2) {
65+
result += &format!("{}\n", response.payload[i]);
66+
}
67+
}
68+
69+
return result;
70+
}
71+
72+
default_formatter(response)
73+
}
74+
75+
pub fn opcode_formatter(response: WitcherPacket) -> String {
76+
if response.payload.len() == 9
77+
&& response.payload[0] == WitcherPacketData::StringUTF8("ScriptDebugger".to_string())
78+
&& response.payload[1] == WitcherPacketData::StringUTF8("OpcodeBreakdownResponse".to_string()) {
79+
// I don't know what most of these magical numbers in the response mean
80+
// so I'm gonna print out only the stuff that looks anywhere useful
81+
return format!("{}{}", response.payload[6], response.payload[8]);
82+
}
83+
84+
default_formatter(response)
85+
}
86+
87+
pub fn var_list_formatter(response: WitcherPacket) -> String {
88+
if response.payload.len() > 4
89+
&& response.payload[1] == WitcherPacketData::StringUTF8("vars".to_string()) {
90+
let mut result = String::new();
91+
92+
let tab_line = format!("{}+-{}+-{}\n", "-".repeat(40), "-".repeat(45), "-".repeat(40) );
93+
result += &tab_line;
94+
result += &format!("{:40}| {:45}| {}\n", "Section", "Variable", "Value");
95+
result += &tab_line;
96+
97+
for i in (4 .. response.payload.len()).step_by(5) {
98+
result += &format!("{:40}| {:45}| {}\n", response.payload[i+1], response.payload[i], response.payload[i+2]);
99+
}
100+
101+
return result;
102+
}
103+
104+
default_formatter(response)
105+
}

0 commit comments

Comments
 (0)