-
-
Notifications
You must be signed in to change notification settings - Fork 4
How it works
TentaCLI receives responses from the WoW Server and can send requests. Each response can be processed by a group of handlers, where each group is defined by specific processor for a particular opcode. When opcode is missed in specific processor, it will be ignored. For handling the rest of application, each handler can return vector of HandlerOutput
values:
#[derive(Debug, Clone)]
pub enum HandlerOutput {
// data transfer
ChatMessage(Message),
Data((u32, Vec<u8>, String)),
TransferCharactersList(Vec<Character>),
TransferRealmsList(Vec<Realm>),
UpdatePlayer(Player),
// commands
ConnectionRequest(String, u16),
Freeze,
Drop,
SelectRealm(Realm),
SelectCharacter(Character),
// messages
ResponseMessage(String, Option<String>),
RequestMessage(String, Option<String>),
DebugMessage(String, Option<String>),
SuccessMessage(String, Option<String>),
ErrorMessage(String, Option<String>),
}
-
HandlerOutput::ChatMessage
notifies about messages received in chat -
HandlerOutput::Data
is used to send some packet to server, contains of opcode, packet body and extra string details. -
TransferCharactersList
orTransferRealmsList
notifies about parsed Characters/Realms list (see ui feature,realm_modal
andcharacters_modal
) -
UpdatePlayer(Player)
is used to notify third-party apps about current player updates (triggered bySMSG_UPDATE_OBJECT
/SMSG_COMPRESSED_UPDATE_OBJECT
packets) -
HandlerOutput::ConnectionRequest
is used to set connection (each call will replace current connection) -
HandlerOutput::Freeze
is mostly used to stop packet handling (to wait for user actions etc) -
HandlerOutput::Drop
exits thehandle_output
task (since version v4.0.0 this behavior is wrong, should be fixed in future) -
SelectRealm
andSelectCharacter
are used to notify core about selection (should be used in features) - messages are used to notify features about output (see features/ui and features/console how they processes the output)
You can configure to handle this automatically or manually. In case you want it to autoselect the character and(or) realm, you need to edit proper settings under autoselect
section in config. For manual just keep realm_name
and character_name
as empty strings. Each host section in config supports multiple account sets, actually it's a dictionary. Example:
connection_data:
127.0.0.1:
account_name:
password: "safe_password"
autoselect:
realm_name: ".*STRING OR REGEX PATTERN TO FIND REALM NAME.*"
character_name: ".*STRING OR REGEX PATTERN TO FIND CHARACTER NAME.*"
another_account_name:
password: "safe_password"
autoselect:
realm_name: ".*STRING OR REGEX PATTERN TO FIND REALM NAME.*"
character_name: ".*STRING OR REGEX PATTERN TO FIND CHARACTER NAME.*"
another.server.com:
account_name:
password: "safe_password"
autoselect:
realm_name: ""
character_name: ""
You can use own features list to extend existing tentacli functionality (and even run multiple tentaclis and connect them using common broadcast channel). Example:
use tokio::task::JoinHandle;
use tentacli::async_broadcast::{BroadcastSender, BroadcastReceiver};
use tentacli::{Client, RunOptions};
use tentacli_traits::Feature;
use tentacli_traits::types::HandlerOutput;
#[tokio::main]
async fn main() {
pub struct MyFeature {
_receiver: Option<BroadcastReceiver<HandlerOutput>>,
_sender: Option<BroadcastSender<HandlerOutput>>,
}
impl Feature for MyFeature {
fn new() -> Self where Self: Sized {
Self {
_receiver: None,
_sender: None,
}
}
fn set_broadcast_channel(
&mut self,
sender: BroadcastSender<HandlerOutput>,
receiver: BroadcastReceiver<HandlerOutput>
) {
self._sender = Some(sender);
self._receiver = Some(receiver);
}
fn get_tasks(&mut self) -> Vec<JoinHandle<()>> {
let mut receiver = self._receiver.as_mut().unwrap().clone();
let handle_smth = || {
tokio::spawn(async move {
loop {
if let Ok(output) = receiver.recv().await {
match output {
HandlerOutput::SuccessMessage(message, _) => {
println!("{}", message);
}
_ => {}
}
}
}
})
};
vec![handle_smth()]
}
}
let options = RunOptions {
external_features: vec![Box::new(MyFeature::new())],
account: "account_name",
config_path: "./dir/another_dir/ConfigFileName.yml",
dotenv_path: "./path/to/.env"
};
// ... pass options to the client
// Client::new().run(options).await.unwrap();
}